aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
Diffstat (limited to 'erts')
-rw-r--r--erts/AUTHORS2
-rw-r--r--erts/Makefile.in2
-rw-r--r--erts/aclocal.m42
-rwxr-xr-xerts/autoconf/configure.vxworks2
-rw-r--r--erts/autoconf/vxworks/sed.general2
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_cpu322
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_ppc322
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_ppc6032
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_ppc603_nolongcall2
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_ppc8602
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_simlinux2
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_simso2
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_sparc2
-rw-r--r--erts/configure.in260
-rw-r--r--erts/doc/Makefile2
-rw-r--r--erts/doc/src/Makefile17
-rw-r--r--erts/doc/src/absform.xml13
-rw-r--r--erts/doc/src/alt_dist.xml2
-rw-r--r--erts/doc/src/book.xml2
-rw-r--r--erts/doc/src/communication.xml2
-rw-r--r--erts/doc/src/crash_dump.xml2
-rw-r--r--erts/doc/src/driver.xml2
-rw-r--r--erts/doc/src/epmd.xml2
-rw-r--r--erts/doc/src/erl.xml26
-rw-r--r--erts/doc/src/erl_dist_protocol.xml4
-rw-r--r--erts/doc/src/erl_driver.xml2
-rw-r--r--erts/doc/src/erl_nif.xml317
-rw-r--r--erts/doc/src/erl_prim_loader.xml2
-rw-r--r--erts/doc/src/erl_tracer.xml668
-rw-r--r--erts/doc/src/erlang.xml662
-rw-r--r--erts/doc/src/erlc.xml2
-rw-r--r--erts/doc/src/erlsrv.xml2
-rw-r--r--erts/doc/src/erts_alloc.xml20
-rw-r--r--erts/doc/src/inet_cfg.xml2
-rw-r--r--erts/doc/src/init.xml2
-rw-r--r--erts/doc/src/match_spec.xml54
-rw-r--r--erts/doc/src/notes.xml67
-rw-r--r--erts/doc/src/notes_history.xml2
-rw-r--r--erts/doc/src/part.xml2
-rw-r--r--erts/doc/src/part_notes.xml2
-rw-r--r--erts/doc/src/part_notes_history.xml2
-rw-r--r--erts/doc/src/ref_man.xml3
-rw-r--r--erts/doc/src/run_erl.xml2
-rw-r--r--erts/doc/src/specs.xml1
-rw-r--r--erts/doc/src/start.xml2
-rw-r--r--erts/doc/src/start_erl.xml2
-rw-r--r--erts/doc/src/tty.xml2
-rw-r--r--erts/doc/src/werl.xml2
-rw-r--r--erts/doc/src/zlib.xml2
-rw-r--r--erts/emulator/Makefile2
-rw-r--r--erts/emulator/Makefile.in26
-rw-r--r--erts/emulator/beam/atom.c2
-rw-r--r--erts/emulator/beam/atom.h2
-rw-r--r--erts/emulator/beam/atom.names23
-rw-r--r--erts/emulator/beam/beam_bif_load.c92
-rw-r--r--erts/emulator/beam/beam_bp.c188
-rw-r--r--erts/emulator/beam/beam_bp.h38
-rw-r--r--erts/emulator/beam/beam_catches.c2
-rw-r--r--erts/emulator/beam/beam_catches.h2
-rw-r--r--erts/emulator/beam/beam_debug.c4
-rw-r--r--erts/emulator/beam/beam_emu.c179
-rw-r--r--erts/emulator/beam/beam_load.c284
-rw-r--r--erts/emulator/beam/beam_load.h3
-rw-r--r--erts/emulator/beam/beam_ranges.c2
-rw-r--r--erts/emulator/beam/benchmark.c2
-rw-r--r--erts/emulator/beam/benchmark.h2
-rw-r--r--erts/emulator/beam/bif.c164
-rw-r--r--erts/emulator/beam/bif.h3
-rw-r--r--erts/emulator/beam/bif.tab9
-rw-r--r--erts/emulator/beam/big.c2
-rw-r--r--erts/emulator/beam/big.h2
-rw-r--r--erts/emulator/beam/binary.c2
-rw-r--r--erts/emulator/beam/break.c12
-rw-r--r--erts/emulator/beam/code_ix.c3
-rw-r--r--erts/emulator/beam/code_ix.h2
-rw-r--r--erts/emulator/beam/copy.c2
-rw-r--r--erts/emulator/beam/dist.c38
-rw-r--r--erts/emulator/beam/dist.h6
-rw-r--r--erts/emulator/beam/dtrace-wrapper.h2
-rw-r--r--erts/emulator/beam/elib_memmove.c2
-rw-r--r--erts/emulator/beam/erl_afit_alloc.c2
-rw-r--r--erts/emulator/beam/erl_afit_alloc.h2
-rw-r--r--erts/emulator/beam/erl_alloc.c205
-rw-r--r--erts/emulator/beam/erl_alloc.h10
-rw-r--r--erts/emulator/beam/erl_alloc.types24
-rw-r--r--erts/emulator/beam/erl_alloc_util.c132
-rw-r--r--erts/emulator/beam/erl_alloc_util.h39
-rw-r--r--erts/emulator/beam/erl_ao_firstfit_alloc.c2
-rw-r--r--erts/emulator/beam/erl_ao_firstfit_alloc.h2
-rw-r--r--erts/emulator/beam/erl_arith.c2
-rw-r--r--erts/emulator/beam/erl_async.c18
-rw-r--r--erts/emulator/beam/erl_async.h2
-rw-r--r--erts/emulator/beam/erl_bestfit_alloc.c2
-rw-r--r--erts/emulator/beam/erl_bestfit_alloc.h2
-rw-r--r--erts/emulator/beam/erl_bif_binary.c2
-rw-r--r--erts/emulator/beam/erl_bif_chksum.c2
-rw-r--r--erts/emulator/beam/erl_bif_ddll.c6
-rw-r--r--erts/emulator/beam/erl_bif_guard.c2
-rw-r--r--erts/emulator/beam/erl_bif_info.c25
-rw-r--r--erts/emulator/beam/erl_bif_lists.c95
-rw-r--r--erts/emulator/beam/erl_bif_op.c2
-rw-r--r--erts/emulator/beam/erl_bif_os.c2
-rw-r--r--erts/emulator/beam/erl_bif_port.c31
-rw-r--r--erts/emulator/beam/erl_bif_re.c2
-rw-r--r--erts/emulator/beam/erl_bif_trace.c739
-rw-r--r--erts/emulator/beam/erl_bif_unique.c22
-rw-r--r--erts/emulator/beam/erl_bif_unique.h14
-rw-r--r--erts/emulator/beam/erl_binary.h2
-rw-r--r--erts/emulator/beam/erl_bits.c2
-rw-r--r--erts/emulator/beam/erl_bits.h2
-rw-r--r--erts/emulator/beam/erl_cpu_topology.c2
-rw-r--r--erts/emulator/beam/erl_cpu_topology.h2
-rw-r--r--erts/emulator/beam/erl_db.c5
-rw-r--r--erts/emulator/beam/erl_db.h2
-rw-r--r--erts/emulator/beam/erl_db_hash.c2
-rw-r--r--erts/emulator/beam/erl_db_hash.h2
-rw-r--r--erts/emulator/beam/erl_db_tree.c2
-rw-r--r--erts/emulator/beam/erl_db_tree.h2
-rw-r--r--erts/emulator/beam/erl_db_util.c487
-rw-r--r--erts/emulator/beam/erl_db_util.h10
-rw-r--r--erts/emulator/beam/erl_debug.c2
-rw-r--r--erts/emulator/beam/erl_driver.h2
-rw-r--r--erts/emulator/beam/erl_drv_nif.h2
-rw-r--r--erts/emulator/beam/erl_drv_thread.c2
-rw-r--r--erts/emulator/beam/erl_fun.c2
-rw-r--r--erts/emulator/beam/erl_fun.h2
-rw-r--r--erts/emulator/beam/erl_gc.c129
-rw-r--r--erts/emulator/beam/erl_gc.h4
-rw-r--r--erts/emulator/beam/erl_goodfit_alloc.c2
-rw-r--r--erts/emulator/beam/erl_goodfit_alloc.h2
-rw-r--r--erts/emulator/beam/erl_hl_timer.c10
-rw-r--r--erts/emulator/beam/erl_init.c61
-rw-r--r--erts/emulator/beam/erl_instrument.c2
-rw-r--r--erts/emulator/beam/erl_instrument.h2
-rw-r--r--erts/emulator/beam/erl_lock_check.c7
-rw-r--r--erts/emulator/beam/erl_lock_check.h2
-rw-r--r--erts/emulator/beam/erl_lock_count.c2
-rw-r--r--erts/emulator/beam/erl_lock_count.h2
-rw-r--r--erts/emulator/beam/erl_map.c91
-rw-r--r--erts/emulator/beam/erl_map.h5
-rw-r--r--erts/emulator/beam/erl_math.c2
-rw-r--r--erts/emulator/beam/erl_message.c232
-rw-r--r--erts/emulator/beam/erl_message.h114
-rw-r--r--erts/emulator/beam/erl_monitors.c2
-rw-r--r--erts/emulator/beam/erl_monitors.h2
-rw-r--r--erts/emulator/beam/erl_msacc.c2
-rw-r--r--erts/emulator/beam/erl_mtrace.c2
-rw-r--r--erts/emulator/beam/erl_mtrace.h2
-rw-r--r--erts/emulator/beam/erl_nif.c664
-rw-r--r--erts/emulator/beam/erl_nif.h28
-rw-r--r--erts/emulator/beam/erl_nif_api_funcs.h20
-rw-r--r--erts/emulator/beam/erl_node_container_utils.h2
-rw-r--r--erts/emulator/beam/erl_node_tables.c30
-rw-r--r--erts/emulator/beam/erl_node_tables.h4
-rw-r--r--erts/emulator/beam/erl_port.h53
-rw-r--r--erts/emulator/beam/erl_port_task.c51
-rw-r--r--erts/emulator/beam/erl_port_task.h4
-rw-r--r--erts/emulator/beam/erl_printf_term.c2
-rw-r--r--erts/emulator/beam/erl_printf_term.h2
-rw-r--r--erts/emulator/beam/erl_process.c522
-rw-r--r--erts/emulator/beam/erl_process.h140
-rw-r--r--erts/emulator/beam/erl_process_dict.c2
-rw-r--r--erts/emulator/beam/erl_process_dict.h2
-rw-r--r--erts/emulator/beam/erl_process_dump.c4
-rw-r--r--erts/emulator/beam/erl_process_lock.c193
-rw-r--r--erts/emulator/beam/erl_process_lock.h40
-rw-r--r--erts/emulator/beam/erl_ptab.c2
-rw-r--r--erts/emulator/beam/erl_ptab.h10
-rw-r--r--erts/emulator/beam/erl_sched_spec_pre_alloc.c2
-rw-r--r--erts/emulator/beam/erl_sched_spec_pre_alloc.h2
-rw-r--r--erts/emulator/beam/erl_smp.h2
-rw-r--r--erts/emulator/beam/erl_sock.h2
-rw-r--r--erts/emulator/beam/erl_sys_driver.h2
-rw-r--r--erts/emulator/beam/erl_term.c92
-rw-r--r--erts/emulator/beam/erl_term.h93
-rw-r--r--erts/emulator/beam/erl_thr_progress.c2
-rw-r--r--erts/emulator/beam/erl_thr_progress.h2
-rw-r--r--erts/emulator/beam/erl_thr_queue.c34
-rw-r--r--erts/emulator/beam/erl_thr_queue.h6
-rw-r--r--erts/emulator/beam/erl_threads.h2
-rw-r--r--erts/emulator/beam/erl_time.h2
-rw-r--r--erts/emulator/beam/erl_time_sup.c4
-rw-r--r--erts/emulator/beam/erl_trace.c3094
-rw-r--r--erts/emulator/beam/erl_trace.h101
-rw-r--r--erts/emulator/beam/erl_unicode.c2
-rw-r--r--erts/emulator/beam/erl_unicode.h2
-rw-r--r--erts/emulator/beam/erl_unicode_normalize.h2
-rw-r--r--erts/emulator/beam/erl_utils.h2
-rw-r--r--erts/emulator/beam/erl_vm.h3
-rw-r--r--erts/emulator/beam/erl_zlib.c2
-rw-r--r--erts/emulator/beam/erl_zlib.h2
-rw-r--r--erts/emulator/beam/erlang_dtrace.d31
-rw-r--r--erts/emulator/beam/erlang_lttng.c32
-rw-r--r--erts/emulator/beam/erlang_lttng.h424
-rw-r--r--erts/emulator/beam/error.h2
-rw-r--r--erts/emulator/beam/export.c2
-rw-r--r--erts/emulator/beam/export.h2
-rw-r--r--erts/emulator/beam/external.c227
-rw-r--r--erts/emulator/beam/external.h9
-rw-r--r--erts/emulator/beam/global.h54
-rw-r--r--erts/emulator/beam/hash.c2
-rw-r--r--erts/emulator/beam/hash.h2
-rw-r--r--erts/emulator/beam/index.c2
-rw-r--r--erts/emulator/beam/index.h2
-rw-r--r--erts/emulator/beam/io.c660
-rw-r--r--erts/emulator/beam/lttng-wrapper.h107
-rw-r--r--erts/emulator/beam/module.c2
-rw-r--r--erts/emulator/beam/module.h2
-rw-r--r--erts/emulator/beam/ops.tab35
-rw-r--r--erts/emulator/beam/packet_parser.c2
-rw-r--r--erts/emulator/beam/packet_parser.h2
-rw-r--r--erts/emulator/beam/register.c16
-rw-r--r--erts/emulator/beam/register.h2
-rw-r--r--erts/emulator/beam/safe_hash.c2
-rw-r--r--erts/emulator/beam/safe_hash.h2
-rw-r--r--erts/emulator/beam/sys.h20
-rw-r--r--erts/emulator/beam/time.c2
-rw-r--r--erts/emulator/beam/utils.c39
-rw-r--r--erts/emulator/beam/version.h2
-rw-r--r--erts/emulator/drivers/common/efile_drv.c14
-rw-r--r--erts/emulator/drivers/common/erl_efile.h8
-rw-r--r--erts/emulator/drivers/common/gzio.h2
-rw-r--r--erts/emulator/drivers/common/gzio_zutil.h2
-rw-r--r--erts/emulator/drivers/common/inet_drv.c2
-rw-r--r--erts/emulator/drivers/common/ram_file_drv.c2
-rw-r--r--erts/emulator/drivers/common/zlib_drv.c2
-rw-r--r--erts/emulator/drivers/unix/bin_drv.c2
-rw-r--r--erts/emulator/drivers/unix/multi_drv.c2
-rw-r--r--erts/emulator/drivers/unix/sig_drv.c2
-rw-r--r--erts/emulator/drivers/unix/ttsl_drv.c7
-rw-r--r--erts/emulator/drivers/unix/unix_efile.c23
-rw-r--r--erts/emulator/drivers/vxworks/vxworks_resolv.c2
-rw-r--r--erts/emulator/drivers/win32/registry_drv.c2
-rw-r--r--erts/emulator/drivers/win32/ttsl_drv.c2
-rw-r--r--erts/emulator/drivers/win32/win_con.c2
-rw-r--r--erts/emulator/drivers/win32/win_con.h2
-rw-r--r--erts/emulator/drivers/win32/win_efile.c2
-rw-r--r--erts/emulator/hipe/TODO2
-rw-r--r--erts/emulator/hipe/elf64ppc.x2
-rw-r--r--erts/emulator/hipe/hipe_amd64.c118
-rw-r--r--erts/emulator/hipe/hipe_amd64.h2
-rw-r--r--erts/emulator/hipe/hipe_amd64.tab2
-rw-r--r--erts/emulator/hipe/hipe_amd64_asm.m42
-rw-r--r--erts/emulator/hipe/hipe_amd64_bifs.m42
-rw-r--r--erts/emulator/hipe/hipe_amd64_gc.h2
-rw-r--r--erts/emulator/hipe/hipe_amd64_glue.S2
-rw-r--r--erts/emulator/hipe/hipe_amd64_glue.h2
-rw-r--r--erts/emulator/hipe/hipe_amd64_primops.h2
-rw-r--r--erts/emulator/hipe/hipe_arch.h2
-rw-r--r--erts/emulator/hipe/hipe_arm.c2
-rw-r--r--erts/emulator/hipe/hipe_arm.h2
-rw-r--r--erts/emulator/hipe/hipe_arm.tab2
-rw-r--r--erts/emulator/hipe/hipe_arm_asm.m42
-rw-r--r--erts/emulator/hipe/hipe_arm_bifs.m42
-rw-r--r--erts/emulator/hipe/hipe_arm_gc.h2
-rw-r--r--erts/emulator/hipe/hipe_arm_glue.S2
-rw-r--r--erts/emulator/hipe/hipe_arm_glue.h2
-rw-r--r--erts/emulator/hipe/hipe_arm_primops.h2
-rw-r--r--erts/emulator/hipe/hipe_bif0.c26
-rw-r--r--erts/emulator/hipe/hipe_bif0.h2
-rw-r--r--erts/emulator/hipe/hipe_bif0.tab2
-rw-r--r--erts/emulator/hipe/hipe_bif1.c2
-rw-r--r--erts/emulator/hipe/hipe_bif1.h2
-rw-r--r--erts/emulator/hipe/hipe_bif1.tab2
-rw-r--r--erts/emulator/hipe/hipe_bif2.c2
-rw-r--r--erts/emulator/hipe/hipe_bif2.tab2
-rw-r--r--erts/emulator/hipe/hipe_bif64.c2
-rw-r--r--erts/emulator/hipe/hipe_bif64.h2
-rw-r--r--erts/emulator/hipe/hipe_bif64.tab2
-rw-r--r--erts/emulator/hipe/hipe_bif_list.m42
-rw-r--r--erts/emulator/hipe/hipe_debug.c4
-rw-r--r--erts/emulator/hipe/hipe_debug.h2
-rw-r--r--erts/emulator/hipe/hipe_gbif_list.h2
-rw-r--r--erts/emulator/hipe/hipe_gc.c2
-rw-r--r--erts/emulator/hipe/hipe_gc.h2
-rw-r--r--erts/emulator/hipe/hipe_mkliterals.c2
-rw-r--r--erts/emulator/hipe/hipe_mode_switch.c104
-rw-r--r--erts/emulator/hipe/hipe_mode_switch.h2
-rw-r--r--erts/emulator/hipe/hipe_native_bif.c4
-rw-r--r--erts/emulator/hipe/hipe_native_bif.h2
-rw-r--r--erts/emulator/hipe/hipe_ops.tab2
-rw-r--r--erts/emulator/hipe/hipe_ppc.c2
-rw-r--r--erts/emulator/hipe/hipe_ppc.h2
-rw-r--r--erts/emulator/hipe/hipe_ppc.tab2
-rw-r--r--erts/emulator/hipe/hipe_ppc64.tab2
-rw-r--r--erts/emulator/hipe/hipe_ppc_asm.m42
-rw-r--r--erts/emulator/hipe/hipe_ppc_bifs.m42
-rw-r--r--erts/emulator/hipe/hipe_ppc_gc.h2
-rw-r--r--erts/emulator/hipe/hipe_ppc_glue.S2
-rw-r--r--erts/emulator/hipe/hipe_ppc_glue.h2
-rw-r--r--erts/emulator/hipe/hipe_ppc_primops.h2
-rw-r--r--erts/emulator/hipe/hipe_primops.h2
-rw-r--r--erts/emulator/hipe/hipe_process.h2
-rw-r--r--erts/emulator/hipe/hipe_risc_gc.h2
-rw-r--r--erts/emulator/hipe/hipe_risc_glue.h2
-rw-r--r--erts/emulator/hipe/hipe_risc_stack.c2
-rw-r--r--erts/emulator/hipe/hipe_signal.h2
-rw-r--r--erts/emulator/hipe/hipe_sparc.c2
-rw-r--r--erts/emulator/hipe/hipe_sparc.h2
-rw-r--r--erts/emulator/hipe/hipe_sparc.tab2
-rw-r--r--erts/emulator/hipe/hipe_sparc_asm.m42
-rw-r--r--erts/emulator/hipe/hipe_sparc_bifs.m42
-rw-r--r--erts/emulator/hipe/hipe_sparc_gc.h2
-rw-r--r--erts/emulator/hipe/hipe_sparc_glue.S2
-rw-r--r--erts/emulator/hipe/hipe_sparc_glue.h2
-rw-r--r--erts/emulator/hipe/hipe_sparc_primops.h2
-rw-r--r--erts/emulator/hipe/hipe_stack.c2
-rw-r--r--erts/emulator/hipe/hipe_stack.h2
-rw-r--r--erts/emulator/hipe/hipe_x86.c2
-rw-r--r--erts/emulator/hipe/hipe_x86.h2
-rw-r--r--erts/emulator/hipe/hipe_x86.tab2
-rw-r--r--erts/emulator/hipe/hipe_x86_abi.txt2
-rw-r--r--erts/emulator/hipe/hipe_x86_asm.m42
-rw-r--r--erts/emulator/hipe/hipe_x86_bifs.m42
-rw-r--r--erts/emulator/hipe/hipe_x86_gc.h2
-rw-r--r--erts/emulator/hipe/hipe_x86_glue.S2
-rw-r--r--erts/emulator/hipe/hipe_x86_glue.h2
-rw-r--r--erts/emulator/hipe/hipe_x86_primops.h2
-rw-r--r--erts/emulator/hipe/hipe_x86_signal.c2
-rw-r--r--erts/emulator/hipe/hipe_x86_stack.c2
-rw-r--r--erts/emulator/internal_doc/dec.erl2
-rw-r--r--erts/emulator/internal_doc/erl_ext_dist.txt2
-rw-r--r--erts/emulator/nifs/common/erl_tracer_nif.c257
-rw-r--r--erts/emulator/pcre/pcre.mk2
-rw-r--r--erts/emulator/sys/common/erl_check_io.c5
-rw-r--r--erts/emulator/sys/common/erl_check_io.h2
-rw-r--r--erts/emulator/sys/common/erl_mmap.c145
-rw-r--r--erts/emulator/sys/common/erl_mmap.h122
-rw-r--r--erts/emulator/sys/common/erl_mseg.c140
-rw-r--r--erts/emulator/sys/common/erl_mseg.h8
-rw-r--r--erts/emulator/sys/common/erl_mtrace_sys_wrap.c2
-rw-r--r--erts/emulator/sys/common/erl_os_monotonic_time_extender.c2
-rw-r--r--erts/emulator/sys/common/erl_poll.c2
-rw-r--r--erts/emulator/sys/common/erl_poll.h2
-rw-r--r--erts/emulator/sys/common/erl_sys_common_misc.c2
-rw-r--r--erts/emulator/sys/common/erl_util_queue.h2
-rw-r--r--erts/emulator/sys/unix/driver_int.h2
-rw-r--r--erts/emulator/sys/unix/erl_child_setup.c2
-rw-r--r--erts/emulator/sys/unix/erl_main.c2
-rw-r--r--erts/emulator/sys/unix/erl_unix_sys.h3
-rw-r--r--erts/emulator/sys/unix/erl_unix_sys_ddll.c2
-rw-r--r--erts/emulator/sys/unix/sys.c22
-rw-r--r--erts/emulator/sys/unix/sys_drivers.c2
-rw-r--r--erts/emulator/sys/unix/sys_float.c112
-rw-r--r--erts/emulator/sys/unix/sys_time.c2
-rw-r--r--erts/emulator/sys/unix/sys_uds.c2
-rw-r--r--erts/emulator/sys/unix/sys_uds.h2
-rw-r--r--erts/emulator/sys/win32/dosmap.c2
-rw-r--r--erts/emulator/sys/win32/driver_int.h2
-rw-r--r--erts/emulator/sys/win32/erl_main.c2
-rw-r--r--erts/emulator/sys/win32/erl_poll.c2
-rw-r--r--erts/emulator/sys/win32/erl_win32_sys_ddll.c2
-rw-r--r--erts/emulator/sys/win32/erl_win_dyn_driver.h2
-rw-r--r--erts/emulator/sys/win32/erl_win_sys.h2
-rw-r--r--erts/emulator/sys/win32/sys.c5
-rw-r--r--erts/emulator/sys/win32/sys_env.c2
-rw-r--r--erts/emulator/sys/win32/sys_float.c5
-rw-r--r--erts/emulator/sys/win32/sys_interrupt.c2
-rw-r--r--erts/emulator/sys/win32/sys_time.c2
-rw-r--r--erts/emulator/test/Makefile6
-rw-r--r--erts/emulator/test/a_SUITE.erl2
-rw-r--r--erts/emulator/test/after_SUITE.erl2
-rw-r--r--erts/emulator/test/alloc_SUITE.erl53
-rw-r--r--erts/emulator/test/alloc_SUITE_data/cpool.c2
-rw-r--r--erts/emulator/test/alloc_SUITE_data/migration.c2
-rw-r--r--erts/emulator/test/beam_SUITE.erl124
-rw-r--r--erts/emulator/test/beam_literals_SUITE.erl2
-rw-r--r--erts/emulator/test/bif_SUITE.erl2
-rw-r--r--erts/emulator/test/big_SUITE.erl2
-rw-r--r--erts/emulator/test/big_SUITE_data/literal_test.erl2
-rw-r--r--erts/emulator/test/binary_SUITE.erl2
-rw-r--r--erts/emulator/test/bs_bincomp_SUITE.erl2
-rw-r--r--erts/emulator/test/bs_bit_binaries_SUITE.erl2
-rw-r--r--erts/emulator/test/bs_construct_SUITE.erl2
-rw-r--r--erts/emulator/test/bs_match_bin_SUITE.erl2
-rw-r--r--erts/emulator/test/bs_match_int_SUITE.erl2
-rw-r--r--erts/emulator/test/bs_match_misc_SUITE.erl2
-rw-r--r--erts/emulator/test/bs_match_tail_SUITE.erl2
-rw-r--r--erts/emulator/test/bs_utf_SUITE.erl2
-rw-r--r--erts/emulator/test/busy_port_SUITE.erl2
-rw-r--r--erts/emulator/test/busy_port_SUITE_data/Makefile.src2
-rw-r--r--erts/emulator/test/busy_port_SUITE_data/hard_busy_drv.c2
-rw-r--r--erts/emulator/test/busy_port_SUITE_data/hs_busy_drv.c2
-rw-r--r--erts/emulator/test/busy_port_SUITE_data/scheduling_drv.c2
-rw-r--r--erts/emulator/test/busy_port_SUITE_data/soft_busy_drv.c2
-rw-r--r--erts/emulator/test/call_trace_SUITE.erl68
-rw-r--r--erts/emulator/test/code_SUITE.erl2
-rw-r--r--erts/emulator/test/code_SUITE_data/another_code_test.erl2
-rw-r--r--erts/emulator/test/code_SUITE_data/cpbugx.erl2
-rw-r--r--erts/emulator/test/code_SUITE_data/fun_confusion.erl2
-rw-r--r--erts/emulator/test/code_SUITE_data/literals.erl2
-rw-r--r--erts/emulator/test/code_SUITE_data/many_funs.erl2
-rw-r--r--erts/emulator/test/code_SUITE_data/my_code_test.erl2
-rw-r--r--erts/emulator/test/code_SUITE_data/versions.erl2
-rw-r--r--erts/emulator/test/code_parallel_load_SUITE.erl2
-rw-r--r--erts/emulator/test/crypto_SUITE.erl2
-rw-r--r--erts/emulator/test/crypto_reference.erl2
-rw-r--r--erts/emulator/test/ddll_SUITE.erl2
-rw-r--r--erts/emulator/test/decode_packet_SUITE.erl2
-rw-r--r--erts/emulator/test/dgawd_handler.erl2
-rw-r--r--erts/emulator/test/distribution_SUITE.erl3
-rw-r--r--erts/emulator/test/distribution_SUITE_data/run.erl2
-rw-r--r--erts/emulator/test/driver_SUITE.erl2
-rw-r--r--erts/emulator/test/driver_SUITE_data/async_blast_drv.c2
-rw-r--r--erts/emulator/test/driver_SUITE_data/consume_timeslice_drv.c2
-rw-r--r--erts/emulator/test/driver_SUITE_data/ioq_exit_drv.c2
-rw-r--r--erts/emulator/test/driver_SUITE_data/otp_9302_drv.c2
-rw-r--r--erts/emulator/test/driver_SUITE_data/thr_free_drv.c2
-rw-r--r--erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c2
-rw-r--r--erts/emulator/test/efile_SUITE.erl2
-rw-r--r--erts/emulator/test/erl_drv_thread_SUITE.erl4
-rw-r--r--erts/emulator/test/erl_link_SUITE.erl2
-rw-r--r--erts/emulator/test/erts_debug_SUITE.erl2
-rw-r--r--erts/emulator/test/estone_SUITE.erl2
-rw-r--r--erts/emulator/test/evil_SUITE.erl2
-rw-r--r--erts/emulator/test/exception_SUITE.erl2
-rw-r--r--erts/emulator/test/float_SUITE.erl2
-rw-r--r--erts/emulator/test/float_SUITE_data/has_fpe_bug.erl2
-rw-r--r--erts/emulator/test/fun_SUITE.erl2
-rw-r--r--erts/emulator/test/fun_r13_SUITE.erl2
-rw-r--r--erts/emulator/test/gc_SUITE.erl2
-rw-r--r--erts/emulator/test/guard_SUITE.erl2
-rw-r--r--erts/emulator/test/hash_SUITE.erl2
-rw-r--r--erts/emulator/test/hibernate_SUITE.erl2
-rw-r--r--erts/emulator/test/ignore_cores.erl4
-rw-r--r--erts/emulator/test/list_bif_SUITE.erl2
-rw-r--r--erts/emulator/test/long_timers_test.erl2
-rw-r--r--erts/emulator/test/lttng_SUITE.erl499
-rw-r--r--erts/emulator/test/lttng_SUITE_data/Makefile.src7
-rw-r--r--erts/emulator/test/lttng_SUITE_data/caller_drv.c159
-rw-r--r--erts/emulator/test/map_SUITE.erl74
-rw-r--r--erts/emulator/test/match_spec_SUITE.erl97
-rw-r--r--erts/emulator/test/message_queue_data_SUITE.erl34
-rw-r--r--erts/emulator/test/module_info_SUITE.erl2
-rw-r--r--erts/emulator/test/monitor_SUITE.erl2
-rw-r--r--erts/emulator/test/mtx_SUITE.erl2
-rw-r--r--erts/emulator/test/mtx_SUITE_data/Makefile.src2
-rw-r--r--erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c2
-rw-r--r--erts/emulator/test/multi_load_SUITE.erl31
-rw-r--r--erts/emulator/test/nested_SUITE.erl2
-rw-r--r--erts/emulator/test/nif_SUITE.erl176
-rw-r--r--erts/emulator/test/nif_SUITE_data/Makefile.src3
-rw-r--r--erts/emulator/test/nif_SUITE_data/echo_drv.c62
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c145
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.c2
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.erl2
-rw-r--r--erts/emulator/test/node_container_SUITE.erl138
-rw-r--r--erts/emulator/test/nofrag_SUITE.erl2
-rw-r--r--erts/emulator/test/num_bif_SUITE.erl2
-rw-r--r--erts/emulator/test/old_mod.erl2
-rw-r--r--erts/emulator/test/old_scheduler_SUITE.erl2
-rw-r--r--erts/emulator/test/op_SUITE.erl17
-rw-r--r--erts/emulator/test/port_SUITE.erl35
-rw-r--r--erts/emulator/test/port_SUITE_data/dead_port.c2
-rw-r--r--erts/emulator/test/port_SUITE_data/port_test.erl2
-rw-r--r--erts/emulator/test/port_bif_SUITE.erl2
-rw-r--r--erts/emulator/test/port_trace_SUITE.erl614
-rw-r--r--erts/emulator/test/port_trace_SUITE_data/Makefile.src3
-rw-r--r--erts/emulator/test/port_trace_SUITE_data/echo_drv.c241
-rw-r--r--erts/emulator/test/process_SUITE.erl4
-rw-r--r--erts/emulator/test/pseudoknot_SUITE.erl2
-rw-r--r--erts/emulator/test/random_iolist.erl2
-rw-r--r--erts/emulator/test/receive_SUITE.erl2
-rw-r--r--erts/emulator/test/ref_SUITE.erl2
-rw-r--r--erts/emulator/test/register_SUITE.erl2
-rw-r--r--erts/emulator/test/save_calls_SUITE.erl19
-rw-r--r--erts/emulator/test/scheduler_SUITE.erl6
-rw-r--r--erts/emulator/test/scheduler_SUITE_data/scheduler_SUITE.c6
-rw-r--r--erts/emulator/test/send_term_SUITE.erl2
-rw-r--r--erts/emulator/test/sensitive_SUITE.erl4
-rw-r--r--erts/emulator/test/signal_SUITE.erl2
-rw-r--r--erts/emulator/test/smoke_test_SUITE.erl2
-rw-r--r--erts/emulator/test/statistics_SUITE.erl2
-rw-r--r--erts/emulator/test/system_info_SUITE.erl2
-rw-r--r--erts/emulator/test/system_profile_SUITE.erl34
-rw-r--r--erts/emulator/test/time_SUITE.erl2
-rw-r--r--erts/emulator/test/timer_bif_SUITE.erl2
-rw-r--r--erts/emulator/test/trace_SUITE.erl520
-rw-r--r--erts/emulator/test/trace_bif_SUITE.erl11
-rw-r--r--erts/emulator/test/trace_call_count_SUITE.erl2
-rw-r--r--erts/emulator/test/trace_call_time_SUITE.erl2
-rw-r--r--erts/emulator/test/trace_local_SUITE.erl26
-rw-r--r--erts/emulator/test/trace_local_SUITE_data/trace_local_dummy.erl2
-rw-r--r--erts/emulator/test/trace_meta_SUITE.erl2
-rw-r--r--erts/emulator/test/trace_nif_SUITE.erl2
-rw-r--r--erts/emulator/test/trace_port_SUITE.erl177
-rw-r--r--erts/emulator/test/tracer_SUITE.erl627
-rw-r--r--erts/emulator/test/tracer_SUITE_data/Makefile.src8
-rw-r--r--erts/emulator/test/tracer_SUITE_data/tracer_test.c122
-rw-r--r--erts/emulator/test/tracer_test.erl55
-rw-r--r--erts/emulator/test/tuple_SUITE.erl2
-rw-r--r--erts/emulator/test/unique_SUITE.erl2
-rw-r--r--erts/emulator/test/z_SUITE.erl2
-rwxr-xr-xerts/emulator/utils/beam_makeops332
-rwxr-xr-xerts/emulator/utils/beam_strip2
-rwxr-xr-xerts/emulator/utils/count2
-rw-r--r--erts/emulator/utils/loaded2
-rwxr-xr-xerts/emulator/utils/make_alloc_types2
-rwxr-xr-xerts/emulator/utils/make_compiler_flags2
-rwxr-xr-xerts/emulator/utils/make_driver_tab15
-rwxr-xr-xerts/emulator/utils/make_preload2
-rwxr-xr-xerts/emulator/utils/make_tables2
-rwxr-xr-xerts/emulator/utils/make_version2
-rw-r--r--erts/emulator/utils/mkver.c2
-rw-r--r--erts/emulator/zlib/zlib.mk2
-rw-r--r--erts/epmd/Makefile2
-rw-r--r--erts/epmd/epmd.mk2
-rw-r--r--erts/epmd/src/Makefile2
-rw-r--r--erts/epmd/src/Makefile.in2
-rw-r--r--erts/epmd/src/epmd.c8
-rw-r--r--erts/epmd/src/epmd.h2
-rw-r--r--erts/epmd/src/epmd_cli.c2
-rw-r--r--erts/epmd/src/epmd_int.h6
-rw-r--r--erts/epmd/src/epmd_srv.c10
-rw-r--r--erts/epmd/test/Makefile2
-rw-r--r--erts/epmd/test/epmd_SUITE.erl2
-rw-r--r--erts/etc/Makefile2
-rw-r--r--erts/etc/common/Makefile2
-rw-r--r--erts/etc/common/Makefile.in2
-rw-r--r--erts/etc/common/ct_run.c26
-rw-r--r--erts/etc/common/dialyzer.c26
-rw-r--r--erts/etc/common/erlc.c26
-rw-r--r--erts/etc/common/erlexec.c27
-rw-r--r--erts/etc/common/escript.c26
-rw-r--r--erts/etc/common/heart.c2
-rw-r--r--erts/etc/common/inet_gethost.c4
-rw-r--r--erts/etc/common/typer.c26
-rw-r--r--erts/etc/unix/Install.src2
-rw-r--r--erts/etc/unix/Makefile2
-rw-r--r--erts/etc/unix/README2
-rw-r--r--erts/etc/unix/RELNOTES2
-rw-r--r--erts/etc/unix/cerl.src2
-rw-r--r--erts/etc/unix/dyn_erl.c2
-rw-r--r--erts/etc/unix/erl.src.src2
-rw-r--r--erts/etc/unix/etp-commands.in4
-rw-r--r--erts/etc/unix/etp-thr.py2
-rw-r--r--erts/etc/unix/etp_commands.erl2
-rw-r--r--erts/etc/unix/etp_commands.mk2
-rw-r--r--erts/etc/unix/format_man_pages2
-rw-r--r--erts/etc/unix/run_erl.c18
-rw-r--r--erts/etc/unix/run_erl.h2
-rw-r--r--erts/etc/unix/safe_string.c2
-rw-r--r--erts/etc/unix/safe_string.h2
-rw-r--r--erts/etc/unix/setuid_socket_wrap.c2
-rw-r--r--erts/etc/unix/start.src2
-rw-r--r--erts/etc/unix/start_erl.src2
-rw-r--r--erts/etc/win32/Install.c2
-rw-r--r--erts/etc/win32/Makefile2
-rw-r--r--erts/etc/win32/Nmakefile.start_erl2
-rw-r--r--erts/etc/win32/beam.rc2
-rwxr-xr-xerts/etc/win32/cygwin_tools/erl2
-rwxr-xr-xerts/etc/win32/cygwin_tools/erlc2
-rwxr-xr-xerts/etc/win32/cygwin_tools/javac.sh2
-rwxr-xr-xerts/etc/win32/cygwin_tools/make_bootstrap_ini.sh2
-rwxr-xr-xerts/etc/win32/cygwin_tools/make_local_ini.sh2
-rwxr-xr-xerts/etc/win32/cygwin_tools/mingw/ar.sh2
-rwxr-xr-xerts/etc/win32/cygwin_tools/mingw/cc.sh2
-rw-r--r--erts/etc/win32/cygwin_tools/mingw/coffix.c2
-rwxr-xr-xerts/etc/win32/cygwin_tools/mingw/emu_cc.sh2
-rwxr-xr-xerts/etc/win32/cygwin_tools/mingw/ld.sh2
-rwxr-xr-xerts/etc/win32/cygwin_tools/mingw/mc.sh2
-rwxr-xr-xerts/etc/win32/cygwin_tools/mingw/rc.sh2
-rwxr-xr-xerts/etc/win32/cygwin_tools/vc/ar.sh2
-rwxr-xr-xerts/etc/win32/cygwin_tools/vc/cc.sh2
-rw-r--r--erts/etc/win32/cygwin_tools/vc/cc_wrap.c2
-rw-r--r--erts/etc/win32/cygwin_tools/vc/coffix.c2
-rwxr-xr-xerts/etc/win32/cygwin_tools/vc/emu_cc.sh2
-rwxr-xr-xerts/etc/win32/cygwin_tools/vc/ld.sh2
-rw-r--r--erts/etc/win32/cygwin_tools/vc/ld_wrap.c2
-rwxr-xr-xerts/etc/win32/cygwin_tools/vc/mc.sh2
-rwxr-xr-xerts/etc/win32/cygwin_tools/vc/rc.sh2
-rw-r--r--erts/etc/win32/erl.c2
-rw-r--r--erts/etc/win32/erl.rc2
-rw-r--r--erts/etc/win32/erl_log.c2
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_global.h2
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_interactive.c2
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_interactive.h2
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_main.c2
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_registry.c2
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_registry.h2
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_service.c2
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_service.h2
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_util.c2
-rw-r--r--erts/etc/win32/erlsrv/erlsrv_util.h2
-rw-r--r--erts/etc/win32/init_file.c2
-rw-r--r--erts/etc/win32/init_file.h2
-rw-r--r--erts/etc/win32/msys_tools/erl2
-rw-r--r--erts/etc/win32/msys_tools/erlc2
-rw-r--r--erts/etc/win32/msys_tools/javac.sh2
-rw-r--r--erts/etc/win32/msys_tools/make_bootstrap_ini.sh2
-rw-r--r--erts/etc/win32/msys_tools/make_local_ini.sh2
-rw-r--r--erts/etc/win32/msys_tools/vc/ar.sh2
-rw-r--r--erts/etc/win32/msys_tools/vc/cc.sh2
-rw-r--r--erts/etc/win32/msys_tools/vc/coffix.c2
-rw-r--r--erts/etc/win32/msys_tools/vc/emu_cc.sh2
-rw-r--r--erts/etc/win32/msys_tools/vc/ld.sh2
-rw-r--r--erts/etc/win32/msys_tools/vc/mc.sh2
-rw-r--r--erts/etc/win32/msys_tools/vc/rc.sh2
-rw-r--r--erts/etc/win32/nsis/Makefile2
-rwxr-xr-xerts/etc/win32/nsis/dll_version_helper.sh2
-rw-r--r--erts/etc/win32/nsis/erlang20.nsi2
-rwxr-xr-xerts/etc/win32/nsis/find_redist.sh2
-rw-r--r--erts/etc/win32/port_entry.c2
-rw-r--r--erts/etc/win32/resource.h2
-rw-r--r--erts/etc/win32/start_erl.c2
-rw-r--r--erts/etc/win32/win_erlexec.c2
-rw-r--r--erts/example/Makefile2
-rw-r--r--erts/example/matrix_nif.c2
-rw-r--r--erts/example/matrix_nif.erl2
-rw-r--r--erts/example/next_perm.cc2
-rw-r--r--erts/example/next_perm.erl2
-rw-r--r--erts/example/pg_async.c2
-rw-r--r--erts/example/pg_async.erl2
-rw-r--r--erts/example/pg_async2.c2
-rw-r--r--erts/example/pg_async2.erl2
-rw-r--r--erts/example/pg_encode.c2
-rw-r--r--erts/example/pg_encode.h2
-rw-r--r--erts/example/pg_encode2.c2
-rw-r--r--erts/example/pg_encode2.h2
-rw-r--r--erts/example/pg_sync.c2
-rw-r--r--erts/example/pg_sync.erl2
-rw-r--r--erts/include/erl_fixed_size_int_types.h2
-rw-r--r--erts/include/erl_int_sizes_config.h.in2
-rw-r--r--erts/include/erl_memory_trace_parser.h2
-rw-r--r--erts/include/erl_native_features_config.h.in2
-rw-r--r--erts/include/internal/README2
-rw-r--r--erts/include/internal/erl_errno.h2
-rw-r--r--erts/include/internal/erl_memory_trace_protocol.h2
-rw-r--r--erts/include/internal/erl_misc_utils.h2
-rw-r--r--erts/include/internal/erl_printf.h2
-rw-r--r--erts/include/internal/erl_printf_format.h2
-rw-r--r--erts/include/internal/erts_internal.mk.in2
-rw-r--r--erts/include/internal/ethr_atomics.h2
-rw-r--r--erts/include/internal/ethr_internal.h2
-rw-r--r--erts/include/internal/ethr_mutex.h2
-rw-r--r--erts/include/internal/ethr_optimized_fallbacks.h2
-rw-r--r--erts/include/internal/ethread.h4
-rw-r--r--erts/include/internal/ethread.mk.in2
-rw-r--r--erts/include/internal/ethread_header_config.h.in2
-rw-r--r--erts/include/internal/ethread_inline.h2
-rw-r--r--erts/include/internal/i386/atomic.h2
-rw-r--r--erts/include/internal/i386/ethr_dw_atomic.h2
-rw-r--r--erts/include/internal/i386/ethr_membar.h2
-rw-r--r--erts/include/internal/i386/ethread.h2
-rw-r--r--erts/include/internal/i386/rwlock.h2
-rw-r--r--erts/include/internal/i386/spinlock.h2
-rw-r--r--erts/include/internal/libatomic_ops/ethr_atomic.h2
-rw-r--r--erts/include/internal/libatomic_ops/ethr_dw_atomic.h2
-rw-r--r--erts/include/internal/libatomic_ops/ethr_membar.h2
-rw-r--r--erts/include/internal/libatomic_ops/ethread.h2
-rw-r--r--erts/include/internal/ppc32/atomic.h2
-rw-r--r--erts/include/internal/ppc32/ethr_membar.h2
-rw-r--r--erts/include/internal/ppc32/ethread.h2
-rw-r--r--erts/include/internal/ppc32/rwlock.h2
-rw-r--r--erts/include/internal/ppc32/spinlock.h2
-rw-r--r--erts/include/internal/pthread/ethr_event.h2
-rw-r--r--erts/include/internal/sparc32/atomic.h2
-rw-r--r--erts/include/internal/sparc32/ethr_membar.h2
-rw-r--r--erts/include/internal/sparc32/ethread.h2
-rw-r--r--erts/include/internal/sparc32/rwlock.h2
-rw-r--r--erts/include/internal/sparc32/spinlock.h2
-rw-r--r--erts/include/internal/sparc64/ethread.h2
-rw-r--r--erts/include/internal/tile/atomic.h2
-rw-r--r--erts/include/internal/tile/ethr_membar.h2
-rw-r--r--erts/include/internal/tile/ethread.h2
-rw-r--r--erts/include/internal/win/ethr_atomic.h2
-rw-r--r--erts/include/internal/win/ethr_dw_atomic.h2
-rw-r--r--erts/include/internal/win/ethr_event.h2
-rw-r--r--erts/include/internal/win/ethr_membar.h2
-rw-r--r--erts/include/internal/win/ethread.h2
-rw-r--r--erts/include/internal/x86_64/ethread.h2
-rw-r--r--erts/lib/internal/README2
-rw-r--r--erts/lib_src/Makefile2
-rw-r--r--erts/lib_src/Makefile.in2
-rw-r--r--erts/lib_src/common/erl_memory_trace_parser.c2
-rw-r--r--erts/lib_src/common/erl_misc_utils.c2
-rw-r--r--erts/lib_src/common/erl_printf.c2
-rw-r--r--erts/lib_src/common/erl_printf_format.c2
-rw-r--r--erts/lib_src/common/ethr_atomics.c2
-rw-r--r--erts/lib_src/common/ethr_aux.c2
-rw-r--r--erts/lib_src/common/ethr_cbf.c2
-rw-r--r--erts/lib_src/common/ethr_mutex.c2
-rw-r--r--erts/lib_src/pthread/ethr_event.c8
-rw-r--r--erts/lib_src/pthread/ethr_x86_sse2_asm.c2
-rw-r--r--erts/lib_src/pthread/ethread.c2
-rwxr-xr-xerts/lib_src/utils/make_atomics_api2
-rw-r--r--erts/lib_src/win/ethr_event.c2
-rw-r--r--erts/lib_src/win/ethread.c2
-rw-r--r--erts/preloaded/Makefile2
-rw-r--r--erts/preloaded/ebin/erl_prim_loader.beambin55528 -> 55800 bytes
-rw-r--r--erts/preloaded/ebin/erl_tracer.beambin0 -> 2128 bytes
-rw-r--r--erts/preloaded/ebin/erlang.beambin102200 -> 104172 bytes
-rw-r--r--erts/preloaded/ebin/erts_code_purger.beambin8704 -> 8712 bytes
-rw-r--r--erts/preloaded/ebin/erts_internal.beambin9976 -> 10552 bytes
-rw-r--r--erts/preloaded/ebin/init.beambin44588 -> 49944 bytes
-rw-r--r--erts/preloaded/ebin/otp_ring0.beambin1448 -> 1460 bytes
-rw-r--r--erts/preloaded/ebin/prim_eval.beambin1320 -> 1328 bytes
-rw-r--r--erts/preloaded/ebin/prim_file.beambin44800 -> 44780 bytes
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin72608 -> 72564 bytes
-rw-r--r--erts/preloaded/ebin/prim_zip.beambin23156 -> 23172 bytes
-rw-r--r--erts/preloaded/ebin/zlib.beambin14156 -> 14152 bytes
-rw-r--r--erts/preloaded/src/Makefile5
-rw-r--r--erts/preloaded/src/add_abstract_code2
-rw-r--r--erts/preloaded/src/erl_prim_loader.erl13
-rw-r--r--erts/preloaded/src/erl_tracer.erl59
-rw-r--r--erts/preloaded/src/erlang.erl119
-rw-r--r--erts/preloaded/src/erts.app.src2
-rw-r--r--erts/preloaded/src/erts_internal.erl31
-rw-r--r--erts/preloaded/src/init.erl200
-rw-r--r--erts/preloaded/src/otp_ring0.erl2
-rw-r--r--erts/preloaded/src/prim_eval.S2
-rw-r--r--erts/preloaded/src/prim_eval.erl2
-rw-r--r--erts/preloaded/src/prim_inet.erl2
-rw-r--r--erts/preloaded/src/prim_zip.erl2
-rw-r--r--erts/preloaded/src/zip_internal.hrl2
-rw-r--r--erts/preloaded/src/zlib.erl2
-rw-r--r--erts/start_scripts/Makefile2
-rw-r--r--erts/start_scripts/no_dot_erlang.rel.src2
-rw-r--r--erts/start_scripts/start_all_example.rel.src2
-rw-r--r--erts/start_scripts/start_clean.rel.src2
-rw-r--r--erts/start_scripts/start_sasl.rel.src2
-rw-r--r--erts/test/Makefile2
-rw-r--r--erts/test/erl_print_SUITE.erl507
-rw-r--r--erts/test/erl_print_SUITE_data/Makefile.src2
-rw-r--r--erts/test/erl_print_SUITE_data/character_test.h2
-rw-r--r--erts/test/erl_print_SUITE_data/erl_print_tests.c2
-rw-r--r--erts/test/erl_print_SUITE_data/integer_64_test.h2
-rw-r--r--erts/test/erl_print_SUITE_data/integer_test.h2
-rw-r--r--erts/test/erl_print_SUITE_data/snprintf_test.h2
-rw-r--r--erts/test/erl_print_SUITE_data/string_test.h2
-rw-r--r--erts/test/erlc_SUITE.erl329
-rw-r--r--erts/test/erlc_SUITE_data/include/erl_test.hrl2
-rw-r--r--erts/test/erlc_SUITE_data/src/erl_test_bad.erl2
-rw-r--r--erts/test/erlc_SUITE_data/src/erl_test_missing_header.erl2
-rw-r--r--erts/test/erlc_SUITE_data/src/erl_test_ok.erl2
-rw-r--r--erts/test/erlc_SUITE_data/src/yecc_test_bad.yrl2
-rw-r--r--erts/test/erlc_SUITE_data/src/yecc_test_ok.yrl2
-rw-r--r--erts/test/erlexec_SUITE.erl240
-rw-r--r--erts/test/erlexec_SUITE_data/Makefile.src2
-rw-r--r--erts/test/erlexec_SUITE_data/erlexec_tests.c2
-rw-r--r--erts/test/ethread_SUITE.erl247
-rw-r--r--erts/test/ethread_SUITE_data/Makefile.src2
-rw-r--r--erts/test/ethread_SUITE_data/ethread_tests.c2
-rw-r--r--erts/test/ignore_cores.erl14
-rw-r--r--erts/test/install_SUITE.erl350
-rw-r--r--erts/test/nt_SUITE.erl703
-rw-r--r--erts/test/nt_SUITE_data/Makefile.src2
-rw-r--r--erts/test/nt_SUITE_data/nt_info.c2
-rw-r--r--erts/test/otp_SUITE.erl533
-rw-r--r--erts/test/run_erl_SUITE.erl155
-rw-r--r--erts/test/run_erl_SUITE_data/defuncter.pl2
-rw-r--r--erts/test/run_erl_SUITE_data/run_erl_test.pl2
-rw-r--r--erts/test/upgrade_SUITE.erl20
-rw-r--r--erts/test/upgrade_SUITE_data/start.src2
-rw-r--r--erts/test/utils/gccifier.c2
-rwxr-xr-xerts/test/utils/gccifier.sh2
-rw-r--r--erts/test/z_SUITE.erl47
757 files changed, 15161 insertions, 8000 deletions
diff --git a/erts/AUTHORS b/erts/AUTHORS
index d8746f65b2..5555502099 100644
--- a/erts/AUTHORS
+++ b/erts/AUTHORS
@@ -1,7 +1,7 @@
%CopyrightBegin%
- Copyright Ericsson AB 1999-2009. All Rights Reserved.
+ Copyright Ericsson AB 1999-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.
diff --git a/erts/Makefile.in b/erts/Makefile.in
index feed00dad5..3052dc3065 100644
--- a/erts/Makefile.in
+++ b/erts/Makefile.in
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2006-2013. All Rights Reserved.
+# Copyright Ericsson AB 2006-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.
diff --git a/erts/aclocal.m4 b/erts/aclocal.m4
index 017fdbd589..86799186fd 100644
--- a/erts/aclocal.m4
+++ b/erts/aclocal.m4
@@ -1,7 +1,7 @@
dnl
dnl %CopyrightBegin%
dnl
-dnl Copyright Ericsson AB 1998-2015. All Rights Reserved.
+dnl Copyright Ericsson AB 1998-2016. All Rights Reserved.
dnl
dnl Licensed under the Apache License, Version 2.0 (the "License");
dnl you may not use this file except in compliance with the License.
diff --git a/erts/autoconf/configure.vxworks b/erts/autoconf/configure.vxworks
index 96dd1f8401..a13e0a6c56 100755
--- a/erts/autoconf/configure.vxworks
+++ b/erts/autoconf/configure.vxworks
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2011. All Rights Reserved.
+# Copyright Ericsson AB 1997-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.
diff --git a/erts/autoconf/vxworks/sed.general b/erts/autoconf/vxworks/sed.general
index 5adee4db45..96a70e4148 100644
--- a/erts/autoconf/vxworks/sed.general
+++ b/erts/autoconf/vxworks/sed.general
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2013. All Rights Reserved.
+# Copyright Ericsson AB 1997-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.
diff --git a/erts/autoconf/vxworks/sed.vxworks_cpu32 b/erts/autoconf/vxworks/sed.vxworks_cpu32
index e3d54246ab..71663676e7 100644
--- a/erts/autoconf/vxworks/sed.vxworks_cpu32
+++ b/erts/autoconf/vxworks/sed.vxworks_cpu32
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2010. All Rights Reserved.
+# Copyright Ericsson AB 1997-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.
diff --git a/erts/autoconf/vxworks/sed.vxworks_ppc32 b/erts/autoconf/vxworks/sed.vxworks_ppc32
index 012760e127..2146e862fd 100644
--- a/erts/autoconf/vxworks/sed.vxworks_ppc32
+++ b/erts/autoconf/vxworks/sed.vxworks_ppc32
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2006-2013. All Rights Reserved.
+# Copyright Ericsson AB 2006-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.
diff --git a/erts/autoconf/vxworks/sed.vxworks_ppc603 b/erts/autoconf/vxworks/sed.vxworks_ppc603
index 55af52571b..fca1ba76d9 100644
--- a/erts/autoconf/vxworks/sed.vxworks_ppc603
+++ b/erts/autoconf/vxworks/sed.vxworks_ppc603
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2000-2010. All Rights Reserved.
+# Copyright Ericsson AB 2000-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.
diff --git a/erts/autoconf/vxworks/sed.vxworks_ppc603_nolongcall b/erts/autoconf/vxworks/sed.vxworks_ppc603_nolongcall
index e0c0891aeb..51c589d79a 100644
--- a/erts/autoconf/vxworks/sed.vxworks_ppc603_nolongcall
+++ b/erts/autoconf/vxworks/sed.vxworks_ppc603_nolongcall
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2010. All Rights Reserved.
+# Copyright Ericsson AB 1997-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.
diff --git a/erts/autoconf/vxworks/sed.vxworks_ppc860 b/erts/autoconf/vxworks/sed.vxworks_ppc860
index 8828339e34..485504e706 100644
--- a/erts/autoconf/vxworks/sed.vxworks_ppc860
+++ b/erts/autoconf/vxworks/sed.vxworks_ppc860
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2010. All Rights Reserved.
+# Copyright Ericsson AB 1997-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.
diff --git a/erts/autoconf/vxworks/sed.vxworks_simlinux b/erts/autoconf/vxworks/sed.vxworks_simlinux
index 950fb79ec5..10cd7bbb82 100644
--- a/erts/autoconf/vxworks/sed.vxworks_simlinux
+++ b/erts/autoconf/vxworks/sed.vxworks_simlinux
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2008-2013. All Rights Reserved.
+# Copyright Ericsson AB 2008-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.
diff --git a/erts/autoconf/vxworks/sed.vxworks_simso b/erts/autoconf/vxworks/sed.vxworks_simso
index 6f2796f04e..cd30f8c2b2 100644
--- a/erts/autoconf/vxworks/sed.vxworks_simso
+++ b/erts/autoconf/vxworks/sed.vxworks_simso
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2005-2013. All Rights Reserved.
+# Copyright Ericsson AB 2005-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.
diff --git a/erts/autoconf/vxworks/sed.vxworks_sparc b/erts/autoconf/vxworks/sed.vxworks_sparc
index e67c34af26..a3758423e8 100644
--- a/erts/autoconf/vxworks/sed.vxworks_sparc
+++ b/erts/autoconf/vxworks/sed.vxworks_sparc
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2009. All Rights Reserved.
+# Copyright Ericsson AB 1997-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.
diff --git a/erts/configure.in b/erts/configure.in
index 021780ecc2..6765f47a88 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -2,7 +2,7 @@ dnl Process this file with autoconf to produce a configure script. -*-m4-*-
dnl %CopyrightBegin%
dnl
-dnl Copyright Ericsson AB 1997-2015. All Rights Reserved.
+dnl Copyright Ericsson AB 1997-2016. All Rights Reserved.
dnl
dnl Licensed under the Apache License, Version 2.0 (the "License");
dnl you may not use this file except in compliance with the License.
@@ -62,9 +62,6 @@ if test x"${ERL_TOP}/erts" != x"$srcdir"; then
fi
erl_top=${ERL_TOP}
-# Remove old configuration information
-/bin/rm -f "$ERL_TOP/erts/CONF_INFO"
-
# echo XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# echo X
# echo "X srcdir = $srcdir"
@@ -215,24 +212,6 @@ AS_HELP_STRING([--enable-fp-exceptions],
esac
],enable_fp_exceptions=auto)
-AC_ARG_ENABLE(darwin-universal,
-AS_HELP_STRING([--enable-darwin-universal],
- [build universal binaries on darwin i386]),
-[ case "$enableval" in
- no) enable_darwin_universal=no ;;
- *) enable_darwin_univeral=yes ;;
- esac
-],enable_darwin_universal=no)
-
-
-AC_ARG_ENABLE(darwin-64bit,
-AS_HELP_STRING([--enable-darwin-64bit], [build 64bit binaries on darwin]),
-[ case "$enableval" in
- no) enable_darwin_64bit=no ;;
- *) enable_darwin_64bit=yes ;;
- esac
-],enable_darwin_64bit=no)
-
AC_ARG_ENABLE(m64-build,
AS_HELP_STRING([--enable-m64-build],
[build 64bit binaries using the -m64 flag to (g)cc]),
@@ -247,18 +226,13 @@ AS_HELP_STRING([--enable-m32-build],
[build 32bit binaries using the -m32 flag to (g)cc]),
[ case "$enableval" in
no) enable_m32_build=no ;;
- *)
- if test X${enable_darwin_64bit} = Xyes -o X${enable_m64_build} = Xyes;
- then
- AC_MSG_ERROR([(--enable-darwin-64bit or --enable-m64-build) and --enable-m32-build are mutually exclusive]) ;
- fi ;
- enable_m32_build=yes ;;
+ *) enable_m32_build=yes ;;
esac
],enable_m32_build=no)
AC_ARG_WITH(dynamic-trace,
-AS_HELP_STRING([--with-dynamic-trace={dtrace|systemtap}],
- [specify use of dynamic trace framework, dtrace or systemtap])
+AS_HELP_STRING([--with-dynamic-trace={dtrace|lttng|systemtap}],
+ [specify use of dynamic trace framework, dtrace, lttng or systemtap])
AS_HELP_STRING([--without-dynamic-trace],
[don't enable any dynamic tracing (default)]))
@@ -268,6 +242,10 @@ fi
case "$with_dynamic_trace" in
no) DYNAMIC_TRACE_FRAMEWORK=;;
+ lttng)
+ AC_DEFINE(USE_LTTNG,[1],
+ [Define if you want to use lttng for dynamic tracing])
+ DYNAMIC_TRACE_FRAMEWORK=lttng;;
dtrace)
AC_DEFINE(USE_DTRACE,[1],
[Define if you want to use dtrace for dynamic tracing])
@@ -303,10 +281,12 @@ AS_HELP_STRING([--enable-vm-probes],
fi)
AC_SUBST(USE_VM_PROBES)
-if test X"$use_vm_probes" = X"yes"; then
- USE_VM_PROBES=yes
- AC_DEFINE(USE_VM_PROBES,[1],
- [Define to enable VM dynamic trace probes])
+if test X"$DYNAMIC_TRACE_FRAMEWORK" != X"lttng"; then
+ if test X"$use_vm_probes" = X"yes"; then
+ USE_VM_PROBES=yes
+ AC_DEFINE(USE_VM_PROBES,[1],
+ [Define to enable VM dynamic trace probes])
+ fi
fi
AC_ARG_WITH(assumed-cache-line-size,
@@ -377,42 +357,7 @@ AC_MSG_CHECKING([OTP version])
AC_MSG_RESULT([$OTP_VERSION])
AC_SUBST(OTP_VERSION)
-dnl OK, we might have darwin switches off different kinds, lets
-dnl check it all before continuing.
-TMPSYS=`uname -s`-`uname -m`
-if test X${enable_darwin_universal} = Xyes; then
- if test X${enable_darwin_64bit} = Xyes; then
- AC_MSG_ERROR([--enable-darwin-universal and --enable-darwin-64bit mutually exclusive])
- fi
- enable_hipe=no
- case $CFLAGS in
- *-arch\ ppc*)
- ;;
- *)
- CFLAGS="-arch ppc $CFLAGS"
- ;;
- esac
- case $CFLAGS in
- *-arch\ i386*)
- ;;
- *)
- CFLAGS="-arch i386 $CFLAGS"
- ;;
- esac
-fi
-if test X${enable_darwin_64bit} = Xyes; then
- case "$TMPSYS" in
- Darwin-i386|Darwin-x86_64)
- ;;
- Darwin*)
- AC_MSG_ERROR([--enable-darwin-64bit only supported on x86 hosts])
- ;;
- *)
- AC_MSG_ERROR([--enable-darwin-64bit only supported on Darwin])
- ;;
- esac
-fi
-if test X${enable_darwin_64bit} = Xyes -o X${enable_m64_build} = Xyes; then
+if test X${enable_m64_build} = Xyes; then
case $CFLAGS in
*-m64*)
;;
@@ -476,9 +421,6 @@ case $host_os in
# -D_WIN32_WINNT=* from CPPFLAGS is saved in ETHR_DEFS.
CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600 -DWINVER=0x0600"
;;
- darwin*)
- CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE"
- ;;
*)
;;
esac
@@ -738,32 +680,13 @@ case $ARCH-$OPSYS in
esac
;;
*-darwin*)
- if test X${enable_darwin_universal} = Xyes; then
- AC_MSG_NOTICE([Adjusting LDFLAGS for universal binaries])
-
- case $LDFLAGS in
- *-arch\ ppc*)
- ;;
- *)
- LDFLAGS="-arch ppc $LDFLAGS"
- ;;
- esac
- case $LDFLAGS in
- *-arch\ i386*)
- ;;
- *)
- LDFLAGS="-arch i386 $LDFLAGS"
- ;;
- esac
- else
- case $LDFLAGS in
- *-m32*)
- ;;
- *)
- LDFLAGS="-m32 $LDFLAGS"
- ;;
- esac
- fi
+ case $LDFLAGS in
+ *-m32*)
+ ;;
+ *)
+ LDFLAGS="-m32 $LDFLAGS"
+ ;;
+ esac
;;
*)
if test X${enable_m64_build} = Xyes; then
@@ -803,8 +726,27 @@ esac
AC_SUBST(LIBCARBON)
-dnl Check if we should/can build a sharing-preserving emulator
+_search_path=/bin:/usr/bin:/usr/local/bin:$PATH
+
+AC_PATH_PROG(RM, rm, false, $_search_path)
+if test "$ac_cv_path_RM" = false; then
+ AC_MSG_ERROR([No 'rm' command found])
+fi
+
+AC_PATH_PROG(MKDIR, mkdir, false, $_search_path)
+if test "$ac_cv_path_MKDIR" = false; then
+ AC_MSG_ERROR([No 'mkdir' command found])
+fi
+_search_path=
+
+
+# Remove old configuration information.
+# Next line should be placed after AC_PATH_PROG(RM, ...), but before
+# first output to CONN_INFO. So this is just the right place.
+$RM -f "$ERL_TOP/erts/CONF_INFO"
+
+dnl Check if we should/can build a sharing-preserving emulator
AC_MSG_CHECKING(if we are building a sharing-preserving emulator)
if test "$enable_sharing_preserving" = "yes"; then
AC_DEFINE(SHCOPY, [1],
@@ -834,27 +776,13 @@ if test "$ac_cv_prog_AR" = false; then
AC_MSG_ERROR([No 'ar' command found in PATH])
fi
-_search_path=/bin:/usr/bin:/usr/local/bin:$PATH
-
-AC_PATH_PROG(RM, rm, false, $_search_path)
-if test "$ac_cv_path_RM" = false; then
- AC_MSG_ERROR([No 'rm' command found])
-fi
-
-AC_PATH_PROG(MKDIR, mkdir, false, $_search_path)
-if test "$ac_cv_path_MKDIR" = false; then
- AC_MSG_ERROR([No 'mkdir' command found])
-fi
-
-_search_path=
-
#
# Get programs needed for building the documentation
#
## Delete previous failed configure results
if test -f doc/CONF_INFO; then
- rm doc/CONF_INFO
+ $RM doc/CONF_INFO
fi
AC_CHECK_PROGS(XSLTPROC, xsltproc)
@@ -1626,7 +1554,7 @@ AC_CHECK_HEADERS(fcntl.h limits.h unistd.h syslog.h dlfcn.h ieeefp.h \
sys/ioctl.h sys/time.h sys/uio.h \
sys/socket.h sys/sockio.h sys/socketio.h \
net/errno.h malloc.h arpa/nameser.h libdlpi.h \
- pty.h util.h utmp.h langinfo.h poll.h sdkddkver.h)
+ pty.h util.h libutil.h utmp.h langinfo.h poll.h sdkddkver.h)
AC_CHECK_MEMBERS([struct ifreq.ifr_hwaddr], [], [],
[#ifdef __WIN32__
@@ -2810,44 +2738,6 @@ if test "$cross_compiling" != "yes" && test X${enable_hipe} != Xno; then
fi
fi
-case $ARCH-$OPSYS in
- amd64-darwin*|x86-darwin*)
- AC_MSG_CHECKING([For modern (leopard) style mcontext_t])
- AC_TRY_COMPILE([
- #include <stdlib.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <mach/mach.h>
- #include <pthread.h>
- #include <machine/signal.h>
- #include <ucontext.h>
- ],[
- #if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__)
- #define __DARWIN__ 1
- #endif
-
- #ifndef __DARWIN__
- #error inpossible
- #else
-
- mcontext_t mc = NULL;
- int x = mc->__fs.__fpu_mxcsr;
-
- #endif
- ],darwin_mcontext_leopard=yes,
- darwin_mcontext_leopard=no)
- if test X"$darwin_mcontext_leopard" = X"yes"; then
- AC_DEFINE(DARWIN_MODERN_MCONTEXT,[],[Modern style mcontext_t in MacOSX])
- AC_MSG_RESULT(yes)
- else
- AC_MSG_RESULT(no)
- fi
- ;;
- *)
- darwin_mcontext_leopard=no
- ;;
-esac
-
if test X${enable_fp_exceptions} = Xauto ; then
case $host_os in
*linux*)
@@ -3463,6 +3353,13 @@ if test X${enable_hipe} = Xyes; then
AC_DEFINE(HIPE,[1],[Define to enable HiPE])
HIPE_HELPERS="xmerl syntax_tools edoc"
ENABLE_ALLOC_TYPE_VARS="$ENABLE_ALLOC_TYPE_VARS hipe"
+ case "$ARCH" in
+ amd64)
+ # For now exec_alloc is only used for hipe on amd64
+ AC_MSG_NOTICE([Enable exec_alloc for hipe code allocation])
+ ENABLE_ALLOC_TYPE_VARS="$ENABLE_ALLOC_TYPE_VARS exec_alloc"
+ ;;
+ esac
fi
fi
AC_SUBST(HIPE_HELPERS)
@@ -3788,14 +3685,8 @@ case $host_os in
DED_LDFLAGS="-m64 $DED_LDFLAGS"
;;
*)
- if test X${enable_darwin_universal} != Xyes; then
- DED_LDFLAGS="-m32 $DED_LDFLAGS"
- fi
;;
esac
- if test X${enable_darwin_universal} = Xyes; then
- DED_LDFLAGS="-arch ppc -arch i386 $DED_LDFLAGS"
- fi
DED_LD="$CC"
DED_LD_FLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH"
;;
@@ -3880,14 +3771,20 @@ dnl
LM_FIND_EMU_CC
dnl
-dnl DTrace
+dnl DTrace & LTTNG
dnl
case $DYNAMIC_TRACE_FRAMEWORK in
dtrace|systemtap)
AC_CHECK_TOOL(DTRACE, dtrace, none)
test "$DTRACE" = "none" && AC_MSG_ERROR([No dtrace utility found.]);
+ enable_lttng_test=no
enable_dtrace_test=yes;;
- *) enable_dtrace_test=no;;
+ lttng)
+ enable_lttng_test=yes
+ enable_dtrace_test=no;;
+ *)
+ enable_lttng_test=no
+ enable_dtrace_test=no;;
esac
AC_SUBST(DTRACE)
@@ -3928,7 +3825,7 @@ if test "$enable_dtrace_test" = "yes" ; then
[$RM -f $DTRACE_2STEP_TEST
dtrace -G $DTRACE_CPP $DTRACE_BITS_FLAG -Iemulator/beam -o $DTRACE_2STEP_TEST -s emulator/beam/erlang_dtrace.d conftest.$OBJEXT 2>&AS_MESSAGE_LOG_FD
if test -f $DTRACE_2STEP_TEST; then
- rm $DTRACE_2STEP_TEST
+ $RM $DTRACE_2STEP_TEST
DTRACE_ENABLED_2STEP=yes
fi],
[])
@@ -3954,6 +3851,37 @@ if test "$enable_dtrace_test" = "yes" ; then
fi
fi
+if test "$enable_lttng_test" = "yes" ; then
+ AC_CHECK_HEADERS(lttng/tracepoint.h)
+ AC_CHECK_HEADERS(lttng/tracepoint-event.h)
+ dnl The macro tracepoint_enabled is not present in older lttng versions
+ dnl checking for tracepoint_enabled
+ AC_MSG_CHECKING([for tracepoint_enabled in lttng/tracepoint.h])
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [#include <lttng/tracepoint.h>
+ #define TRACEPOINT_PROVIDER com_ericsson_otp
+ TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ dummy,
+ TP_ARGS(int, my_int),
+ TP_FIELDS(ctf_integer(int, my_int, my_int)))
+ #define TRACEPOINT_CREATE_PROBES
+ #define TRACEPOINT_DEFINE],
+ [if(tracepoint_enabled(com_ericsson_otp,dummy)) do {} while(0)])],
+ [AC_MSG_RESULT([yes])],
+ [AC_MSG_ERROR([no (must be present)])])
+ if test "x$ac_cv_header_lttng_tracepoint_h" = "xyes" \
+ -a "x$ac_cv_header_lttng_tracepoint_event_h" = "xyes"; then
+ # No straight forward way to test for liblttng-ust when no public symbol exists,
+ # just add the lib.
+ LIBS="$LIBS -llttng-ust -ldl"
+ else
+ AC_MSG_ERROR([No LTTng support found.])
+ fi
+fi
+
+
dnl
dnl SSL, SSH and CRYPTO need the OpenSSL libraries
dnl
@@ -4104,7 +4032,7 @@ ssl_done=yes # Default only one run
# Remove all SKIP files from previous runs
for a in ssl crypto ssh; do
- /bin/rm -f $ERL_TOP/lib/$a/SKIP
+ $RM -f $ERL_TOP/lib/$a/SKIP
done
SSL_DYNAMIC_ONLY=$enable_dynamic_ssl
@@ -4701,7 +4629,7 @@ need_java="jinterface ic/java_src"
# Remove all SKIP files from previous runs
for a in $need_java ; do
- /bin/rm -f $ERL_TOP/lib/$a/SKIP
+ $RM -f $ERL_TOP/lib/$a/SKIP
done
if test "X$with_javac" = "Xno"; then
@@ -4752,7 +4680,7 @@ dnl this deliberately does not believe that 'gcc' is a C++ compiler
AC_CHECK_TOOLS(CXX, [$CCC c++ g++ CC cxx cc++ cl], false)
# Remove SKIP file from previous run
-/bin/rm -f $ERL_TOP/lib/orber/SKIP
+$RM -f $ERL_TOP/lib/orber/SKIP
if test "$CXX" = false; then
echo "No C++ compiler found" > $ERL_TOP/lib/orber/SKIP
diff --git a/erts/doc/Makefile b/erts/doc/Makefile
index d415e544f3..f26a43592e 100644
--- a/erts/doc/Makefile
+++ b/erts/doc/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2009. All Rights Reserved.
+# Copyright Ericsson AB 1996-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.
diff --git a/erts/doc/src/Makefile b/erts/doc/src/Makefile
index 83f4c58560..b96cbbce40 100644
--- a/erts/doc/src/Makefile
+++ b/erts/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2012. All Rights Reserved.
+# Copyright Ericsson AB 1997-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.
@@ -50,12 +50,14 @@ XML_REF1_FILES = epmd.xml \
XML_REF3_EFILES = \
erl_prim_loader.xml \
erlang.xml \
+ erl_tracer.xml \
init.xml \
zlib.xml
XML_REF3_FILES = \
driver_entry.xml \
erl_nif.xml \
+ erl_tracer.xml \
erl_driver.xml \
erl_prim_loader.xml \
erlang.xml \
@@ -154,18 +156,9 @@ clean:
rm -f $(SPECDIR)/*
rm -f errs core *~
-$(SPECDIR)/specs_driver_entry.xml:
+$(SPECDIR)/specs_%.xml:
escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
- -o$(dir $@) -module driver_entry
-$(SPECDIR)/specs_erl_nif.xml:
- escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
- -o$(dir $@) -module erl_nif
-$(SPECDIR)/specs_erl_driver.xml:
- escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
- -o$(dir $@) -module erl_driver
-$(SPECDIR)/specs_erts_alloc.xml:
- escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
- -o$(dir $@) -module erts_alloc
+ -o$(dir $@) -module $(patsubst $(SPECDIR)/specs_%.xml,%,$@)
# ----------------------------------------------------
# Release Target
diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml
index 13756ddfdc..bfabb7f042 100644
--- a/erts/doc/src/absform.xml
+++ b/erts/doc/src/absform.xml
@@ -68,22 +68,12 @@
<item>If D is a module declaration consisting of the forms
<c>F_1</c>, ..., <c>F_k</c>, then
Rep(D) = <c>[Rep(F_1), ..., Rep(F_k)]</c>.</item>
- <item>If F is an attribute <c>-behavior(Behavior)</c>, then
- Rep(F) = <c>{attribute,LINE,behavior,Behavior}</c>.</item>
- <item>If F is an attribute <c>-behaviour(Behaviour)</c>, then
- Rep(F) = <c>{attribute,LINE,behaviour,Behaviour}</c>.</item>
- <item>If F is an attribute <c>-compile(Options)</c>, then
- Rep(F) = <c>{attribute,LINE,compile,Options}</c>.</item>
<item>If F is an attribute <c>-export([Fun_1/A_1, ..., Fun_k/A_k])</c>, then
Rep(F) = <c>{attribute,LINE,export,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}</c>.</item>
- <item>If F is an attribute <c>-export_type([Type_1/A_1, ..., Type_k/A_k])</c>, then
- Rep(F) = <c>{attribute,LINE,export_type,[{Type_1,A_1}, ..., {Type_k,A_k}]}</c>.</item>
<item>If F is an attribute <c>-import(Mod,[Fun_1/A_1, ..., Fun_k/A_k])</c>, then
Rep(F) = <c>{attribute,LINE,import,{Mod,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}}</c>.</item>
<item>If F is an attribute <c>-module(Mod)</c>, then
Rep(F) = <c>{attribute,LINE,module,Mod}</c>.</item>
- <item>If F is an attribute <c>-optional_callbacks([Fun_1/A_1, ..., Fun_k/A_k])</c>, then
- Rep(F) = <c>{attribute,LINE,optional_callbacks,[{Fun_1,A_1}, ..., {Fun_k,A_k}]}</c>.</item>
<item>If F is an attribute <c>-file(File,Line)</c>, then
Rep(F) = <c>{attribute,LINE,file,{File,Line}}</c>.</item>
<item>If F is a function declaration
@@ -636,6 +626,9 @@
<item>If A is an association type <c>K => V</c>, where
<c>K</c> and <c>V</c> are types, then Rep(A) =
<c>{type,LINE,map_field_assoc,[Rep(K),Rep(V)]}</c>.</item>
+ <item>If A is an association type <c>K := V</c>, where
+ <c>K</c> and <c>V</c> are types, then Rep(A) =
+ <c>{type,LINE,map_field_exact,[Rep(K),Rep(V)]}</c>.</item>
</list>
</section>
diff --git a/erts/doc/src/alt_dist.xml b/erts/doc/src/alt_dist.xml
index 2263302707..e283acc1b4 100644
--- a/erts/doc/src/alt_dist.xml
+++ b/erts/doc/src/alt_dist.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2000</year><year>2013</year>
+ <year>2000</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/book.xml b/erts/doc/src/book.xml
index 12eda03ee5..a0780c91d9 100644
--- a/erts/doc/src/book.xml
+++ b/erts/doc/src/book.xml
@@ -4,7 +4,7 @@
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<header titlestyle="normal">
<copyright>
- <year>1997</year><year>2013</year>
+ <year>1997</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/communication.xml b/erts/doc/src/communication.xml
index 3deea3e4af..1eb05310e9 100644
--- a/erts/doc/src/communication.xml
+++ b/erts/doc/src/communication.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2012</year><year>2013</year>
+ <year>2012</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/crash_dump.xml b/erts/doc/src/crash_dump.xml
index 61c9159823..0b827ae583 100644
--- a/erts/doc/src/crash_dump.xml
+++ b/erts/doc/src/crash_dump.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1999</year><year>2013</year>
+ <year>1999</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/driver.xml b/erts/doc/src/driver.xml
index a68e87d3b3..4bef5e1388 100644
--- a/erts/doc/src/driver.xml
+++ b/erts/doc/src/driver.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2001</year><year>2013</year>
+ <year>2001</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/epmd.xml b/erts/doc/src/epmd.xml
index 7f61804bea..d9f580d081 100644
--- a/erts/doc/src/epmd.xml
+++ b/erts/doc/src/epmd.xml
@@ -4,7 +4,7 @@
<comref>
<header>
<copyright>
- <year>1996</year><year>2013</year>
+ <year>1996</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml
index 096af096dc..c499fc8081 100644
--- a/erts/doc/src/erl.xml
+++ b/erts/doc/src/erl.xml
@@ -4,7 +4,7 @@
<comref>
<header>
<copyright>
- <year>1996</year><year>2015</year>
+ <year>1996</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -632,6 +632,15 @@
<p>Sets the initial process dictionary size of processes to the size
<c><![CDATA[Size]]></c>.</p>
</item>
+ <tag><marker id="+hmqd"><c>+hmqd off_heap|on_heap|mixed</c></marker></tag>
+ <item><p>
+ Sets the default value for the process flag
+ <c>message_queue_data</c>. If <c>+hmqd</c> is not
+ passed, <c>mixed</c> will be the default. For more information,
+ see the documentation of
+ <seealso marker="erlang#process_flag_message_queue_data"><c>process_flag(message_queue_data,
+ MQD)</c></seealso>.
+ </p></item>
<tag><c><![CDATA[+K true | false]]></c></tag>
<item>
<p>Enables or disables the kernel poll functionality if
@@ -1361,21 +1370,6 @@
<seealso marker="kernel:error_logger#warning_map/0">error_logger(3)</seealso>
for further information.</p>
</item>
- <tag><c><![CDATA[+xFlag Value]]></c></tag>
- <item>
- <p>Default process flag settings.</p>
- <taglist>
- <tag><marker id="+xmqd"><c>+xmqd off_heap|on_heap|mixed</c></marker></tag>
- <item><p>
- Sets the default value for the process flag
- <c>message_queue_data</c>. If <c>+xmqd</c> is not
- passed, <c>mixed</c> will be the default. For more information,
- see the documentation of
- <seealso marker="erlang#process_flag_message_queue_data"><c>process_flag(message_queue_data,
- MQD)</c></seealso>.
- </p></item>
- </taglist>
- </item>
<tag><c><![CDATA[+zFlag Value]]></c></tag>
<item>
<p>Miscellaneous flags.</p>
diff --git a/erts/doc/src/erl_dist_protocol.xml b/erts/doc/src/erl_dist_protocol.xml
index b435d5c9b4..f9fa981d9a 100644
--- a/erts/doc/src/erl_dist_protocol.xml
+++ b/erts/doc/src/erl_dist_protocol.xml
@@ -364,14 +364,14 @@ If Result > 0, the packet only consists of [119, Result].
NodeInfo is, as expressed in Erlang:
</p>
<code>
- io:format("active name ~ts at port ~p, fd = ~p ~n",
+ io:format("active name ~ts at port ~p, fd = ~p~n",
[NodeName, Port, Fd]).
</code>
<p>
or
</p>
<code>
- io:format("old/unused name ~ts at port ~p, fd = ~p~n",
+ io:format("old/unused name ~ts at port ~p, fd = ~p ~n",
[NodeName, Port, Fd]).
</code>
diff --git a/erts/doc/src/erl_driver.xml b/erts/doc/src/erl_driver.xml
index 241d4131d5..175b7f6bfb 100644
--- a/erts/doc/src/erl_driver.xml
+++ b/erts/doc/src/erl_driver.xml
@@ -4,7 +4,7 @@
<cref>
<header>
<copyright>
- <year>2001</year><year>2015</year>
+ <year>2001</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml
index be0e406b9c..7546f7ef81 100644
--- a/erts/doc/src/erl_nif.xml
+++ b/erts/doc/src/erl_nif.xml
@@ -4,7 +4,7 @@
<cref>
<header>
<copyright>
- <year>2001</year><year>2015</year>
+ <year>2001</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -524,6 +524,18 @@ typedef struct {
<p>Note that <c>ErlNifBinary</c> is a semi-opaque type and you are
only allowed to read fields <c>size</c> and <c>data</c>.</p>
</item>
+
+ <tag><marker id="ErlNifBinaryToTerm"/>ErlNifBinaryToTerm</tag>
+ <item>
+ <p>An enumeration of the options that can be given to
+ <seealso marker="#enif_binary_to_term">enif_binary_to_term</seealso>.
+ For default behavior, use the value <c>0</c>.</p>
+ <taglist>
+ <tag><c>ERL_NIF_BIN2TERM_SAFE</c></tag>
+ <item><p>Use this option when receiving data from untrusted sources.</p></item>
+ </taglist>
+ </item>
+
<tag><marker id="ErlNifPid"/>ErlNifPid</tag>
<item>
<p><c>ErlNifPid</c> is a process identifier (pid). In contrast to
@@ -532,6 +544,14 @@ typedef struct {
<seealso marker="#ErlNifEnv">environment</seealso>. <c>ErlNifPid</c>
is an opaque type.</p>
</item>
+ <tag><marker id="ErlNifPort"/>ErlNifPort</tag>
+ <item>
+ <p><c>ErlNifPort</c> is a port identifier. In contrast to
+ port id terms (instances of <c>ERL_NIF_TERM</c>), <c>ErlNifPort</c>'s are self
+ contained and not bound to any
+ <seealso marker="#ErlNifEnv">environment</seealso>. <c>ErlNifPort</c>
+ is an opaque type.</p>
+ </item>
<tag><marker id="ErlNifResourceType"/>ErlNifResourceType</tag>
<item>
@@ -546,8 +566,7 @@ typedef struct {
<code type="none">
typedef void ErlNifResourceDtor(ErlNifEnv* env, void* obj);
</code>
- <p>The function prototype of a resource destructor function.
- A destructor function is not allowed to call any term-making functions.</p>
+ <p>The function prototype of a resource destructor function.</p>
</item>
<tag><marker id="ErlNifCharEncoding"/>ErlNifCharEncoding</tag>
<item>
@@ -591,6 +610,21 @@ typedef enum {
</taglist>
</item>
+ <tag><marker id="ErlNifUniqueInteger"/>ErlNifUniqueInteger</tag>
+ <item>
+ <p>An enumeration of the properties that can be requested from
+ <seealso marker="#enif_make_unique_integer">enif_unique_integer</seealso>.
+ For default properties, use the value <c>0</c>.</p>
+ <taglist>
+ <tag><c>ERL_NIF_UNIQUE_POSITIVE</c></tag>
+ <item><p>Return only positive integers</p></item>
+ <tag><c>ERL_NIF_UNIQUE_MONOTONIC</c></tag>
+ <item><p>Return only
+ <seealso marker="time_correction#Strictly_Monotonically_Increasing">strictly
+ monotonically increasing</seealso> integer corresponding to creation time</p></item>
+ </taglist>
+ </item>
+
</taglist>
</section>
@@ -632,6 +666,25 @@ typedef enum {
have been allocated with <seealso marker="#enif_alloc_env">enif_alloc_env</seealso>.
</p></desc>
</func>
+ <func><name><ret>size_t</ret><nametext>enif_binary_to_term(ErlNifEnv *env, const unsigned char* data, size_t size, ERL_NIF_TERM *term, ErlNifBinaryToTerm opts)</nametext></name>
+ <fsummary>Create a term from the external format</fsummary>
+ <desc>
+ <p>Create a term that is the result of decoding the binary data
+ at <c>data</c>, which must be encoded according to the Erlang external term format.
+ No more than <c>size</c> bytes are read from <c>data</c>. Argument <c>opts</c>
+ correspond to the second argument to <seealso marker="erlang#binary_to_term-2">
+ <c>erlang:binary_to_term/2</c></seealso>, and must be either <c>0</c> or
+ <c>ERL_NIF_BIN2TERM_SAFE</c>.</p>
+ <p>On success, store the resulting term at <c>*term</c> and return
+ the actual number of bytes read. Return zero if decoding fails or if <c>opts</c>
+ is invalid.</p>
+ <p>See also:
+ <seealso marker="#ErlNifBinaryToTerm"><c>ErlNifBinaryToTerm</c></seealso>,
+ <seealso marker="erlang#binary_to_term-2"><c>erlang:binary_to_term/2</c></seealso> and
+ <seealso marker="#enif_term_to_binary"><c>enif_term_to_binary</c></seealso>.
+ </p>
+ </desc>
+ </func>
<func><name><ret>int</ret><nametext>enif_compare(ERL_NIF_TERM lhs, ERL_NIF_TERM rhs)</nametext></name>
<fsummary>Compare two terms</fsummary>
<desc><p>Return an integer less than, equal to, or greater than
@@ -689,7 +742,48 @@ typedef enum {
a number of repeated NIF-calls without the need to create threads.
See also the <seealso marker="#WARNING">warning</seealso> text at the beginning of this document.</p>
</desc>
+
</func>
+
+ <func>
+ <name><ret>ErlNifTime</ret><nametext>enif_convert_time_unit(ErlNifTime val, ErlNifTimeUnit from, ErlNifTimeUnit to)</nametext></name>
+ <fsummary>Convert time unit of a time value</fsummary>
+ <desc>
+ <marker id="enif_convert_time_unit"></marker>
+ <p>Arguments:</p>
+ <taglist>
+ <tag><c>val</c></tag>
+ <item>Value to convert time unit for.</item>
+ <tag><c>from</c></tag>
+ <item>Time unit of <c>val</c>.</item>
+ <tag><c>to</c></tag>
+ <item>Time unit of returned value.</item>
+ </taglist>
+ <p>Converts the <c>val</c> value of time unit <c>from</c> to
+ the corresponding value of time unit <c>to</c>. The result is
+ rounded using the floor function.</p>
+ <p>Returns <c>ERL_NIF_TIME_ERROR</c> if called with an invalid
+ time unit argument.</p>
+ <p>See also:
+ <seealso marker="#ErlNifTime"><c>ErlNifTime</c></seealso> and
+ <seealso marker="#ErlNifTimeUnit"><c>ErlNifTimeUnit</c></seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name><ret>ERL_NIF_TERM</ret><nametext>enif_cpu_time(ErlNifEnv *)</nametext></name>
+ <fsummary></fsummary>
+ <desc>
+ <p>Returns the CPU time in the same format as <seealso marker="erlang#timestamp-0">erlang:timestamp()</seealso>.
+ The CPU time is the time the current logical cpu has spent executing since
+ some arbitrary point in the past.
+ If the OS does not support fetching of this value <c>enif_cpu_time</c>
+ invokes <seealso marker="#enif_make_badarg">enif_make_badarg</seealso>.
+ </p>
+ </desc>
+ </func>
+
<func><name><ret>int</ret><nametext>enif_equal_tids(ErlNifTid tid1, ErlNifTid tid2)</nametext></name>
<fsummary></fsummary>
<desc><p>Same as <seealso marker="erl_driver#erl_drv_equal_tids">erl_drv_equal_tids</seealso>.
@@ -744,6 +838,12 @@ typedef enum {
pid variable <c>*pid</c> from it and return true. Otherwise return false.
No check if the process is alive is done.</p></desc>
</func>
+ <func><name><ret>int</ret><nametext>enif_get_local_port(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifPort* port_id)</nametext></name>
+ <fsummary>Read an local port term</fsummary>
+ <desc><p>If <c>term</c> identifies a node local port, initialize the
+ port variable <c>*port_id</c> from it and return true. Otherwise return false.
+ No check if the port is alive is done.</p></desc>
+ </func>
<func><name><ret>int</ret><nametext>enif_get_list_cell(ErlNifEnv* env, ERL_NIF_TERM list, ERL_NIF_TERM* head, ERL_NIF_TERM* tail)</nametext></name>
<fsummary>Get head and tail from a list</fsummary>
<desc><p>Set <c>*head</c> and <c>*tail</c> from
@@ -912,6 +1012,17 @@ typedef enum {
<fsummary>Determine if a term is a port</fsummary>
<desc><p>Return true if <c>term</c> is a port.</p></desc>
</func>
+ <func><name><ret>int</ret><nametext>enif_is_port_alive(ErlNifEnv* env, ErlNifPort *port_id)</nametext></name>
+ <fsummary>Determine if a local port is alive or not.</fsummary>
+ <desc><p>Return true if <c>port_id</c> is currently alive.</p>
+ <p>This function can only be used in a from a NIF-calling thread.</p></desc>
+ </func>
+ <func><name><ret>int</ret><nametext>enif_is_process_alive(ErlNifEnv* env, ErlNifPid *pid)</nametext></name>
+ <fsummary>Determine if a local process is alive or not.</fsummary>
+ <desc><p>Return true if <c>pid</c> is currently alive.</p>
+ <p>This function is only thread-safe when the emulator with SMP support is used.
+ It can only be used in a non-SMP emulator from a NIF-calling thread.</p></desc>
+ </func>
<func><name><ret>int</ret><nametext>enif_is_ref(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name>
<fsummary>Determine if a term is a reference</fsummary>
<desc><p>Return true if <c>term</c> is a reference.</p></desc>
@@ -961,7 +1072,7 @@ typedef enum {
<seealso marker="#enif_is_exception">enif_is_exception</seealso>, but
not to any other NIF API function.</p>
<p>See also: <seealso marker="#enif_has_pending_exception">enif_has_pending_exception</seealso>
- and <seealso marker="#enif_raise_exception">enif_raise_exception</seealso>
+ and <seealso marker="#enif_raise_exception">enif_raise_exception</seealso>.
</p>
<note><p>In earlier versions (older than erts-7.0, OTP 18) the return value
from <c>enif_make_badarg</c> had to be returned from the NIF. This
@@ -1195,6 +1306,23 @@ typedef enum {
<fsummary>Create an unsigned integer term</fsummary>
<desc><p>Create an integer term from an unsigned 64-bit integer.</p></desc>
</func>
+ <func>
+ <name><ret>ERL_NIF_TERM</ret><nametext>enif_make_unique_integer(ErlNifEnv *env, ErlNifUniqueInteger properties)</nametext></name>
+ <fsummary></fsummary>
+ <desc>
+ <p>Returns a unique integer with the same properties as given by <seealso marker="erlang#unique_integer-1">erlang:unique_integer/1</seealso>.</p>
+ <p><c>env</c> is the environment to create the integer in.</p>
+ <p>
+ <c>ERL_NIF_UNIQUE_POSITIVE</c> and <c>ERL_NIF_UNIQUE_MONOTONIC</c> can
+ be passed as the second argument to change the properties of the
+ integer returned. It is possible to combine them by or:ing the
+ two values together.
+ </p>
+ <p>See also:
+ <seealso marker="#ErlNifUniqueInteger"><c>ErlNifUniqueInteger</c></seealso>.
+ </p>
+ </desc>
+ </func>
<func><name><ret>ERL_NIF_TERM</ret><nametext>enif_make_ulong(ErlNifEnv* env, unsigned long i)</nametext></name>
<fsummary>Create an integer term from an unsigned long int</fsummary>
<desc><p>Create an integer term from an <c>unsigned long int</c>.</p></desc>
@@ -1265,6 +1393,33 @@ enif_map_iterator_destroy(env, &amp;iter);
or false if the iterator is positioned at the head (before the first
entry).</p></desc>
</func>
+
+ <func>
+ <name><ret>ErlNifTime</ret><nametext>enif_monotonic_time(ErlNifTimeUnit time_unit)</nametext></name>
+ <fsummary>Get Erlang Monotonic Time</fsummary>
+ <desc>
+ <marker id="enif_monotonic_time"></marker>
+ <p>Arguments:</p>
+ <taglist>
+ <tag><c>time_unit</c></tag>
+ <item>Time unit of returned value.</item>
+ </taglist>
+ <p>
+ Returns the current
+ <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang
+ monotonic time</seealso>. Note that it is not uncommon with
+ negative values.
+ </p>
+ <p>Returns <c>ERL_NIF_TIME_ERROR</c> if called with an invalid
+ time unit argument, or if called from a thread that is not a
+ scheduler thread.</p>
+ <p>See also:
+ <seealso marker="#ErlNifTime"><c>ErlNifTime</c></seealso> and
+ <seealso marker="#ErlNifTimeUnit"><c>ErlNifTimeUnit</c></seealso>.
+ </p>
+ </desc>
+ </func>
+
<func><name><ret>ErlNifMutex *</ret><nametext>enif_mutex_create(char *name)</nametext></name>
<fsummary></fsummary>
<desc><p>Same as <seealso marker="erl_driver#erl_drv_mutex_create">erl_drv_mutex_create</seealso>.
@@ -1290,6 +1445,11 @@ enif_map_iterator_destroy(env, &amp;iter);
<desc><p>Same as <seealso marker="erl_driver#erl_drv_mutex_unlock">erl_drv_mutex_unlock</seealso>.
</p></desc>
</func>
+ <func><name><ret>ERL_NIF_TERM</ret><nametext>enif_now_time(ErlNifEnv *env)</nametext></name>
+ <fsummary></fsummary>
+ <desc><p>Retuns an <seealso marker="erlang#now-0">erlang:now()</seealso> timestamp.
+ The enif_now_time function is <em>deprecated</em>.</p></desc>
+ </func>
<func><name><ret>ErlNifResourceType *</ret><nametext>enif_open_resource_type(ErlNifEnv* env,
const char* module_str, const char* name,
ErlNifResourceDtor* dtor, ErlNifResourceFlags flags, ErlNifResourceFlags* tried)</nametext></name>
@@ -1319,6 +1479,35 @@ enif_map_iterator_destroy(env, &amp;iter);
and <seealso marker="#upgrade">upgrade</seealso>.</p>
</desc>
</func>
+ <func><name><ret>int</ret><nametext>enif_port_command(ErlNifEnv* env, const ErlNifPort* to_port, ErlNifEnv *msg_env, ERL_NIF_TERM msg)</nametext></name>
+ <fsummary>Send a port_command to to_port</fsummary>
+ <desc>
+ <p>This function works the same as <seealso marker="erlang#port_command-2">erlang:port_command/2</seealso>
+ except that it is always completely asynchronous. This call may return false
+ if it detects that the port is already dead, otherwise it will return true.
+ </p>
+ <taglist>
+ <tag><c>env</c></tag>
+ <item>The environment of the calling process. May not be NULL.</item>
+ <tag><c>*to_port</c></tag>
+ <item>The port id of the receiving port. The port id should refer to a
+ port on the local node.</item>
+ <tag><c>msg_env</c></tag>
+ <item>The environment of the message term. Can be a process
+ independent environment allocated with
+ <seealso marker="#enif_alloc_env">enif_alloc_env</seealso> or NULL.</item>
+ <tag><c>msg</c></tag>
+ <item>The message term to send. The same limitations apply as on the
+ payload to <seealso marker="erlang#port_command-2">erlang:port_command/2</seealso>.</item>
+ </taglist>
+ <p>Using a <c>msg_env</c> of NULL is an optimization which groups together
+ calls to <c>enif_alloc_env</c>, <c>enif_make_copy</c>, <c>enif_port_command</c>
+ and <c>enif_free_env</c> into one call. This optimization is only usefull
+ when a majority of the terms are to be copied from <c>env</c> to the <c>msg_env</c>.</p>
+ <p>The call may return false if it detects that the command failed for some reason. Otherwise true is returned.</p>
+ <p>See also: <seealso marker="#enif_get_local_port"><c>enif_get_local_port</c></seealso>.</p>
+ </desc>
+ </func>
<func><name><ret>void *</ret><nametext>enif_priv_data(ErlNifEnv* env)</nametext></name>
<fsummary>Get the private data of a NIF library</fsummary>
<desc><p>Return the pointer to the private data that was set by <c>load</c>,
@@ -1442,7 +1631,7 @@ enif_map_iterator_destroy(env, &amp;iter);
<tag><c>msg_env</c></tag>
<item>The environment of the message term. Must be a process
independent environment allocated with
- <seealso marker="#enif_alloc_env">enif_alloc_env</seealso>.</item>
+ <seealso marker="#enif_alloc_env">enif_alloc_env</seealso> or NULL.</item>
<tag><c>msg</c></tag>
<item>The message term to send.</item>
</taglist>
@@ -1451,8 +1640,12 @@ enif_map_iterator_destroy(env, &amp;iter);
<c>msg</c>) will be invalidated by a successful call to <c>enif_send</c>. The environment
should either be freed with <seealso marker="#enif_free_env">enif_free_env</seealso>
of cleared for reuse with <seealso marker="#enif_clear_env">enif_clear_env</seealso>.</p>
+ <p>If <c>msg_env</c> is set to NULL the <c>msg</c> term is copied and
+ the original term and its environemt is still valid after the call.</p>
<p>This function is only thread-safe when the emulator with SMP support is used.
It can only be used in a non-SMP emulator from a NIF-calling thread.</p>
+ <note><p>Passing <c>msg_env</c> as <c>NULL</c> is only supported since
+ erts-8.0 (OTP 19).</p></note>
</desc>
</func>
<func><name><ret>unsigned</ret><nametext>enif_sizeof_resource(void* obj)</nametext></name>
@@ -1466,6 +1659,18 @@ enif_map_iterator_destroy(env, &amp;iter);
<desc><p>Same as <seealso marker="erl_driver#driver_system_info">driver_system_info</seealso>.
</p></desc>
</func>
+ <func><name><ret>int</ret><nametext>enif_term_to_binary(ErlNifEnv *env, ERL_NIF_TERM term, ErlNifBinary *bin)</nametext></name>
+ <fsummary>Convert a term to the external format</fsummary>
+ <desc>
+ <p>Allocates a new binary with <seealso marker="#enif_alloc_binary">enif_alloc_binary</seealso>
+ and stores the result of encoding <c>term</c> according to the Erlang external term format.</p>
+ <p>Returns true on success or false if allocation failed.</p>
+ <p>See also:
+ <seealso marker="erlang#term_to_binary-1"><c>erlang:term_to_binary/1</c></seealso> and
+ <seealso marker="#enif_binary_to_term"><c>enif_binary_to_term</c></seealso>.
+ </p>
+ </desc>
+ </func>
<func><name><ret>int</ret><nametext>enif_thread_create(char *name,ErlNifTid *tid,void * (*func)(void *),void *args,ErlNifThreadOpts *opts)</nametext></name>
<fsummary></fsummary>
<desc><p>Same as <seealso marker="erl_driver#erl_drv_thread_create">erl_drv_thread_create</seealso>.
@@ -1496,54 +1701,6 @@ enif_map_iterator_destroy(env, &amp;iter);
<desc><p>Same as <seealso marker="erl_driver#erl_drv_thread_self">erl_drv_thread_self</seealso>.
</p></desc>
</func>
- <func><name><ret>int</ret><nametext>enif_tsd_key_create(char *name, ErlNifTSDKey *key)</nametext></name>
- <fsummary></fsummary>
- <desc><p>Same as <seealso marker="erl_driver#erl_drv_tsd_key_create">erl_drv_tsd_key_create</seealso>.
- </p></desc>
- </func>
- <func><name><ret>void</ret><nametext>enif_tsd_key_destroy(ErlNifTSDKey key)</nametext></name>
- <fsummary></fsummary>
- <desc><p>Same as <seealso marker="erl_driver#erl_drv_tsd_key_destroy">erl_drv_tsd_key_destroy</seealso>.
- </p></desc>
- </func>
- <func><name><ret>void *</ret><nametext>enif_tsd_get(ErlNifTSDKey key)</nametext></name>
- <fsummary></fsummary>
- <desc><p>Same as <seealso marker="erl_driver#erl_drv_tsd_get">erl_drv_tsd_get</seealso>.
- </p></desc>
- </func>
- <func><name><ret>void</ret><nametext>enif_tsd_set(ErlNifTSDKey key, void *data)</nametext></name>
- <fsummary></fsummary>
- <desc><p>Same as <seealso marker="erl_driver#erl_drv_tsd_set">erl_drv_tsd_set</seealso>.
- </p></desc>
- </func>
-
-
- <func>
- <name><ret>ErlNifTime</ret><nametext>enif_monotonic_time(ErlNifTimeUnit time_unit)</nametext></name>
- <fsummary>Get Erlang Monotonic Time</fsummary>
- <desc>
- <marker id="enif_monotonic_time"></marker>
- <p>Arguments:</p>
- <taglist>
- <tag><c>time_unit</c></tag>
- <item>Time unit of returned value.</item>
- </taglist>
- <p>
- Returns
- <seealso marker="time_correction#Erlang_Monotonic_Time">Erlang
- monotonic time</seealso>. Note that it is not uncommon with
- negative values.
- </p>
- <p>Returns <c>ERL_NIF_TIME_ERROR</c> if called with an invalid
- time unit argument, or if called from a thread that is not a
- scheduler thread.</p>
- <p>See also:</p>
- <list>
- <item><seealso marker="#ErlNifTime"><c>ErlNifTime</c></seealso></item>
- <item><seealso marker="#ErlNifTimeUnit"><c>ErlNifTimeUnit</c></seealso></item>
- </list>
- </desc>
- </func>
<func>
<name><ret>ErlNifTime</ret><nametext>enif_time_offset(ErlNifTimeUnit time_unit)</nametext></name>
@@ -1563,41 +1720,33 @@ enif_map_iterator_destroy(env, &amp;iter);
<p>Returns <c>ERL_NIF_TIME_ERROR</c> if called with an invalid
time unit argument, or if called from a thread that is not a
scheduler thread.</p>
- <p>See also:</p>
- <list>
- <item><seealso marker="#ErlNifTime"><c>ErlNifTime</c></seealso></item>
- <item><seealso marker="#ErlNifTimeUnit"><c>ErlNifTimeUnit</c></seealso></item>
- </list>
+ <p>See also:
+ <seealso marker="#ErlNifTime"><c>ErlNifTime</c></seealso> and
+ <seealso marker="#ErlNifTimeUnit"><c>ErlNifTimeUnit</c></seealso>.
+ </p>
</desc>
</func>
- <func>
- <name><ret>ErlNifTime</ret><nametext>enif_convert_time_unit(ErlNifTime val, ErlNifTimeUnit from, ErlNifTimeUnit to)</nametext></name>
- <fsummary>Convert time unit of a time value</fsummary>
- <desc>
- <marker id="enif_convert_time_unit"></marker>
- <p>Arguments:</p>
- <taglist>
- <tag><c>val</c></tag>
- <item>Value to convert time unit for.</item>
- <tag><c>from</c></tag>
- <item>Time unit of <c>val</c>.</item>
- <tag><c>to</c></tag>
- <item>Time unit of returned value.</item>
- </taglist>
- <p>Converts the <c>val</c> value of time unit <c>from</c> to
- the corresponding value of time unit <c>to</c>. The result is
- rounded using the floor function.</p>
- <p>Returns <c>ERL_NIF_TIME_ERROR</c> if called with an invalid
- time unit argument.</p>
- <p>See also:</p>
- <list>
- <item><seealso marker="#ErlNifTime"><c>ErlNifTime</c></seealso></item>
- <item><seealso marker="#ErlNifTimeUnit"><c>ErlNifTimeUnit</c></seealso></item>
- </list>
- </desc>
+ <func><name><ret>int</ret><nametext>enif_tsd_key_create(char *name, ErlNifTSDKey *key)</nametext></name>
+ <fsummary></fsummary>
+ <desc><p>Same as <seealso marker="erl_driver#erl_drv_tsd_key_create">erl_drv_tsd_key_create</seealso>.
+ </p></desc>
+ </func>
+ <func><name><ret>void</ret><nametext>enif_tsd_key_destroy(ErlNifTSDKey key)</nametext></name>
+ <fsummary></fsummary>
+ <desc><p>Same as <seealso marker="erl_driver#erl_drv_tsd_key_destroy">erl_drv_tsd_key_destroy</seealso>.
+ </p></desc>
+ </func>
+ <func><name><ret>void *</ret><nametext>enif_tsd_get(ErlNifTSDKey key)</nametext></name>
+ <fsummary></fsummary>
+ <desc><p>Same as <seealso marker="erl_driver#erl_drv_tsd_get">erl_drv_tsd_get</seealso>.
+ </p></desc>
+ </func>
+ <func><name><ret>void</ret><nametext>enif_tsd_set(ErlNifTSDKey key, void *data)</nametext></name>
+ <fsummary></fsummary>
+ <desc><p>Same as <seealso marker="erl_driver#erl_drv_tsd_set">erl_drv_tsd_set</seealso>.
+ </p></desc>
</func>
-
</funcs>
<section>
<title>SEE ALSO</title>
diff --git a/erts/doc/src/erl_prim_loader.xml b/erts/doc/src/erl_prim_loader.xml
index 8f66e07ae1..d3ece37cc5 100644
--- a/erts/doc/src/erl_prim_loader.xml
+++ b/erts/doc/src/erl_prim_loader.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2013</year>
+ <year>1996</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/erl_tracer.xml b/erts/doc/src/erl_tracer.xml
new file mode 100644
index 0000000000..2075b962d8
--- /dev/null
+++ b/erts/doc/src/erl_tracer.xml
@@ -0,0 +1,668 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2016</year><year>2016</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>erl_tracer</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ </header>
+ <module>erl_tracer</module>
+ <modulesummary>Erlang Tracer Behaviour</modulesummary>
+ <description>
+ <p>A behaviour module for implementing the back end of the erlang
+ tracing system. The functions in this module will be called whenever
+ a trace probe is triggered. Both the <c>enabled</c> and <c>trace</c>
+ functions are called in the context of the entity that triggered the
+ trace probe.
+ This means that the overhead by having the tracing enabled will be
+ greatly effected by how much time is spent in these functions. So do as
+ little work as possible in these functions.</p>
+ <note>
+ <p>All functions in this behaviour have to be implemented as NIF's.
+ This is a limitation that may the lifted in the future.
+ There is an <seealso marker="#example">example tracer module nif</seealso>
+ implementation at the end of this page.</p>
+ </note>
+ <warning>
+ <p>Do not send messages or issue port commands to the <c>Tracee</c>
+ in any of the callbacks. Doing so is not allowed and can cause all
+ sorts of strange behaviour, including but not limited to infinite
+ recursions.</p>
+ </warning>
+ </description>
+
+ <datatypes>
+ <datatype> <name name="trace_tag_send" /> </datatype>
+ <datatype> <name name="trace_tag_receive" /> </datatype>
+ <datatype> <name name="trace_tag_call" /> </datatype>
+ <datatype> <name name="trace_tag_procs" /> </datatype>
+ <datatype> <name name="trace_tag_ports" /> </datatype>
+ <datatype> <name name="trace_tag_running_procs" /> </datatype>
+ <datatype> <name name="trace_tag_running_ports" /> </datatype>
+ <datatype> <name name="trace_tag_gc" /> </datatype>
+ <datatype>
+ <name name="trace_tag" />
+ <desc>
+ <p>The different trace tags that the tracer will be called with.
+ Each trace tag is described in greater detail in
+ <seealso marker="#trace">Module:trace/6</seealso>
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="tracee" />
+ <desc>
+ <p>The process or port that the trace belongs to.
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="trace_opts" />
+ <desc>
+ <p>The options for the tracee.
+ <taglist>
+ <tag><c>timestamp</c></tag>
+ <item>If not set to <c>undefined</c>, the tracer has been requested to
+ include a timestamp.</item>
+ <tag><c>match_spec_result</c></tag>
+ <item>If not set to <c>true</c>, the tracer has been requested to
+ include the output of a match specification that was run.</item>
+ <tag><c>scheduler_id</c></tag>
+ <item>Set to a number of the scheduler id is to be included by the tracer.
+ Otherwise it is set to <c>undefined</c>.</item>
+ </taglist>
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="tracer_state" />
+ <desc>
+ <p>
+ The state which is given when calling
+ <seealso marker="erlang#trace-3"><c>erlang:trace(PidPortSpec,true,[{tracer,Module,TracerState}])</c></seealso>.
+ The tracer state is an immutable value that is passed to erl_tracer callbacks and should
+ contain all the data that is needed to generate the trace event.
+ </p>
+ </desc>
+ </datatype>
+ </datatypes>
+
+ <section>
+ <title>CALLBACK FUNCTIONS</title>
+ <p>The following functions
+ should be exported from a <c>erl_tracer</c> callback module.</p>
+ <taglist>
+ <tag><seealso marker="#enabled"><c>Module:enabled/3</c></seealso></tag>
+ <item>Mandatory</item>
+ <tag><seealso marker="#trace"><c>Module:trace/6</c></seealso></tag>
+ <item>Mandatory</item>
+ <tag><seealso marker="#enabled_procs"><c>Module:enabled_procs/3</c></seealso></tag>
+ <item>Optional</item>
+ <tag><seealso marker="#trace_procs"><c>Module:trace_procs/6</c></seealso></tag>
+ <item>Optional</item>
+ <tag><seealso marker="#enabled_ports"><c>Module:enabled_ports/3</c></seealso></tag>
+ <item>Optional</item>
+ <tag><seealso marker="#trace_ports"><c>Module:trace_ports/6</c></seealso></tag>
+ <item>Optional</item>
+ <tag><seealso marker="#enabled_running_ports"><c>Module:enabled_running_ports/3</c></seealso></tag>
+ <item>Optional</item>
+ <tag><seealso marker="#trace_running_ports"><c>Module:trace_running_ports/6</c></seealso></tag>
+ <item>Optional</item>
+ <tag><seealso marker="#enabled_running_procs"><c>Module:enabled_running_procs/3</c></seealso></tag>
+ <item>Optional</item>
+ <tag><seealso marker="#trace_running_procs"><c>Module:trace_running_procs/6</c></seealso></tag>
+ <item>Optional</item>
+ </taglist>
+
+ </section>
+ <marker id="enabled"></marker>
+ <funcs>
+ <func>
+ <name>Module:enabled(TraceTag, TracerState, Tracee) -> Result</name>
+ <fsummary>Check if a trace event should be generated.</fsummary>
+ <type>
+ <v>TraceTag = <seealso marker="#type-trace_tag">trace_tag()</seealso> | trace_status</v>
+ <v>TracerState = term()</v>
+ <v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
+ <v>Result = trace | discard | remove</v>
+ </type>
+ <desc>
+ <p>This callback will be called whenever a tracepoint is triggered. It
+ allows the tracer to decide whether a trace should be generated or not.
+ This check is made as early as possible in order to limit the amount of
+ overhead associated with tracing. If <c>trace</c> is returned the
+ necessary trace data will be created and the trace call-back of the tracer
+ will be called. If <c>discard</c> is returned, this trace call
+ will be discarded and no call to trace will be done. If
+ <c>remove</c> is returned, the VM will attempt to remove this tracer
+ from the tracee, together with any trace flags set on the tracee.
+ </p>
+ <p><c>trace_status</c> is a special type of <c>TraceTag</c> which is used
+ to check if the tracer should still be active. It is called in multiple
+ scenarios, but most significantly it is used when tracing is started
+ using this tracer.</p>
+ <p>This function may be called multiple times per tracepoint, so it
+ is important that it is both fast and side effect free.</p>
+ </desc>
+ </func>
+ <marker id="trace"></marker>
+ <func>
+ <name>Module:trace(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
+ <fsummary>Check if a trace event should be generated.</fsummary>
+ <type>
+ <v>TraceTag = <seealso marker="#type-trace_tag">trace_tag()</seealso></v>
+ <v>TracerState = term()</v>
+ <v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
+ <v>FirstTraceTerm = term()</v>
+ <v>SecondTraceTerm = term() | undefined</v>
+ <v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
+ <v>Result = ok</v>
+ </type>
+ <desc>
+ <p>This callback will be called when a tracepoint is triggered and
+ the <seealso marker="#enabled">Module:enabled/3</seealso>
+ callback returned <c>trace</c>. In it any side effects needed by
+ the tracer should be done. The tracepoint payload is located in
+ the <c>FirstTraceTerm</c> and <c>SecondTraceTerm</c>. The content
+ of the TraceTerms depends on which <c>TraceTag</c> has been triggered.
+ The <c>FirstTraceTerm</c> and <c>SecondTraceTerm</c> correspond to the
+ fourth and fifth slot in the trace tuples described in
+ <seealso marker="erlang#trace_3_trace_messages">erlang:trace/3</seealso>.
+ If the tuple only has four elements, <c>SecondTraceTerm</c> will be
+ <c>undefined</c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="trace">Module:trace(seq_trace, TracerState, Label, SeqTraceInfo, undefined, Opts) -> Result</name>
+ <fsummary>Check if a sequence trace event should be generated.</fsummary>
+ <type>
+ <v>TracerState = term()</v>
+ <v>Label = term()</v>
+ <v>SeqTraceInfo = term()</v>
+ <v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
+ <v>Result = ok</v>
+ </type>
+ <desc>
+ <p>The <c>TraceTag</c> <c>seq_trace</c> is handled a little bit
+ differently. There is not <c>Tracee</c> for seq_trace, instead the
+ <c>Label</c> associated with the seq_trace event is given.
+ For more info on what <c>Label</c> and <c>SeqTraceInfo</c> can be
+ see the <seealso marker="kernel:seq_trace">seq_trace</seealso> manual.</p>
+ </desc>
+ </func>
+
+ <marker id="enabled_procs"></marker>
+ <func>
+ <name>Module:enabled_procs(TraceTag, TracerState, Tracee) -> Result</name>
+ <fsummary>Check if a trace event should be generated.</fsummary>
+ <type>
+ <v>TraceTag = <seealso marker="#type-trace_tag_procs">trace_tag_procs()</seealso></v>
+ <v>TracerState = term()</v>
+ <v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
+ <v>Result = trace | discard | remove</v>
+ </type>
+ <desc>
+ <p>This callback will be called whenever a tracepoint with trace flag
+ <seealso marker="erlang#trace-3"><c>procs</c></seealso>
+ is triggered.</p>
+ <p>If <c>enabled_procs/3</c> is not defined <c>enabled/3</c> will be called instead.</p>
+ </desc>
+ </func>
+
+ <marker id="trace_procs"></marker>
+ <func>
+ <name>Module:trace_procs(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
+ <fsummary>Check if a trace event should be generated.</fsummary>
+ <type>
+ <v>TraceTag = <seealso marker="#type-trace_tag_procs">trace_tag()</seealso></v>
+ <v>TracerState = term()</v>
+ <v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
+ <v>FirstTraceTerm = term()</v>
+ <v>SecondTraceTerm = term() | undefined</v>
+ <v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
+ <v>Result = ok</v>
+ </type>
+ <desc>
+ <p>This callback will be called when a tracepoint is triggered and
+ the <seealso marker="#enabled_procs">Module:enabled_procs/3</seealso>
+ callback returned <c>trace</c>.</p>
+ <p>If <c>trace_procs/6</c> is not defined <c>trace/6</c> will be called instead.</p>
+ </desc>
+ </func>
+
+ <marker id="enabled_ports"></marker>
+ <func>
+ <name>Module:enabled_ports(TraceTag, TracerState, Tracee) -> Result</name>
+ <fsummary>Check if a trace event should be generated.</fsummary>
+ <type>
+ <v>TraceTag = <seealso marker="#type-trace_tag_ports">trace_tag_ports()</seealso></v>
+ <v>TracerState = term()</v>
+ <v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
+ <v>Result = trace | discard | remove</v>
+ </type>
+ <desc>
+ <p>This callback will be called whenever a tracepoint with trace flag
+ <seealso marker="erlang#trace-3"><c>ports</c></seealso>
+ is triggered.</p>
+ <p>If <c>enabled_ports/3</c> is not defined <c>enabled/3</c> will be called instead.</p>
+ </desc>
+ </func>
+
+ <marker id="trace_ports"></marker>
+ <func>
+ <name>Module:trace_ports(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
+ <fsummary>Check if a trace event should be generated.</fsummary>
+ <type>
+ <v>TraceTag = <seealso marker="#type-trace_tag_ports">trace_tag()</seealso></v>
+ <v>TracerState = term()</v>
+ <v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
+ <v>FirstTraceTerm = term()</v>
+ <v>SecondTraceTerm = term() | undefined</v>
+ <v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
+ <v>Result = ok</v>
+ </type>
+ <desc>
+ <p>This callback will be called when a tracepoint is triggered and
+ the <seealso marker="#enabled_ports">Module:enabled_ports/3</seealso>
+ callback returned <c>trace</c>.</p>
+ <p>If <c>trace_ports/6</c> is not defined <c>trace/6</c> will be called instead.</p>
+ </desc>
+ </func>
+
+ <marker id="enabled_running_procs"></marker>
+ <func>
+ <name>Module:enabled_running_procs(TraceTag, TracerState, Tracee) -> Result</name>
+ <fsummary>Check if a trace event should be generated.</fsummary>
+ <type>
+ <v>TraceTag = <seealso marker="#type-trace_tag_running_procs">trace_tag_running_procs()</seealso></v>
+ <v>TracerState = term()</v>
+ <v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
+ <v>Result = trace | discard | remove</v>
+ </type>
+ <desc>
+ <p>This callback will be called whenever a tracepoint with trace flag
+ <seealso marker="erlang#trace-3"><c>running_procs | running</c></seealso>
+ is triggered.</p>
+ <p>If <c>enabled_running_procs/3</c> is not defined <c>enabled/3</c> will be called instead.</p>
+ </desc>
+ </func>
+
+ <marker id="trace_running_procs"></marker>
+ <func>
+ <name>Module:trace_running_procs(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
+ <fsummary>Check if a trace event should be generated.</fsummary>
+ <type>
+ <v>TraceTag = <seealso marker="#type-trace_tag_running_procs">trace_tag_running_procs()</seealso></v>
+ <v>TracerState = term()</v>
+ <v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
+ <v>FirstTraceTerm = term()</v>
+ <v>SecondTraceTerm = term() | undefined</v>
+ <v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
+ <v>Result = ok</v>
+ </type>
+ <desc>
+ <p>This callback will be called when a tracepoint is triggered and
+ the <seealso marker="#enabled_running_procs">Module:enabled_running_procs/3</seealso>
+ callback returned <c>trace</c>.</p>
+ <p>If <c>trace_running_procs/6</c> is not defined <c>trace/6</c> will be called instead.</p>
+ </desc>
+ </func>
+
+ <marker id="enabled_running_ports"></marker>
+ <func>
+ <name>Module:enabled_running_ports(TraceTag, TracerState, Tracee) -> Result</name>
+ <fsummary>Check if a trace event should be generated.</fsummary>
+ <type>
+ <v>TraceTag = <seealso marker="#type-trace_tag_running_ports">trace_tag_running_ports()</seealso></v>
+ <v>TracerState = term()</v>
+ <v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
+ <v>Result = trace | discard | remove</v>
+ </type>
+ <desc>
+ <p>This callback will be called whenever a tracepoint with trace flag
+ <seealso marker="erlang#trace-3"><c>running_ports</c></seealso>
+ is triggered.</p>
+ <p>If <c>enabled_running_ports/3</c> is not defined <c>enabled/3</c> will be called instead.</p>
+ </desc>
+ </func>
+
+ <marker id="trace_running_ports"></marker>
+ <func>
+ <name>Module:trace_running_ports(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
+ <fsummary>Check if a trace event should be generated.</fsummary>
+ <type>
+ <v>TraceTag = <seealso marker="#type-trace_tag_running_ports">trace_tag_running_ports()</seealso></v>
+ <v>TracerState = term()</v>
+ <v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
+ <v>FirstTraceTerm = term()</v>
+ <v>SecondTraceTerm = term() | undefined</v>
+ <v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
+ <v>Result = ok</v>
+ </type>
+ <desc>
+ <p>This callback will be called when a tracepoint is triggered and
+ the <seealso marker="#enabled_running_ports">Module:enabled_running_ports/3</seealso>
+ callback returned <c>trace</c>.</p>
+ <p>If <c>trace_running_ports/6</c> is not defined <c>trace/6</c> will be called instead.</p>
+ </desc>
+ </func>
+
+ <marker id="enabled_call"></marker>
+ <func>
+ <name>Module:enabled_call(TraceTag, TracerState, Tracee) -> Result</name>
+ <fsummary>Check if a trace event should be generated.</fsummary>
+ <type>
+ <v>TraceTag = <seealso marker="#type-trace_tag_call">trace_tag_call()</seealso></v>
+ <v>TracerState = term()</v>
+ <v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
+ <v>Result = trace | discard | remove</v>
+ </type>
+ <desc>
+ <p>This callback will be called whenever a tracepoint with trace flag
+ <seealso marker="erlang#trace-3"><c>call | return_to</c></seealso>
+ is triggered.</p>
+ <p>If <c>enabled_call/3</c> is not defined <c>enabled/3</c> will be called instead.</p>
+ </desc>
+ </func>
+
+ <marker id="trace_call"></marker>
+ <func>
+ <name>Module:trace_call(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
+ <fsummary>Check if a trace event should be generated.</fsummary>
+ <type>
+ <v>TraceTag = <seealso marker="#type-trace_tag_call">trace_tag_call()</seealso></v>
+ <v>TracerState = term()</v>
+ <v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
+ <v>FirstTraceTerm = term()</v>
+ <v>SecondTraceTerm = term() | undefined</v>
+ <v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
+ <v>Result = ok</v>
+ </type>
+ <desc>
+ <p>This callback will be called when a tracepoint is triggered and
+ the <seealso marker="#enabled_call">Module:enabled_call/3</seealso>
+ callback returned <c>trace</c>.</p>
+ <p>If <c>trace_call/6</c> is not defined <c>trace/6</c> will be called instead.</p>
+ </desc>
+ </func>
+
+ <marker id="enabled_send"></marker>
+ <func>
+ <name>Module:enabled_send(TraceTag, TracerState, Tracee) -> Result</name>
+ <fsummary>Check if a trace event should be generated.</fsummary>
+ <type>
+ <v>TraceTag = <seealso marker="#type-trace_tag_send">trace_tag_send()</seealso></v>
+ <v>TracerState = term()</v>
+ <v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
+ <v>Result = trace | discard | remove</v>
+ </type>
+ <desc>
+ <p>This callback will be called whenever a tracepoint with trace flag
+ <seealso marker="erlang#trace-3"><c>send</c></seealso>
+ is triggered.</p>
+ <p>If <c>enabled_send/3</c> is not defined <c>enabled/3</c> will be called instead.</p>
+ </desc>
+ </func>
+
+ <marker id="trace_send"></marker>
+ <func>
+ <name>Module:trace_send(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
+ <fsummary>Check if a trace event should be generated.</fsummary>
+ <type>
+ <v>TraceTag = <seealso marker="#type-trace_tag_send">trace_tag_send()</seealso></v>
+ <v>TracerState = term()</v>
+ <v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
+ <v>FirstTraceTerm = term()</v>
+ <v>SecondTraceTerm = term() | undefined</v>
+ <v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
+ <v>Result = ok</v>
+ </type>
+ <desc>
+ <p>This callback will be called when a tracepoint is triggered and
+ the <seealso marker="#enabled_send">Module:enabled_send/3</seealso>
+ callback returned <c>trace</c>.</p>
+ <p>If <c>trace_send/6</c> is not defined <c>trace/6</c> will be called instead.</p>
+ </desc>
+ </func>
+
+ <marker id="enabled_receive"></marker>
+ <func>
+ <name>Module:enabled_receive(TraceTag, TracerState, Tracee) -> Result</name>
+ <fsummary>Check if a trace event should be generated.</fsummary>
+ <type>
+ <v>TraceTag = <seealso marker="#type-trace_tag_receive">trace_tag_receive()</seealso></v>
+ <v>TracerState = term()</v>
+ <v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
+ <v>Result = trace | discard | remove</v>
+ </type>
+ <desc>
+ <p>This callback will be called whenever a tracepoint with trace flag
+ <seealso marker="erlang#trace-3"><c>'receive'</c></seealso>
+ is triggered.</p>
+ <p>If <c>enabled_receive/3</c> is not defined <c>enabled/3</c> will be called instead.</p>
+ </desc>
+ </func>
+
+ <marker id="trace_receive"></marker>
+ <func>
+ <name>Module:trace_receive(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
+ <fsummary>Check if a trace event should be generated.</fsummary>
+ <type>
+ <v>TraceTag = <seealso marker="#type-trace_tag_receive">trace_tag_receive()</seealso></v>
+ <v>TracerState = term()</v>
+ <v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
+ <v>FirstTraceTerm = term()</v>
+ <v>SecondTraceTerm = term() | undefined</v>
+ <v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
+ <v>Result = ok</v>
+ </type>
+ <desc>
+ <p>This callback will be called when a tracepoint is triggered and
+ the <seealso marker="#enabled_receive">Module:enabled_receive/3</seealso>
+ callback returned <c>trace</c>.</p>
+ <p>If <c>trace_receive/6</c> is not defined <c>trace/6</c> will be called instead.</p>
+ </desc>
+ </func>
+
+ <marker id="enabled_garbage_collection"></marker>
+ <func>
+ <name>Module:enabled_garbage_collection(TraceTag, TracerState, Tracee) -> Result</name>
+ <fsummary>Check if a trace event should be generated.</fsummary>
+ <type>
+ <v>TraceTag = <seealso marker="#type-trace_tag_gc">trace_tag_gc()</seealso></v>
+ <v>TracerState = term()</v>
+ <v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
+ <v>Result = trace | discard | remove</v>
+ </type>
+ <desc>
+ <p>This callback will be called whenever a tracepoint with trace flag
+ <seealso marker="erlang#trace-3"><c>garbage_collection</c></seealso>
+ is triggered.</p>
+ <p>If <c>enabled_garbage_collection/3</c> is not defined <c>enabled/3</c> will be called instead.</p>
+ </desc>
+ </func>
+
+ <marker id="trace_garbage_collection"></marker>
+ <func>
+ <name>Module:trace_garbage_collection(TraceTag, TracerState, Tracee, FirstTraceTerm, SecondTraceTerm, Opts) -> Result</name>
+ <fsummary>Check if a trace event should be generated.</fsummary>
+ <type>
+ <v>TraceTag = <seealso marker="#type-trace_tag_gc">trace_tag_gc()</seealso></v>
+ <v>TracerState = term()</v>
+ <v>Tracee = <seealso marker="#type-tracee">tracee()</seealso></v>
+ <v>FirstTraceTerm = term()</v>
+ <v>SecondTraceTerm = term() | undefined</v>
+ <v>Opts = <seealso marker="#type-trace_opts">trace_opts()</seealso></v>
+ <v>Result = ok</v>
+ </type>
+ <desc>
+ <p>This callback will be called when a tracepoint is triggered and
+ the <seealso marker="#enabled_garbage_collection">Module:enabled_garbage_collection/3</seealso>
+ callback returned <c>trace</c>.</p>
+ <p>If <c>trace_garbage_collection/6</c> is not defined <c>trace/6</c> will be called instead.</p>
+ </desc>
+ </func>
+
+ </funcs>
+ <section>
+ <marker id="example"></marker>
+ <title>Erl Tracer Module example</title>
+ <p>In the example below a tracer module with a nif backend sends a message
+ for each <c>send</c> trace tag containing only the sender and receiver.
+ Using this tracer module, a much more lightweight message tracer is
+ used that only records who sent messages to who.</p>
+ <p>Here is an example session using it on Linux.</p>
+ <pre>
+$ gcc -I erts-8.0/include/ -fPIC -shared -o erl_msg_tracer.so erl_msg_tracer.c
+$ erl
+Erlang/OTP 19 [DEVELOPMENT] [erts-8.0] [source-ed2b56b] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false]
+
+Eshell V8.0 (abort with ^G)
+1&gt; c(erl_msg_tracer), erl_msg_tracer:load().
+ok
+2&gt; Tracer = spawn(fun F() -&gt; receive M -&gt; io:format("~p~n",[M]), F() end end).
+&lt;0.37.0&gt;
+3&gt; erlang:trace(new, true, [send,{tracer, erl_msg_tracer, Tracer}]).
+0
+{&lt;0.39.0&gt;,&lt;0.27.0&gt;}
+4&gt; {ok, D} = file:open("/tmp/tmp.data",[write]).
+{trace,#Port&lt;0.486&gt;,&lt;0.40.0&gt;}
+{trace,&lt;0.40.0&gt;,&lt;0.21.0&gt;}
+{trace,#Port&lt;0.487&gt;,&lt;0.4.0&gt;}
+{trace,#Port&lt;0.488&gt;,&lt;0.4.0&gt;}
+{trace,#Port&lt;0.489&gt;,&lt;0.4.0&gt;}
+{trace,#Port&lt;0.490&gt;,&lt;0.4.0&gt;}
+{ok,&lt;0.40.0&gt;}
+{trace,&lt;0.41.0&gt;,&lt;0.27.0&gt;}
+5&gt;
+ </pre>
+ <p>erl_msg_tracer.erl</p>
+ <pre>
+-module(erl_msg_tracer).
+
+-export([enabled/3, trace/6, load/0]).
+
+load() ->
+ erlang:load_nif("erl_msg_tracer", []).
+
+enabled(_, _, _) ->
+ error.
+
+trace(_, _, _,_, _, _) ->
+ error.
+ </pre>
+ <p>erl_msg_tracer.c</p>
+ <pre>
+#include "erl_nif.h"
+
+/* NIF interface declarations */
+static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info);
+static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info);
+static void unload(ErlNifEnv* env, void* priv_data);
+
+/* The NIFs: */
+static ERL_NIF_TERM enabled(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+static ErlNifFunc nif_funcs[] = {
+ {"enabled", 3, enabled},
+ {"trace", 6, trace}
+};
+
+ERL_NIF_INIT(erl_msg_tracer, nif_funcs, load, NULL, upgrade, unload)
+
+static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
+{
+ *priv_data = NULL;
+ return 0;
+}
+
+static void unload(ErlNifEnv* env, void* priv_data)
+{
+
+}
+
+static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data,
+ ERL_NIF_TERM load_info)
+{
+ if (*old_priv_data != NULL || *priv_data != NULL) {
+ return -1; /* Don't know how to do that */
+ }
+ if (load(env, priv_data, load_info)) {
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * argv[0]: Trace Tag
+ * argv[1]: TracerState
+ * argv[2]: Tracee
+ */
+static ERL_NIF_TERM enabled(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifPid to_pid;
+ if (enif_get_local_pid(env, argv[1], &amp;to_pid))
+ if (!enif_is_process_alive(env, &amp;to_pid))
+ /* tracer is dead so we should remove this tracepoint */
+ return enif_make_atom(env, "remove");
+
+ /* Only generate trace for when tracer != tracee */
+ if (enif_is_identical(argv[1], argv[2]))
+ return enif_make_atom(env, "discard");
+
+ /* Only trigger trace messages on 'send' */
+ if (enif_is_identical(enif_make_atom(env, "send"), argv[0]))
+ return enif_make_atom(env, "trace");
+
+ /* Have to answer trace_status */
+ if (enif_is_identical(enif_make_atom(env, "trace_status"), argv[0]))
+ return enif_make_atom(env, "trace");
+
+ return enif_make_atom(env, "discard");
+}
+
+/*
+ * argv[0]: Trace Tag, should only be 'send'
+ * argv[1]: TracerState, process to send {argv[2], argv[4]} to
+ * argv[2]: Tracee
+ * argv[3]: Message, ignored
+ * argv[4]: Recipient
+ * argv[5]: Options, ignored
+ */
+static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifPid to_pid;
+
+ if (enif_get_local_pid(env, argv[1], &amp;to_pid)) {
+ ERL_NIF_TERM msg = enif_make_tuple3(env, enif_make_atom(env, "trace"), argv[2], argv[4]);
+ enif_send(env, &amp;to_pid, NULL, msg);
+ }
+
+ return enif_make_atom(env, "ok");
+}
+ </pre>
+ </section>
+</erlref>
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 350a8506f5..bf30cc7928 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2015</year>
+ <year>1996</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -2613,6 +2613,48 @@ os_prompt% </pre>
</func>
<func>
+ <name name="match_spec_test" arity="3"/>
+ <fsummary>Test that a match specification works</fsummary>
+ <desc>
+ <p>
+ This function is a utility to test a match_spec used in calls to
+ <seealso marker="stdlib:ets#select/2">ets:select/2</seealso> and
+ <seealso marker="#trace_pattern/3">erlang:trace_pattern/3</seealso>.
+ The function both tests MatchSpec for "syntactic" correctness and
+ runs the match_spec against the object. If the match_spec contains
+ errors, the tuple {error, Errors} is returned where Errors is a list
+ of natural language descriptions of what was wrong with the match_spec.
+ </p>
+ <p>
+ If the <c><anno>Type</anno></c> is <c>table</c> the object to match
+ against should be a tuple. The function then returns
+ {ok,Result,[],Warnings} where Result is what would have been the
+ result in a real ets:select/2 call or false if the match_spec does
+ not match the object tuple.
+ </p>
+
+ <p>
+ If <c><anno>Type</anno></c> is <c>trace</c> the object to match
+ against should be a list. The function returns
+ {ok, Result, Flags, Warnings} where Result is <c>true</c> if a trace
+ message should be emitted, <c>false</c> if a trace message should not
+ be emitted or the message term to be appended to the trace message.
+ Flags is a list containing all the trace flags that will be enabled,
+ at the moment this is only <c>return_trace</c>.
+ </p>
+
+ <p>
+ This is a useful debugging and test tool, especially when writing complicated
+ match specifications.
+ </p>
+ <p>
+ See also
+ <seealso marker="stdlib:ets#test_ms/2">ets:test_ms/2</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
<name name="max" arity="2"/>
<fsummary>Returns the largest of two terms.</fsummary>
<desc>
@@ -4329,7 +4371,7 @@ os_prompt% </pre>
</taglist>
<p>
The default <c>message_queue_data</c> process flag is determined
- by the <seealso marker="erl#+xmqd"><c>+xmqd</c></seealso>
+ by the <seealso marker="erl#+hmqd"><c>+hmqd</c></seealso>
<c>erl</c> command line argument.
</p>
<p>
@@ -4660,7 +4702,7 @@ os_prompt% </pre>
detailed information about garbage collection for this process.
The content of <c><anno>GCInfo</anno></c> can be changed without
prior notice.
- See <seealso marker="#gc_start">gc_start</seealso> in
+ See <seealso marker="#gc_minor_start">gc_minor_start</seealso> in
<seealso marker="#trace/3">erlang:trace/3</seealso> for details about
what each item means.
</p>
@@ -4836,7 +4878,9 @@ os_prompt% </pre>
<tag><c>{total_heap_size, <anno>Size</anno>}</c></tag>
<item>
<p><c><anno>Size</anno></c> is the total size, in words, of all heap
- fragments of the process. This includes the process stack.</p>
+ fragments of the process. This includes the process stack and
+ any unreceived messages that are considered to be part of the
+ heap. </p>
</item>
<tag><c>{trace, <anno>InternalTraceFlags</anno>}</c></tag>
<item>
@@ -5667,7 +5711,7 @@ true</pre>
flag. <c><anno>MQD</anno></c> should be either <c>off_heap</c>,
<c>on_heap</c>, or <c>mixed</c>. The default
<c>message_queue_data</c> process flag is determined by the
- <seealso marker="erl#+xmqd"><c>+xmqd</c></seealso> <c>erl</c>
+ <seealso marker="erl#+hmqd"><c>+hmqd</c></seealso> <c>erl</c>
command line argument. For more information, see the
documentation of
<seealso marker="#process_flag_message_queue_data"><c>process_flag(message_queue_data,
@@ -6797,11 +6841,7 @@ ok
As from <c>ERTS</c> 5.6.1, the return value is a list
of <c>{instance, InstanceNo, InstanceInfo}</c> tuples,
where <c>InstanceInfo</c> contains information about
- a specific instance of the allocator. As from
- <c>ERTS</c> 5.10.4, the returned list when calling
- <c>erlang:system_info({allocator, mseg_alloc})</c> also
- includes an <c>{erts_mmap, _}</c> tuple as one element
- in the list. If <c><anno>Alloc</anno></c> is not a
+ a specific instance of the allocator. If <c><anno>Alloc</anno></c> is not a
recognized allocator, <c>undefined</c> is returned.
If <c><anno>Alloc</anno></c> is disabled,
<c>false</c> is returned.</p>
@@ -6813,7 +6853,13 @@ ok
briefly documented.</p>
<p>The recognized allocators are listed in
<seealso marker="erts:erts_alloc">erts_alloc(3)</seealso>.
- After reading the <c>erts_alloc(3)</c> documentation,
+ Information about super carriers can be obtained from
+ <c>ERTS</c> 8.0 with <c>{allocator, erts_mmap}</c> or from
+ <c>ERTS</c> 5.10.4, the returned list when calling with
+ <c>{allocator, mseg_alloc}</c> also includes an
+ <c>{erts_mmap, _}</c> tuple as one element in the list.</p>
+
+ <p>After reading the <c>erts_alloc(3)</c> documentation,
the returned information
more or less speaks for itself, but it can be worth
explaining some things. Call counts are presented by two
@@ -7346,7 +7392,7 @@ ok
<p>Returns the default value of the <c>message_queue_data</c>
process flag which is either <c>off_heap</c>, <c>on_heap</c>, or <c>mixed</c>.
This default is set by the <c>erl</c> command line argument
- <seealso marker="erl#+xmqd"><c>+xmqd</c></seealso>. For more information on the
+ <seealso marker="erl#+hmqd"><c>+hmqd</c></seealso>. For more information on the
<c>message_queue_data</c> process flag, see documentation of
<seealso marker="#process_flag_message_queue_data"><c>process_flag(message_queue_data,
MQD)</c></seealso>.</p>
@@ -7924,7 +7970,7 @@ ok
<c>stack_size</c>, <c>mbuf_size</c>, <c>old_heap_size</c>,
and <c>old_heap_block_size</c>. These tuples are
explained in the description of trace message
- <seealso marker="#gc_start">gc_start</seealso> (see
+ <seealso marker="#gc_minor_start">gc_minor_start</seealso> (see
<seealso marker="#trace/3">erlang:trace/3</seealso>).
New tuples can be added, and the order of the tuples in
the <c>Info</c> list can be changed at any time without
@@ -8347,22 +8393,47 @@ timestamp() ->
<c><anno>How</anno> == false</c>) the trace flags in
<c><anno>FlagList</anno></c> for
the process or processes represented by
- <c><anno>PidSpec</anno></c>.</p>
- <p><c><anno>PidSpec</anno></c> is either a process identifier
- (pid) for a local process, or one of the following atoms:</p>
+ <c><anno>PidPortSpec</anno></c>.</p>
+ <p><c><anno>PidPortSpec</anno></c> is either a process identifier
+ (pid) for a local process, a port identifier,
+ or one of the following atoms:</p>
<taglist>
+ <tag><c>all</c></tag>
+ <item>
+ <p>All currently existing processes and ports and all that
+ will be created in the future.</p>
+ </item>
+ <tag><c>processes</c></tag>
+ <item>
+ <p>All currently existing processes and all that will be created in the future.</p>
+ </item>
+ <tag><c>ports</c></tag>
+ <item>
+ <p>All currently existing ports and all that will be created in the future.</p>
+ </item>
<tag><c>existing</c></tag>
<item>
+ <p>All currently existing processes and ports.</p>
+ </item>
+ <tag><c>existing_processes</c></tag>
+ <item>
<p>All currently existing processes.</p>
</item>
+ <tag><c>existing_ports</c></tag>
+ <item>
+ <p>All currently existing ports.</p>
+ </item>
<tag><c>new</c></tag>
<item>
- <p>All processes that are created in the future.</p>
+ <p>All processes and ports that will be created in the future.</p>
</item>
- <tag><c>all</c></tag>
+ <tag><c>new_processes</c></tag>
+ <item>
+ <p>All processes that will be created in the future.</p>
+ </item>
+ <tag><c>new_ports</c></tag>
<item>
- <p>All currently existing processes and all processes that
- are created in the future.</p>
+ <p>All ports that will be created in the future.</p>
</item>
</taglist>
<p><c><anno>FlagList</anno></c> can contain any number of the
@@ -8371,35 +8442,28 @@ timestamp() ->
<taglist>
<tag><c>all</c></tag>
<item>
- <p>Sets all trace flags except <c>{tracer, Tracer}</c> and
+ <p>Sets all trace flags except <c>tracer</c> and
<c>cpu_timestamp</c>, which are in their nature different
than the others.</p>
</item>
<tag><c>send</c></tag>
<item>
<p>Traces sending of messages.</p>
- <p>Message tags: <c>send</c> and
- <c>send_to_non_existing_process</c>.</p>
+ <p>Message tags: <c><seealso marker="#trace_3_trace_messages_send">send</seealso></c> and
+ <c><seealso marker="#trace_3_trace_messages_send_to_non_existing_process">send_to_non_existing_process</seealso></c>.</p>
</item>
<tag><c>'receive'</c></tag>
<item>
<p>Traces receiving of messages.</p>
- <p>Message tags: <c>'receive'</c>.</p>
+ <p>Message tags: <c><seealso marker="#trace_3_trace_messages_receive">'receive'</seealso></c>.</p>
</item>
- <tag><c>procs</c></tag>
- <item>
- <p>Traces process-related events.</p>
- <p>Message tags: <c>spawn</c>, <c>exit</c>,
- <c>register</c>, <c>unregister</c>, <c>link</c>,
- <c>unlink</c>, <c>getting_linked</c>, and
- <c>getting_unlinked</c>.</p>
- </item>
- <tag><c>call</c></tag>
+<tag><c>call</c></tag>
<item>
<p>Traces certain function calls. Specify which function
calls to trace by calling
<seealso marker="#trace_pattern/3">erlang:trace_pattern/3</seealso>.</p>
- <p>Message tags: <c>call</c> and <c>return_from</c>.</p>
+ <p>Message tags: <c><seealso marker="#trace_3_trace_messages_call">call</seealso></c> and
+ <c><seealso marker="#trace_3_trace_messages_return_from">return_from</seealso></c>.</p>
</item>
<tag><c>silent</c></tag>
<item>
@@ -8417,8 +8481,9 @@ timestamp() ->
specification function <c>{silent,Bool}</c>, giving
a high degree of control of which functions with which
arguments that trigger the trace.</p>
- <p>Message tags: <c>call</c>, <c>return_from</c>, and
- <c>return_to</c>. Or rather, the absence of.</p>
+ <p>Message tags: <c><seealso marker="#trace_3_trace_messages_call">call</seealso></c>,
+ <c><seealso marker="#trace_3_trace_messages_return_from">return_from</seealso></c>, and
+ <c><seealso marker="#trace_3_trace_messages_return_to">return_to</seealso></c>. Or rather, the absence of.</p>
</item>
<tag><c>return_to</c></tag>
<item>
@@ -8439,23 +8504,63 @@ timestamp() ->
<p>To get trace messages containing return values from
functions, use the <c>{return_trace}</c> match
specification action instead.</p>
- <p>Message tags: <c>return_to</c>.</p>
+ <p>Message tags: <c><seealso marker="#trace_3_trace_messages_return_to">return_to</seealso></c>.</p>
+ </item>
+ <tag><c>procs</c></tag>
+ <item>
+ <p>Traces process-related events.</p>
+ <p>Message tags: <c><seealso marker="#trace_3_trace_messages_spawn">spawn</seealso></c>,
+ <c><seealso marker="#trace_3_trace_messages_spawned">spawned</seealso></c>,
+ <c><seealso marker="#trace_3_trace_messages_exit">exit</seealso></c>,
+ <c><seealso marker="#trace_3_trace_messages_register">register</seealso></c>,
+ <c><seealso marker="#trace_3_trace_messages_unregister">unregister</seealso></c>,
+ <c><seealso marker="#trace_3_trace_messages_link">link</seealso></c>,
+ <c><seealso marker="#trace_3_trace_messages_unlink">unlink</seealso></c>,
+ <c><seealso marker="#trace_3_trace_messages_getting_linked">getting_linked</seealso></c>, and
+ <c><seealso marker="#trace_3_trace_messages_getting_unlinked">getting_unlinked</seealso></c>.</p>
+ </item>
+ <tag><c>ports</c></tag>
+ <item>
+ <p>Traces port-related events.</p>
+ <p>Message tags: <c><seealso marker="#trace_3_trace_messages_open">open</seealso></c>,
+ <c><seealso marker="#trace_3_trace_messages_closed">closed</seealso></c>,
+ <c><seealso marker="#trace_3_trace_messages_register">register</seealso></c>,
+ <c><seealso marker="#trace_3_trace_messages_unregister">unregister</seealso></c>,
+ <c><seealso marker="#trace_3_trace_messages_getting_linked">getting_linked</seealso></c>, and
+ <c><seealso marker="#trace_3_trace_messages_getting_unlinked">getting_unlinked</seealso></c>.</p>
</item>
<tag><c>running</c></tag>
<item>
<p>Traces scheduling of processes.</p>
- <p>Message tags: <c>in</c> and <c>out</c>.</p>
+ <p>Message tags: <c><seealso marker="#trace_3_trace_messages_in_proc">in</seealso></c> and
+ <c><seealso marker="#trace_3_trace_messages_out_proc">out</seealso></c>.</p>
</item>
<tag><c>exiting</c></tag>
<item>
<p>Traces scheduling of exiting processes.</p>
- <p>Message tags: <c>in_exiting</c>, <c>out_exiting</c>, and
- <c>out_exited</c>.</p>
+ <p>Message tags: <c><seealso marker="#trace_3_trace_messages_in_exiting_proc">in_exiting</seealso></c>,
+ <c><seealso marker="#trace_3_trace_messages_out_exiting_proc">out_exiting</seealso></c>, and
+ <c><seealso marker="#trace_3_trace_messages_out_exited_proc">out_exited</seealso></c>.</p>
+ </item>
+ <tag><c>running_procs</c></tag>
+ <item>
+ <p>Traces scheduling of processes just like <c>running</c>.
+ However this option also includes schedule events when the
+ process executes within the context of a port without
+ being scheduled out itself.</p>
+ <p>Message tags: <c><seealso marker="#trace_3_trace_messages_in_proc">in</seealso></c> and
+ <c><seealso marker="#trace_3_trace_messages_out_proc">out</seealso></c>.</p>
+ </item>
+ <tag><c>running_ports</c></tag>
+ <item>
+ <p>Traces scheduling of ports.</p>
+ <p>Message tags: <c><seealso marker="#trace_3_trace_messages_in_port">in</seealso></c> and
+ <c><seealso marker="#trace_3_trace_messages_out_port">out</seealso></c>.</p>
</item>
<tag><c>garbage_collection</c></tag>
<item>
<p>Traces garbage collections of processes.</p>
- <p>Message tags: <c>gc_start</c> and <c>gc_end</c>.</p>
+ <p>Message tags: <c><seealso marker="#trace_3_trace_messages_gc_minor_start">gc_minor_start</seealso></c> and <c><seealso marker="#trace_3_trace_messages_gc_minor_end">gc_minor_end</seealso></c>.</p>
</item>
<tag><c>timestamp</c></tag>
<item>
@@ -8470,8 +8575,8 @@ timestamp() ->
in CPU time, not wall clock time. That is, <c>cpu_timestamp</c>
will not be used if <c>monotonic_timestamp</c>, or
<c>strict_monotonic_timestamp</c> is enabled.
- Only allowed with <c>PidSpec==all</c>. If the host
- machine OS does not support high-resolution
+ Only allowed with <c><anno>PidPortSpec</anno>==all</c>. If the
+ host machine OS does not support high-resolution
CPU time measurements, <c>trace/3</c> exits with
<c>badarg</c>. Notice that most OS do
not synchronize this value across cores, so be prepared
@@ -8483,8 +8588,8 @@ timestamp() ->
<seealso marker="time_correction#Erlang_Monotonic_Time">Erlang
monotonic time</seealso> time-stamp in all trace messages. The
time-stamp (Ts) has the same format and value as produced by
- <c>erlang:monotonic_time(nano_seconds)</c>. This flag overrides
- the <c>cpu_timestamp</c> flag.</p>
+ <c><seealso marker="#monotonic_time-1">erlang:monotonic_time(nano_seconds)</seealso></c>.
+ This flag overrides the <c>cpu_timestamp</c> flag.</p>
</item>
<tag><c>strict_monotonic_timestamp</c></tag>
<item>
@@ -8493,9 +8598,9 @@ timestamp() ->
monotonic time</seealso> and a monotonically increasing
integer in all trace messages. The time-stamp (Ts) has the
same format and value as produced by
- <c>{erlang:monotonic_time(nano_seconds),
- erlang:unique_integer([monotonic])}</c>. This flag overrides
- the <c>cpu_timestamp</c> flag.</p>
+ <c>{<seealso marker="#monotonic_time-1">erlang:monotonic_time(nano_seconds)</seealso>,
+ <seealso marker="#unique_integer-1">erlang:unique_integer([monotonic])</seealso>}</c>.
+ This flag overrides the <c>cpu_timestamp</c> flag.</p>
</item>
<tag><c>arity</c></tag>
<item>
@@ -8529,12 +8634,20 @@ timestamp() ->
<item>
<p>Specifies where to send the trace messages. <c>Tracer</c>
must be the process identifier of a local process
- or the port identifier
- of a local port. If this flag is not given, trace
- messages are sent to the process that called
- <c>erlang:trace/3</c>.</p>
+ or the port identifier of a local port.</p>
+ </item>
+ <tag><c>{tracer, TracerModule, TracerState}</c></tag>
+ <item>
+ <p>Specifies that a tracer module should be called
+ instead of sending a trace message. The tracer module
+ can then ignore or change the trace message. For more details
+ on how to write a tracer module see
+ <seealso marker="erts:erl_tracer"><c>erl_tracer</c></seealso>
+ </p>
</item>
</taglist>
+ <p>If no <c>tracer</c> is given, the calling process
+ will be receiving all of the trace messages</p>
<p>The effect of combining <c>set_on_first_link</c> with
<c>set_on_link</c> is the same as having
<c>set_on_first_link</c> alone. Likewise for
@@ -8555,21 +8668,36 @@ timestamp() ->
the other one will become active.</p>
<marker id="trace_3_trace_messages"></marker>
<taglist>
- <tag><c>{trace, Pid, 'receive', Msg}</c></tag>
- <item>
- <p>When <c>Pid</c> receives message <c>Msg</c>.</p>
- </item>
- <tag><c>{trace, Pid, send, Msg, To}</c></tag>
+ <tag>
+ <marker id="trace_3_trace_messages_send"></marker>
+ <c>{trace, PidPort, send, Msg, To}</c>
+ </tag>
<item>
- <p>When <c>Pid</c> sends message <c>Msg</c> to
+ <p>When <c>PidPort</c> sends message <c>Msg</c> to
process <c>To</c>.</p>
</item>
- <tag><c>{trace, Pid, send_to_non_existing_process, Msg, To}</c></tag>
+ <tag>
+ <marker id="trace_3_trace_messages_send_to_non_existing_process"></marker>
+ <c>{trace, PidPort, send_to_non_existing_process, Msg, To}</c>
+ </tag>
<item>
- <p>When <c>Pid</c> sends message <c>Msg</c> to
+ <p>When <c>PidPort</c> sends message <c>Msg</c> to
the non-existing process <c>To</c>.</p>
</item>
- <tag><c>{trace, Pid, call, {M, F, Args}}</c></tag>
+ <tag>
+ <marker id="trace_3_trace_messages_receive"></marker>
+ <c>{trace, PidPort, 'receive', Msg}</c>
+ </tag>
+ <item>
+ <p>When <c>PidPort</c> receives message <c>Msg</c>.
+ If <c>Msg</c> is set to timeout, then a receive
+ statement may have timedout, or the process received
+ a message with the payload <c>timeout</c>.</p>
+ </item>
+ <tag>
+ <marker id="trace_3_trace_messages_call"></marker>
+ <c>{trace, Pid, call, {M, F, Args}}</c>
+ </tag>
<item>
<p>When <c>Pid</c> calls a traced function. The return
values of calls are never supplied, only the call and its
@@ -8578,7 +8706,10 @@ timestamp() ->
change the contents of this message, so that <c>Arity</c>
is specified instead of <c>Args</c>.</p>
</item>
- <tag><c>{trace, Pid, return_to, {M, F, Arity}}</c></tag>
+ <tag>
+ <marker id="trace_3_trace_messages_return_to"></marker>
+ <c>{trace, Pid, return_to, {M, F, Arity}}</c>
+ </tag>
<item>
<p>When <c>Pid</c> returns <em>to</em> the specified
function. This trace message is sent if both
@@ -8590,76 +8721,175 @@ timestamp() ->
(that is, the functions match specification matched, and
<c>{message, false}</c> was not an action).</p>
</item>
- <tag><c>{trace, Pid, return_from, {M, F, Arity}, ReturnValue}</c></tag>
+ <tag>
+ <marker id="trace_3_trace_messages_return_from"></marker>
+ <c>{trace, Pid, return_from, {M, F, Arity}, ReturnValue}</c>
+ </tag>
<item>
<p>When <c>Pid</c> returns <em>from</em> the specified
function. This trace message is sent if flag <c>call</c>
is set, and the function has a match specification
with a <c>return_trace</c> or <c>exception_trace</c> action.</p>
</item>
- <tag><c>{trace, Pid, exception_from, {M, F, Arity}, {Class, Value}}</c></tag>
+ <tag>
+ <marker id="trace_3_trace_messages_exception_from"></marker>
+ <c>{trace, Pid, exception_from, {M, F, Arity}, {Class, Value}}</c>
+ </tag>
<item>
<p>When <c>Pid</c> exits <em>from</em> the specified
function because of an exception. This trace message is
sent if flag <c>call</c> is set, and the function has
a match specification with an <c>exception_trace</c> action.</p>
</item>
- <tag><c>{trace, Pid, spawn, Pid2, {M, F, Args}}</c></tag>
+ <tag>
+ <marker id="trace_3_trace_messages_spawn"></marker>
+ <c>{trace, Pid, spawn, Pid2, {M, F, Args}}</c>
+ </tag>
<item>
<p>When <c>Pid</c> spawns a new process <c>Pid2</c> with
the specified function call as entry point.</p>
<p><c>Args</c> is supposed to be the argument list,
but can be any term if the spawn is erroneous.</p>
</item>
- <tag><c>{trace, Pid, exit, Reason}</c></tag>
+ <tag>
+ <marker id="trace_3_trace_messages_spawned"></marker>
+ <c>{trace, Pid, spawned, Pid2, {M, F, Args}}</c>
+ </tag>
+ <item>
+ <p>When <c>Pid</c> is spawned by process <c>Pid2</c> with
+ the specified function call as entry point.</p>
+ <p><c>Args</c> is supposed to be the argument list,
+ but can be any term if the spawn is erroneous.</p>
+ </item>
+ <tag>
+ <marker id="trace_3_trace_messages_exit"></marker>
+ <c>{trace, Pid, exit, Reason}</c>
+ </tag>
<item>
<p>When <c>Pid</c> exits with reason <c>Reason</c>.</p>
</item>
- <tag><c>{trace, Pid, link, Pid2}</c></tag>
+ <tag>
+ <marker id="trace_3_trace_messages_register"></marker>
+ <c>{trace, PidPort, register, RegName}</c>
+ </tag>
+ <item>
+ <p>When <c>PidPort</c> gets the name <c>RegName</c> registered.</p>
+ </item>
+ <tag>
+ <marker id="trace_3_trace_messages_unregister"></marker>
+ <c>{trace, PidPort, unregister, RegName}</c>
+ </tag>
+ <item>
+ <p>When <c>PidPort</c> gets the name <c>RegName</c> unregistered.
+ This is done automatically when a registered
+ process or port exits.</p>
+ </item>
+ <tag>
+ <marker id="trace_3_trace_messages_link"></marker>
+ <c>{trace, Pid, link, Pid2}</c>
+ </tag>
<item>
<p>When <c>Pid</c> links to a process <c>Pid2</c>.</p>
</item>
- <tag><c>{trace, Pid, unlink, Pid2}</c></tag>
+ <tag>
+ <marker id="trace_3_trace_messages_unlink"></marker>
+ <c>{trace, Pid, unlink, Pid2}</c>
+ </tag>
<item>
<p>When <c>Pid</c> removes the link from a process
<c>Pid2</c>.</p>
</item>
- <tag><c>{trace, Pid, getting_linked, Pid2}</c></tag>
+ <tag>
+ <marker id="trace_3_trace_messages_getting_linked"></marker>
+ <c>{trace, PidPort, getting_linked, Pid2}</c>
+ </tag>
+ <item>
+ <p>When <c>PidPort</c> gets linked to a process <c>Pid2</c>.</p>
+ </item>
+ <tag>
+ <marker id="trace_3_trace_messages_getting_unlinked"></marker>
+ <c>{trace, PidPort, getting_unlinked, Pid2}</c>
+ </tag>
<item>
- <p>When <c>Pid</c> gets linked to a process <c>Pid2</c>.</p>
+ <p>When <c>PidPort</c> gets unlinked from a process <c>Pid2</c>.</p>
</item>
- <tag><c>{trace, Pid, getting_unlinked, Pid2}</c></tag>
+ <tag>
+ <marker id="trace_3_trace_messages_exit"></marker>
+ <c>{trace, Pid, exit, Reason}</c>
+ </tag>
<item>
- <p>When <c>Pid</c> gets unlinked from a process <c>Pid2</c>.</p>
+ <p>When <c>Pid</c> exits with reason <c>Reason</c>.</p>
</item>
- <tag><c>{trace, Pid, register, RegName}</c></tag>
+ <tag>
+ <marker id="trace_3_trace_messages_open"></marker>
+ <c>{trace, Port, open, Pid, Driver}</c>
+ </tag>
<item>
- <p>When <c>Pid</c> gets the name <c>RegName</c> registered.</p>
+ <p>When <c>Pid</c> opens a new port <c>Port</c> with
+ the running the <c>Driver</c>.</p>
+ <p><c>Driver</c> is the name of the driver as an atom.</p>
</item>
- <tag><c>{trace, Pid, unregister, RegName}</c></tag>
+ <tag>
+ <marker id="trace_3_trace_messages_closed"></marker>
+ <c>{trace, Port, closed, Reason}</c>
+ </tag>
<item>
- <p>When <c>Pid</c> gets the name <c>RegName</c> unregistered.
- This is done automatically when a registered
- process exits.</p>
+ <p>When <c>Port</c> closed with <c>Reason</c>.</p>
</item>
- <tag><c>{trace, Pid, in, {M, F, Arity} | 0}</c></tag>
+ <tag>
+ <marker id="trace_3_trace_messages_in_proc"></marker>
+ <marker id="trace_3_trace_messages_in_exiting_proc"></marker>
+ <c>{trace, Pid, in | in_exiting, {M, F, Arity} | 0}</c>
+ </tag>
<item>
<p>When <c>Pid</c> is scheduled to run. The process
runs in function <c>{M, F, Arity}</c>. On some rare
occasions, the current function cannot be determined,
then the last element is <c>0</c>.</p>
</item>
- <tag><c>{trace, Pid, out, {M, F, Arity} | 0}</c></tag>
+ <tag>
+ <marker id="trace_3_trace_messages_out_proc"></marker>
+ <marker id="trace_3_trace_messages_out_exiting_proc"></marker>
+ <marker id="trace_3_trace_messages_out_exited_proc"></marker>
+ <c>{trace, Pid, out | out_exiting | out_exited, {M, F, Arity} | 0}</c>
+ </tag>
<item>
<p>When <c>Pid</c> is scheduled out. The process was
running in function {M, F, Arity}. On some rare occasions,
the current function cannot be determined, then the last
element is <c>0</c>.</p>
</item>
- <tag><c>{trace, Pid, gc_start, Info}</c></tag>
+ <tag>
+ <marker id="trace_3_trace_messages_in_port"></marker>
+ <c>{trace, Port, in, Command | 0}</c>
+ </tag>
+ <item>
+ <p>When <c>Port</c> is scheduled to run. <c>Command</c> is the
+ first thing the port will execute, it may however run several
+ commands before being scheduled out. On some rare
+ occasions, the current function cannot be determined,
+ then the last element is <c>0</c>.</p>
+ <p>The possible commands are: <c>call | close | command | connect | control | flush | info | link | open | unlink</c></p>
+ </item>
+ <tag>
+ <marker id="trace_3_trace_messages_out_port"></marker>
+ <c>{trace, Port, out, Command | 0}</c>
+ </tag>
+ <item>
+ <p>When <c>Port</c> is scheduled out. The last command run
+ was <c>Command</c>. On some rare occasions,
+ the current function cannot be determined, then the last
+ element is <c>0</c>. <c>Command</c> can contain the same
+ commands as <c>in</c>
+ </p>
+ </item>
+ <tag>
+ <marker id="trace_3_trace_messages_gc_minor_start"></marker>
+ <c>{trace, Pid, gc_minor_start, Info}</c>
+ </tag>
<item>
- <marker id="gc_start"></marker>
- <p>Sent when garbage collection is about to be started.
+ <marker id="gc_minor_start"></marker>
+ <p>Sent when a young garbage collection is about to be started.
<c>Info</c> is a list of two-element tuples, where
the first element is a key, and the second is the value.
Do not depend on any order of the tuples.
@@ -8698,26 +8928,46 @@ timestamp() ->
</taglist>
<p>All sizes are in words.</p>
</item>
- <tag><c>{trace, Pid, gc_end, Info}</c></tag>
+ <tag>
+ <marker id="trace_3_trace_messages_gc_minor_end"></marker>
+ <c>{trace, Pid, gc_minor_end, Info}</c>
+ </tag>
<item>
- <p>Sent when garbage collection is finished. <c>Info</c>
- contains the same kind of list as in message <c>gc_start</c>,
+ <p>Sent when young garbage collection is finished. <c>Info</c>
+ contains the same kind of list as in message <c>gc_minor_start</c>,
but the sizes reflect the new sizes after
garbage collection.</p>
</item>
+ <tag>
+ <marker id="trace_3_trace_messages_gc_major_start"></marker>
+ <c>{trace, Pid, gc_major_start, Info}</c>
+ </tag>
+ <item>
+ <p>Sent when fullsweep garbage collection is about to be started. <c>Info</c>
+ contains the same kind of list as in message <c>gc_minor_start</c>.</p>
+ </item>
+ <tag>
+ <marker id="trace_3_trace_messages_gc_major_end"></marker>
+ <c>{trace, Pid, gc_major_end, Info}</c>
+ </tag>
+ <item>
+ <p>Sent when fullsweep garbage collection is finished. <c>Info</c>
+ contains the same kind of list as in message <c>gc_minor_start</c>
+ but the sizes reflect the new sizes after a fullsweep garbage collection.</p>
+ </item>
</taglist>
- <p>If the tracing process dies, the flags are silently
- removed.</p>
- <p>Only one process can trace a particular process. Therefore,
+ <p>If the tracing process/port dies or the tracer module returns
+ <c>remove</c>, the flags are silently removed.</p>
+ <p>Each process can only be traced by one tracer. Therefore,
attempts to trace an already traced process fail.</p>
<p>Returns: A number indicating the number of processes that
- matched <c><anno>PidSpec</anno></c>.
- If <c><anno>PidSpec</anno></c> is a process
+ matched <c><anno>PidPortSpec</anno></c>.
+ If <c><anno>PidPortSpec</anno></c> is a process
identifier, the return value is <c>1</c>.
- If <c><anno>PidSpec</anno></c>
+ If <c><anno>PidPortSpec</anno></c>
is <c>all</c> or <c>existing</c>, the return value is
- the number of processes running, excluding tracer processes.
- If <c><anno>PidSpec</anno></c> is <c>new</c>, the return value is
+ the number of processes running.
+ If <c><anno>PidPortSpec</anno></c> is <c>new</c>, the return value is
<c>0</c>.</p>
<p>Failure: <c>badarg</c> if the specified arguments are
not supported. For example, <c>cpu_timestamp</c> is not
@@ -8729,7 +8979,11 @@ timestamp() ->
<name name="trace_delivered" arity="1"/>
<fsummary>Notification when trace has been delivered.</fsummary>
<desc>
- <p>The delivery of trace messages is dislocated on the time-line
+ <p>The delivery of trace messages (generated by
+ <seealso marker="#trace/3"><c>erlang:trace/3</c></seealso>,
+ <seealso marker="kernel:seq_trace"><c>seq_trace</c></seealso> or
+ <seealso marker="#system_profile/2"><c>erlang:system_profile/2</c></seealso>)
+ is dislocated on the time-line
compared to other events in the system. If you know that
<c><anno>Tracee</anno></c> has passed some specific point
in its execution,
@@ -8750,13 +9004,16 @@ timestamp() ->
has not been traced by someone, but if this is the case,
<em>no</em> trace messages have been delivered when the
<c>trace_delivered</c> message arrives.</p>
- <p>Notice that that <c><anno>Tracee</anno></c> must refer
+ <p>Notice that <c><anno>Tracee</anno></c> must refer
to a process currently,
or previously existing on the same node as the caller of
<c>erlang:trace_delivered(<anno>Tracee</anno>)</c> resides on.
The special <c><anno>Tracee</anno></c> atom <c>all</c>
- denotes all processes
- that currently are traced in the node.</p>
+ denotes all processes that currently are traced in the node.</p>
+ <p>When used together with an <seealso marker="erts:erl_tracer">
+ Tracer Module</seealso> any message sent in the trace callback
+ is guaranteed to have reached it's recipient before the
+ <c>trace_delivered</c> message is sent.</p>
<p>Example: Process <c>A</c> is <c><anno>Tracee</anno></c>,
port <c>B</c> is tracer, and process <c>C</c> is the port
owner of <c>B</c>. <c>C</c> wants to close <c>B</c> when
@@ -8779,13 +9036,16 @@ timestamp() ->
<type name="trace_info_flag"/>
<type name="trace_match_spec"/>
<desc>
- <p>Returns trace information about a process or function.</p>
- <p>To get information about a process,
- <c><anno>PidOrFunc</anno></c> is to
- be a process identifier (pid) or the atom <c>new</c>.
- The atom <c>new</c> means that the default trace state for
- processes to be created is returned.</p>
- <p>The following <c>Item</c>s are valid:</p>
+ <p>Returns trace information about a port, process, function or event.</p>
+ <p><em>To get information about a port or process</em>,
+ <c><anno>PidPortFuncEvent</anno></c> is to
+ be a process identifier (pid), port identifier or one of
+ the atoms <c>new</c>, <c>new_processes</c>, <c>new_ports</c>.
+ The atom <c>new</c> or <c>new_processes</c> means that the default trace
+ state for processes to be created is returned. The atom <c>new_ports</c>
+ means that the default trace state for ports to be created is returned.
+ </p>
+ <p>The following <c>Item</c>s are valid for ports and processes:</p>
<taglist>
<tag><c>flags</c></tag>
<item>
@@ -8794,24 +9054,30 @@ timestamp() ->
traces are enabled, and one or more of the followings
atoms if traces are enabled: <c>send</c>,
<c>'receive'</c>, <c>set_on_spawn</c>, <c>call</c>,
- <c>return_to</c>, <c>procs</c>, <c>set_on_first_spawn</c>,
- <c>set_on_link</c>, <c>running</c>,
+ <c>return_to</c>, <c>procs</c>, <c>ports</c>, <c>set_on_first_spawn</c>,
+ <c>set_on_link</c>, <c>running</c>, <c>running_procs</c>,
+ <c>running_ports</c>, <c>silent</c>, <c>exiting</c>
+ <c>monotonic_timestamp</c>, <c>strict_monotonic_timestamp</c>,
<c>garbage_collection</c>, <c>timestamp</c>, and
<c>arity</c>. The order is arbitrary.</p>
</item>
<tag><c>tracer</c></tag>
<item>
- <p>Returns the identifier for process or port tracing this
+ <p>Returns the identifier for process, port or a tuple containing
+ the tracer module and tracer state tracing this
process. If this process is not being traced, the return
value is <c>[]</c>.</p>
</item>
</taglist>
- <p>To get information about a function, <c>PidOrFunc</c> is to
+ <p><em>To get information about a function</em>, <c><anno>PidPortFuncEvent</anno></c> is to
be the three-element tuple <c>{Module, Function, Arity}</c> or
the atom <c>on_load</c>. No wild cards are allowed. Returns
<c>undefined</c> if the function does not exist, or
- <c>false</c> if the function is not traced.</p>
- <p>The following <c>Item</c>s are valid::</p>
+ <c>false</c> if the function is not traced. If <c><anno>PidPortFuncEvent</anno></c>
+ is <c>on_load</c>, the information returned refers to
+ the default value for code that will be loaded.</p>
+
+ <p>The following <c>Item</c>s are valid for functions:</p>
<taglist>
<tag><c>traced</c></tag>
<item>
@@ -8830,8 +9096,8 @@ timestamp() ->
</item>
<tag><c>meta</c></tag>
<item>
- <p>Returns the meta-trace tracer process or port for this
- function, if it has one. If the function is not
+ <p>Returns the meta-trace tracer process, port or trace module
+ for this function, if it has one. If the function is not
meta-traced, the returned value is <c>false</c>. If
the function is meta-traced but has once detected that
the tracer process is invalid, the returned value is [].</p>
@@ -8870,39 +9136,177 @@ timestamp() ->
is active for this function.</p>
</item>
</taglist>
+ <p><em>To get information about an event</em>, <c><anno>PidPortFuncEvent</anno></c> is to
+ be one of the atoms <c>send</c> or <c>'receive'</c>.</p>
+ <p>The only valid <c>Item</c> for events is:</p>
+ <taglist>
+ <tag><c>match_spec</c></tag>
+ <item>
+ <p>Returns the match specification for this event, if it
+ has one, or <c>true</c> if no match specification has been
+ set.</p>
+ </item>
+ </taglist>
<p>The return value is <c>{<anno>Item</anno>, Value}</c>, where
<c>Value</c> is the requested information as described earlier.
If a pid for a dead process was given, or the name of a
non-existing function, <c>Value</c> is <c>undefined</c>.</p>
- <p>If <c><anno>PidOrFunc</anno></c> is <c>on_load</c>, the information
- returned refers to the default value for code that will be
- loaded.</p>
</desc>
</func>
<func>
<name name="trace_pattern" arity="2" clause_i="1"/>
- <fsummary>Sets trace patterns for global call tracing.</fsummary>
+ <fsummary>Sets trace patterns for call, send or 'receive' tracing.</fsummary>
<type name="trace_pattern_mfa"/>
<type name="trace_match_spec"/>
<desc>
<p>The same as
- <seealso marker="#trace_pattern/3">erlang:trace_pattern(MFA, MatchSpec, [])</seealso>,
+ <seealso marker="#trace_pattern/3">erlang:trace_pattern(Event, MatchSpec, [])</seealso>,
retained for backward compatibility.</p>
</desc>
</func>
<func>
- <name name="trace_pattern" arity="3"/>
+ <name name="trace_pattern" arity="3" clause_i="1"/>
+ <fsummary>Sets trace pattern for message sending.</fsummary>
+ <type name="trace_match_spec"/>
+ <desc>
+ <p>Sets trace pattern for <em>message sending</em>.
+ Must be combined with
+ <seealso marker="#trace/3">erlang:trace/3</seealso>
+ to set the <c>send</c> trace flag for one or more processes.
+ By default all messages, sent from <c>send</c> traced processes,
+ are traced. Use <c>erlang:trace_pattern/3</c> to limit
+ traced send events based on the message content, the sender
+ and/or the receiver.</p>
+ <p>Argument <c><anno>MatchSpec</anno></c> can take the
+ following forms:</p>
+ <taglist>
+ <tag><c><anno>MatchSpecList</anno></c></tag>
+ <item>
+ <p>A list of match specifications. The matching is done
+ on the list <c>[Receiver, Msg]</c>. <c>Receiver</c>
+ is the process or port identity of the receiver and
+ <c>Msg</c> is the message term. The pid of the sending
+ process can be accessed with the guard function
+ <c>self/0</c>. An empty list is the same as <c>true</c>.
+ See the users guide section
+ <seealso marker="erts:match_spec">Match Specifications in Erlang</seealso>
+ for more information.</p>
+ </item>
+ <tag><c>true</c></tag>
+ <item>
+ <p>Enables tracing for all sent messages (from <c>send</c>
+ traced processes). Any match specification is
+ removed. <em>This is the default</em>.</p>
+ </item>
+ <tag><c>false</c></tag>
+ <item>
+ <p>Disables tracing for all sent messages.
+ Any match specification is removed.</p>
+ </item>
+ </taglist>
+ <p>Argument <c><anno>FlagList</anno></c> must be <c>[]</c>
+ for send tracing.</p>
+ <p>The return value is always <c>1</c>.</p>
+ <p>Example; only trace messages to a specific process <c>Pid</c>:</p>
+ <pre>
+> <input>erlang:trace_pattern(send, [{[Pid, '_'],[],[]}], []).</input>
+1</pre>
+ <p>Only trace messages matching <c>{reply, _}</c>:</p>
+ <pre>
+> <input>erlang:trace_pattern(send, [{['_', {reply,'_'}],[],[]}], []).</input>
+1</pre>
+ <p>Only trace messages sent to the sender itself:</p>
+ <pre>
+> <input>erlang:trace_pattern(send, [{['$1', '_'],[{'=:=','$1',{self}}],[]}], []).</input>
+1</pre>
+ <p>Only trace messages sent to other nodes:</p>
+ <pre>
+> <input>erlang:trace_pattern(send, [{['$1', '_'],[{'=/=',{node,'$1'},{node}}],[]}], []).</input>
+1</pre>
+ <note><p>A match specification for <c>send</c> trace can use
+ all guard and body functions except <c>caller</c>.</p></note>
+ </desc>
+ </func>
+
+ <func>
+ <name name="trace_pattern" arity="3" clause_i="2"/>
+ <fsummary>Sets trace pattern for tracing of message receiving.</fsummary>
+ <type name="trace_match_spec"/>
+ <desc>
+ <p></p>
+ <p>Sets trace pattern for <em>message receiving</em>.
+ Must be combined with
+ <seealso marker="#trace/3">erlang:trace/3</seealso>
+ to set the <c>'receive'</c> trace flag for one or more processes.
+ By default all messages, received by <c>'receive'</c> traced processes,
+ are traced. Use <c>erlang:trace_pattern/3</c> to limit
+ traced receive events based on the message content, the sender
+ and/or the receiver.</p>
+ <p>Argument <c><anno>MatchSpec</anno></c> can take the
+ following forms:</p>
+ <taglist>
+ <tag><c><anno>MatchSpecList</anno></c></tag>
+ <item>
+ <p>A list of match specifications. The matching is done
+ on the list <c>[Node, Sender, Msg]</c>. <c>Node</c>
+ is the node name of the sender. <c>Sender</c> is the
+ process or port identity of the sender, or the atom
+ <c>undefined</c> if the sender is not known (which may
+ be the case for remote senders). <c>Msg</c> is the
+ message term. The pid of the receiving process can be
+ accessed with the guard function <c>self/0</c>. An empty
+ list is the same as <c>true</c>. See the users guide section
+ <seealso marker="erts:match_spec">Match Specifications in Erlang</seealso>
+ for more information.</p>
+ </item>
+ <tag><c>true</c></tag>
+ <item>
+ <p>Enables tracing for all received messages (to <c>'receive'</c>
+ traced processes). Any match specification is
+ removed. <em>This is the default</em>.</p>
+ </item>
+ <tag><c>false</c></tag>
+ <item>
+ <p>Disables tracing for all received messages.
+ Any match specification is removed.</p>
+ </item>
+ </taglist>
+ <p>Argument <c><anno>FlagList</anno></c> must be <c>[]</c>
+ for receive tracing.</p>
+ <p>The return value is always <c>1</c>.</p>
+ <p>Example; only trace messages from a specific process <c>Pid</c>:</p>
+ <pre>
+> <input>erlang:trace_pattern('receive', [{['_',Pid, '_'],[],[]}], []).</input>
+1</pre>
+ <p>Only trace messages matching <c>{reply, _}</c>:</p>
+ <pre>
+> <input>erlang:trace_pattern('receive', [{['_','_', {reply,'_'}],[],[]}], []).</input>
+1</pre>
+ <p>Only trace messages from other nodes:</p>
+ <pre>
+> <input>erlang:trace_pattern('receive', [{['$1', '_', '_'],[{'=/=','$1',{node}}],[]}], []).</input>
+1</pre>
+ <note><p>A match specification for <c>'receive'</c> trace can
+ use all guard and body functions except <c>caller,
+ is_seq_trace, get_seq_token, set_seq_token, enable_trace,
+ disable_trace, trace, silent</c> and <c>process_dump</c>.</p></note>
+ </desc>
+ </func>
+
+ <func>
+ <name name="trace_pattern" arity="3" clause_i="3"/>
<fsummary>Sets trace patterns for tracing of function calls.</fsummary>
<type name="trace_pattern_mfa"/>
<type name="trace_match_spec"/>
<type name="trace_pattern_flag"/>
<desc>
- <p>Enables or disables call tracing for
- one or more functions. Must be combined with
+ <p>Enables or disables <em>call tracing</em> for one or more functions.
+ Must be combined with
<seealso marker="#trace/3">erlang:trace/3</seealso>
- to set the <c>call</c> trace flag for one or more processes.</p>
+ to set the <c>call</c> trace flag
+ for one or more processes.</p>
<p>Conceptually, call tracing works as follows. Inside
the Erlang Virtual Machine, a set of processes and
a set of functions are to be traced. If a traced process
@@ -8957,7 +9361,8 @@ timestamp() ->
</item>
<tag><c>true</c></tag>
<item>
- <p>Enables tracing for the matching functions.</p>
+ <p>Enables tracing for the matching functions.
+ Any match specification is removed.</p>
</item>
<tag><c><anno>MatchSpecList</anno></c></tag>
<item>
@@ -8999,13 +9404,12 @@ timestamp() ->
the process, a <c>return_to</c> message is also sent
when this function returns to its caller.</p>
</item>
- <tag><c>meta | {meta, <anno>Pid</anno>}</c></tag>
+ <tag><c>meta | {meta, <anno>Pid</anno>} | {meta, <anno>TracerModule</anno>, <anno>TracerState</anno>}</c>
+ </tag>
<item>
<p>Turns on or off meta-tracing for all types of function
- calls. Trace messages are sent to the tracer process
- or port <c><anno>Pid</anno></c> whenever any of the specified
- functions are called, regardless of how they are called.
- If no <c><anno>Pid</anno></c> is specified,
+ calls. Trace messages are sent to the tracer whenever any of
+ the specified functions are called. If no tracer is specified,
<c>self()</c> is used as a default tracer process.</p>
<p>Meta-tracing traces all processes and does not care
about the process trace flags set by <c>trace/3</c>,
@@ -9013,7 +9417,7 @@ timestamp() ->
<c>[call, timestamp]</c>.</p>
<p>The match specification function <c>{return_trace}</c>
works with meta-trace and sends its trace message to the
- same tracer process.</p>
+ same tracer.</p>
</item>
<tag><c>call_count</c></tag>
<item>
diff --git a/erts/doc/src/erlc.xml b/erts/doc/src/erlc.xml
index 9fc5864413..a64927fec2 100644
--- a/erts/doc/src/erlc.xml
+++ b/erts/doc/src/erlc.xml
@@ -4,7 +4,7 @@
<comref>
<header>
<copyright>
- <year>1997</year><year>2013</year>
+ <year>1997</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/erlsrv.xml b/erts/doc/src/erlsrv.xml
index ccb8b2dd76..fb00444aa4 100644
--- a/erts/doc/src/erlsrv.xml
+++ b/erts/doc/src/erlsrv.xml
@@ -4,7 +4,7 @@
<comref>
<header>
<copyright>
- <year>1998</year><year>2013</year>
+ <year>1998</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/erts_alloc.xml b/erts/doc/src/erts_alloc.xml
index 0965f9b49c..70775b9f0f 100644
--- a/erts/doc/src/erts_alloc.xml
+++ b/erts/doc/src/erts_alloc.xml
@@ -4,7 +4,7 @@
<cref>
<header>
<copyright>
- <year>2002</year><year>2015</year>
+ <year>2002</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -63,6 +63,9 @@
<tag><c>fix_alloc</c></tag>
<item>A fast allocator used for some frequently used
fixed size data types.</item>
+ <tag><c>exec_alloc</c></tag>
+ <item>Allocator used by hipe for native executable code
+ on specific architectures (x86_64).</item>
<tag><c>std_alloc</c></tag>
<item>Allocator used for most memory blocks not allocated via any of
the other allocators described above.</item>
@@ -80,7 +83,8 @@
the number of system calls made.</item>
</taglist>
<p><c>sys_alloc</c> and <c>literal_alloc</c> are always enabled and
- cannot be disabled. <c>mseg_alloc</c> is always enabled if it is
+ cannot be disabled. <c>exec_alloc</c> is only available if it is needed
+ and cannot be disabled. <c>mseg_alloc</c> is always enabled if it is
available and an allocator that uses it is enabled. All other
allocators can be <seealso marker="#M_e">enabled or disabled</seealso>.
By default all allocators are enabled.
@@ -248,16 +252,17 @@
the currently present allocators:</p>
<list type="bulleted">
<item><c>B: binary_alloc</c></item>
- <item><c>I: literal_alloc</c></item>
<item><c>D: std_alloc</c></item>
<item><c>E: ets_alloc</c></item>
<item><c>F: fix_alloc</c></item>
<item><c>H: eheap_alloc</c></item>
+ <item><c>I: literal_alloc</c></item>
<item><c>L: ll_alloc</c></item>
<item><c>M: mseg_alloc</c></item>
<item><c>R: driver_alloc</c></item>
<item><c>S: sl_alloc</c></item>
<item><c>T: temp_alloc</c></item>
+ <item><c>X: exec_alloc</c></item>
<item><c>Y: sys_alloc</c></item>
</list>
<p>The following flags are available for configuration of
@@ -576,6 +581,15 @@
and is usually sufficient. The flag is ignored on 32-bit
architectures.</item>
</taglist>
+ <p>The following flag is special for <c>exec_alloc</c>:</p>
+ <taglist>
+ <tag><marker id="MIscs"/><c><![CDATA[+MXscs <size in MB>]]></c></tag>
+ <item>
+ <c>exec_alloc</c> super carrier size (in MB). The amount of
+ <em>virtual</em> address space reserved for native executable code
+ used by hipe on specific architectures (x86_64). The default is 512 MB.
+ </item>
+ </taglist>
<p>Instrumentation flags:</p>
<taglist>
<tag><marker id="Mim"/><c>+Mim true|false</c></tag>
diff --git a/erts/doc/src/inet_cfg.xml b/erts/doc/src/inet_cfg.xml
index 5caf232a62..027fe600d7 100644
--- a/erts/doc/src/inet_cfg.xml
+++ b/erts/doc/src/inet_cfg.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2013</year>
+ <year>2004</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/init.xml b/erts/doc/src/init.xml
index 2a33096d04..84a5aea335 100644
--- a/erts/doc/src/init.xml
+++ b/erts/doc/src/init.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2013</year>
+ <year>1996</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/match_spec.xml b/erts/doc/src/match_spec.xml
index 08dad8cc10..3944f24f84 100644
--- a/erts/doc/src/match_spec.xml
+++ b/erts/doc/src/match_spec.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1999</year><year>2013</year>
+ <year>1999</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -287,7 +287,7 @@
can <em>not</em> be one of the atoms <c><![CDATA[all]]></c>, <c><![CDATA[new]]></c> or
<c><![CDATA[existing]]></c> (unless, of course, they are registered names).
<c><![CDATA[P2]]></c> can <em>not</em> be <c><![CDATA[cpu_timestamp]]></c> nor
- <c><![CDATA[{tracer,_}]]></c>.
+ <c><![CDATA[tracer]]></c>.
Returns <c><![CDATA[true]]></c> and may only be used in
the <c><![CDATA[MatchBody]]></c> part when tracing.
</p>
@@ -298,7 +298,7 @@
be either a process identifier or a registered name and is given
as the first argument to the match_spec function.
<c><![CDATA[P2]]></c> can <em>not</em> be <c><![CDATA[cpu_timestamp]]></c> nor
- <c><![CDATA[{tracer,_}]]></c>. Returns
+ <c><![CDATA[tracer]]></c>. Returns
<c><![CDATA[true]]></c> and may only be used in the <c><![CDATA[MatchBody]]></c> part
when tracing.
</p>
@@ -308,11 +308,14 @@
disable list is applied first, but effectively all changes
are applied atomically. The trace flags
are the same as for <c><![CDATA[erlang:trace/3]]></c> not including
- <c><![CDATA[cpu_timestamp]]></c> but including <c><![CDATA[{tracer,_}]]></c>. If a
+ <c><![CDATA[cpu_timestamp]]></c> but including <c><![CDATA[tracer]]></c>. If a
tracer is specified in both lists, the tracer in the
enable list takes precedence. If no tracer is specified the
same tracer as the process executing the match spec is
- used. With three parameters to this function the first is
+ used. When using a <seealso marker="erl_tracer">tracer module</seealso>
+ the module has to be loaded before the match specification is executed.
+ If it is not loaded the match will fail.
+ With three parameters to this function the first is
either a process identifier or the registered name of a
process to set trace flags on, the second is the disable
list, and the third is the enable list. Returns
@@ -525,7 +528,7 @@
</section>
<section>
- <title>Examples</title>
+ <title>ETS Examples</title>
<p>Match an argument list of three where the first and third arguments
are equal:</p>
<code type="none"><![CDATA[
@@ -616,5 +619,44 @@
<p>The function <c><![CDATA[ets:test_ms/2]]></c> can be useful for testing
complicated ets matches.</p>
</section>
+ <section>
+ <title>Tracing Examples</title>
+ <p>Only generate trace message if trace control word is set to 1:</p>
+ <code type="none"><![CDATA[
+[{'_',
+ [{'==',{get_tcw},{const, 1}}],
+ []}]
+ ]]></code>
+ <p>Only generate trace message if there is a seq trace token:</p>
+ <code type="none"><![CDATA[
+[{'_',
+ [{'==',{is_seq_trace},{const, 1}}],
+ []}]
+ ]]></code>
+ <p>Remove 'silent' trace flag when first argument is 'verbose'
+ and add it when it is 'silent':</p>
+ <code type="none"><![CDATA[
+[{'$1',
+ [{'==',{hd, '$1'},verbose}],
+ [{trace, [silent],[]}]},
+ {'$1',
+ [{'==',{hd, '$1'},silent}],
+ [{trace, [],[silent]}]}]
+ ]]></code>
+ <p>Add return_trace message if function is of arity 3:</p>
+ <code type="none"><![CDATA[
+[{'$1',
+ [{'==',{length, '$1'},3}],
+ [{return_trace}]},
+ {'_',[],[]}]
+ ]]></code>
+ <p>Only generate trace message if function is of arity 3 and first argument is 'trace':</p>
+ <code type="none"><![CDATA[
+[{['trace','$2','$3'],
+ [],
+ []},
+ {'_',[],[]}]
+ ]]></code>
+ </section>
</chapter>
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index acd816a81c..7501ccd9ce 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2015</year>
+ <year>2004</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,71 @@
<p>This document describes the changes made to the ERTS application.</p>
+<section><title>Erts 7.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ <c>process_info(Pid, last_calls)</c> did not work for
+ <c>Pid /= self()</c>.</p>
+ <p>
+ Own Id: OTP-13418</p>
+ </item>
+ <item>
+ <p>
+ Make sure to create a crash dump when running out of
+ memory. This was accidentally removed in the erts-7.3
+ release.</p>
+ <p>
+ Own Id: OTP-13419</p>
+ </item>
+ <item>
+ <p>
+ Schedulers could be woken by a premature timeout on
+ Linux. This premature wakeup was however harmless.</p>
+ <p>
+ Own Id: OTP-13420</p>
+ </item>
+ <item>
+ <p>
+ A process communicating with a port via one of the
+ <c>erlang:port_*</c> BIFs could potentially end up in an
+ inconsistent state if the port terminated during the
+ communication. When this occurred the process could later
+ block in a <c>receive</c> even though it had messages
+ matching in its message queue.</p>
+ <p>
+ This bug was introduced in erts version 5.10 (OTP R16A).</p>
+ <p>
+ Own Id: OTP-13424 Aux Id: OTP-10336 </p>
+ </item>
+ <item>
+ <p>
+ The reference count of a process structure could under
+ rare circumstances be erroneously managed. When this
+ happened invalid memory accesses occurred.</p>
+ <p>
+ Own Id: OTP-13446</p>
+ </item>
+ <item>
+ <p>
+ Fix race between <c>process_flag(trap_exit,true)</c> and
+ a received exit signal.</p>
+ <p>
+ A process could terminate due to exit signal even though
+ <c>process_flag(trap_exit,true)</c> had returned. A very
+ specific timing between call to <c>process_flag/2</c> and
+ exit signal from another scheduler was required for this
+ to happen.</p>
+ <p>
+ Own Id: OTP-13452</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 7.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/erts/doc/src/notes_history.xml b/erts/doc/src/notes_history.xml
index 0886ae4039..0bc2ab1383 100644
--- a/erts/doc/src/notes_history.xml
+++ b/erts/doc/src/notes_history.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2006</year><year>2013</year>
+ <year>2006</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/part.xml b/erts/doc/src/part.xml
index 2f5eca93db..b2abfc62ca 100644
--- a/erts/doc/src/part.xml
+++ b/erts/doc/src/part.xml
@@ -4,7 +4,7 @@
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1996</year><year>2013</year>
+ <year>1996</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/part_notes.xml b/erts/doc/src/part_notes.xml
index 83bb479715..e579b7635d 100644
--- a/erts/doc/src/part_notes.xml
+++ b/erts/doc/src/part_notes.xml
@@ -4,7 +4,7 @@
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2004</year><year>2013</year>
+ <year>2004</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/part_notes_history.xml b/erts/doc/src/part_notes_history.xml
index 055d1681d5..277683a2b5 100644
--- a/erts/doc/src/part_notes_history.xml
+++ b/erts/doc/src/part_notes_history.xml
@@ -4,7 +4,7 @@
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2006</year><year>2013</year>
+ <year>2006</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/ref_man.xml b/erts/doc/src/ref_man.xml
index ac589f8cb5..e45402a397 100644
--- a/erts/doc/src/ref_man.xml
+++ b/erts/doc/src/ref_man.xml
@@ -4,7 +4,7 @@
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1996</year><year>2013</year>
+ <year>1996</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -56,5 +56,6 @@
<xi:include href="driver_entry.xml"/>
<xi:include href="erts_alloc.xml"/>
<xi:include href="erl_nif.xml"/>
+ <xi:include href="erl_tracer.xml"/>
</application>
diff --git a/erts/doc/src/run_erl.xml b/erts/doc/src/run_erl.xml
index faec3c68c1..6b0fef7c0a 100644
--- a/erts/doc/src/run_erl.xml
+++ b/erts/doc/src/run_erl.xml
@@ -4,7 +4,7 @@
<comref>
<header>
<copyright>
- <year>1999</year><year>2013</year>
+ <year>1999</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/specs.xml b/erts/doc/src/specs.xml
index 41a3984659..ed6be650e5 100644
--- a/erts/doc/src/specs.xml
+++ b/erts/doc/src/specs.xml
@@ -2,6 +2,7 @@
<specs xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="../specs/specs_erl_prim_loader.xml"/>
<xi:include href="../specs/specs_erlang.xml"/>
+ <xi:include href="../specs/specs_erl_tracer.xml"/>
<xi:include href="../specs/specs_init.xml"/>
<xi:include href="../specs/specs_zlib.xml"/>
</specs>
diff --git a/erts/doc/src/start.xml b/erts/doc/src/start.xml
index 386fbe6e88..adacf5b98d 100644
--- a/erts/doc/src/start.xml
+++ b/erts/doc/src/start.xml
@@ -4,7 +4,7 @@
<comref>
<header>
<copyright>
- <year>1999</year><year>2013</year>
+ <year>1999</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/start_erl.xml b/erts/doc/src/start_erl.xml
index 62610b43b0..243aeaa717 100644
--- a/erts/doc/src/start_erl.xml
+++ b/erts/doc/src/start_erl.xml
@@ -4,7 +4,7 @@
<comref>
<header>
<copyright>
- <year>1998</year><year>2013</year>
+ <year>1998</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/tty.xml b/erts/doc/src/tty.xml
index cd46d1203c..b2866c82cf 100644
--- a/erts/doc/src/tty.xml
+++ b/erts/doc/src/tty.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1996</year><year>2013</year>
+ <year>1996</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/werl.xml b/erts/doc/src/werl.xml
index 9e7ad584eb..1a3cb6f502 100644
--- a/erts/doc/src/werl.xml
+++ b/erts/doc/src/werl.xml
@@ -4,7 +4,7 @@
<comref>
<header>
<copyright>
- <year>1998</year><year>2013</year>
+ <year>1998</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/zlib.xml b/erts/doc/src/zlib.xml
index 0a641346d9..861661043f 100644
--- a/erts/doc/src/zlib.xml
+++ b/erts/doc/src/zlib.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2005</year><year>2013</year>
+ <year>2005</year><year>2016</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/emulator/Makefile b/erts/emulator/Makefile
index 550e6e6f5b..65fdbdb747 100644
--- a/erts/emulator/Makefile
+++ b/erts/emulator/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2009. All Rights Reserved.
+# Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index 12148ad9c7..fb486c917f 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2013. All Rights Reserved.
+# Copyright Ericsson AB 1996-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.
@@ -577,7 +577,7 @@ GENERATE += $(TARGET)/erl_version.h
# driver table
$(TTF_DIR)/driver_tab.c: Makefile.in utils/make_driver_tab
- $(gen_verbose)LANG=C $(PERL) utils/make_driver_tab -o $@ -nifs $(STATIC_NIF_LIBS) -drivers $(DRV_OBJS) $(STATIC_DRIVER_LIBS)
+ $(gen_verbose)LANG=C $(PERL) utils/make_driver_tab -o $@ -nifs $(NIF_OBJS) $(STATIC_NIF_LIBS) -drivers $(DRV_OBJS) $(STATIC_DRIVER_LIBS)
GENERATE += $(TTF_DIR)/driver_tab.c
@@ -600,8 +600,8 @@ $(PRELOAD_SRC): $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \
$(ERL_TOP)/erts/preloaded/ebin/prim_zip.beam \
$(ERL_TOP)/erts/preloaded/ebin/erl_prim_loader.beam \
$(ERL_TOP)/erts/preloaded/ebin/erlang.beam \
- $(ERL_TOP)/erts/preloaded/ebin/erts_internal.beam
-
+ $(ERL_TOP)/erts/preloaded/ebin/erts_internal.beam \
+ $(ERL_TOP)/erts/preloaded/ebin/erl_tracer.beam
$(gen_verbose)LANG=C $(PERL) utils/make_preload $(MAKE_PRELOAD_EXTRA) -rc $^ > $@
else
PRELOAD_OBJ = $(OBJDIR)/preload.o
@@ -616,7 +616,8 @@ $(PRELOAD_SRC): $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \
$(ERL_TOP)/erts/preloaded/ebin/prim_zip.beam \
$(ERL_TOP)/erts/preloaded/ebin/erl_prim_loader.beam \
$(ERL_TOP)/erts/preloaded/ebin/erlang.beam \
- $(ERL_TOP)/erts/preloaded/ebin/erts_internal.beam
+ $(ERL_TOP)/erts/preloaded/ebin/erts_internal.beam \
+ $(ERL_TOP)/erts/preloaded/ebin/erl_tracer.beam
$(gen_verbose)LANG=C $(PERL) utils/make_preload -old $^ > $@
endif
@@ -690,6 +691,9 @@ $(OBJDIR)/%.o: drivers/common/%.c
$(OBJDIR)/%.o: drivers/$(ERLANG_OSTYPE)/%.c
$(V_CC) $(CFLAGS) $(INCLUDES) -Idrivers/common -Idrivers/$(ERLANG_OSTYPE) -I../etc/$(ERLANG_OSTYPE) -c $< -o $@
+$(OBJDIR)/%.o: nifs/common/%.c
+ $(V_CC) $(CFLAGS) -DLIBSCTP=$(LIBSCTP) $(INCLUDES) -Inifs/common -Inifs/$(ERLANG_OSTYPE) -c $< -o $@
+
# ----------------------------------------------------------------------
# Specials
#
@@ -779,6 +783,9 @@ RUN_OBJS = \
$(OBJDIR)/erl_ptab.o $(OBJDIR)/erl_map.o \
$(OBJDIR)/erl_msacc.o
+LTTNG_OBJS = $(OBJDIR)/erlang_lttng.o
+NIF_OBJS = $(OBJDIR)/erl_tracer_nif.o
+
ifeq ($(TARGET),win32)
DRV_OBJS = \
$(OBJDIR)/registry_drv.o \
@@ -885,9 +892,9 @@ ifdef HIPE_ENABLED
EXTRA_BASE_OBJS += $(HIPE_OBJS)
endif
-BASE_OBJS = $(EMU_OBJS) $(RUN_OBJS) $(OS_OBJS) $(EXTRA_BASE_OBJS)
+BASE_OBJS = $(EMU_OBJS) $(RUN_OBJS) $(OS_OBJS) $(EXTRA_BASE_OBJS) $(LTTNG_OBJS)
-before_DTrace_OBJS = $(BASE_OBJS) $(DRV_OBJS)
+before_DTrace_OBJS = $(BASE_OBJS) $(DRV_OBJS) $(NIF_OBJS)
DTRACE_OBJS =
ifdef DTRACE_ENABLED_2STEP
@@ -1040,6 +1047,7 @@ endif
BEAM_SRC=$(wildcard beam/*.c)
DRV_COMMON_SRC=$(wildcard drivers/common/*.c)
DRV_OSTYPE_SRC=$(wildcard drivers/$(ERLANG_OSTYPE)/*.c)
+NIF_COMMON_SRC=$(wildcard nifs/common/*.c)
ALL_SYS_SRC=$(wildcard sys/$(ERLANG_OSTYPE)/*.c) $(wildcard sys/common/*.c)
# We use $(shell ls) here instead of wildcard as $(wildcard ) resolved at
# loadtime of the makefile and at that time these files are not generated yet.
@@ -1072,7 +1080,7 @@ MG_FLAG=-MG
endif
DEP_CC=$(CC)
-DEP_FLAGS=-MM $(MG_FLAG) $(CFLAGS) $(INCLUDES) -Idrivers/common -Idrivers/$(ERLANG_OSTYPE)
+DEP_FLAGS=-MM $(MG_FLAG) $(CFLAGS) $(INCLUDES) -Inifs/common -Idrivers/common -Idrivers/$(ERLANG_OSTYPE)
SYS_SRC=$(ALL_SYS_SRC)
endif
@@ -1097,6 +1105,8 @@ $(TTF_DIR)/depend.mk: $(TTF_DIR)/GENERATED $(PRELOAD_SRC)
| $(SED_DEPEND) >> $(TTF_DIR)/depend.mk
$(V_at)$(DEP_CC) $(DEP_FLAGS) -I../etc/$(ERLANG_OSTYPE) $(DRV_OSTYPE_SRC) \
| $(SED_DEPEND) >> $(TTF_DIR)/depend.mk
+ $(V_at)$(DEP_CC) $(DEP_FLAGS) $(NIF_COMMON_SRC) \
+ | $(SED_DEPEND) >> $(TTF_DIR)/depend.mk
$(V_at)$(DEP_CC) $(DEP_FLAGS) $(SYS_SRC) \
| $(SED_DEPEND) >> $(TTF_DIR)/depend.mk
$(V_at)$(DEP_CC) $(DEP_FLAGS) $(TARGET_SRC) \
diff --git a/erts/emulator/beam/atom.c b/erts/emulator/beam/atom.c
index 099c00bcf6..a5e778e4aa 100644
--- a/erts/emulator/beam/atom.c
+++ b/erts/emulator/beam/atom.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/beam/atom.h b/erts/emulator/beam/atom.h
index 2c002ca92f..fbd0528009 100644
--- a/erts/emulator/beam/atom.h
+++ b/erts/emulator/beam/atom.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index 169b071cd7..3022c0a99a 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2013. All Rights Reserved.
+# Copyright Ericsson AB 1996-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.
@@ -43,7 +43,7 @@ atom false true
atom Underscore='_'
atom Noname='nonode@nohost'
atom EOT='$end_of_table'
-atom Cookie=''
+atom Empty=''
#
# Used in the Beam emulator loop. (Smaller literals usually means tighter code.)
@@ -161,6 +161,7 @@ atom close
atom closed
atom code
atom command
+atom commandv
atom compact
atom compat_rel
atom compile
@@ -197,6 +198,7 @@ atom dirty_cpu_schedulers_online
atom dirty_io
atom disable_trace
atom disabled
+atom discard
atom display_items
atom dist
atom dist_cmd
@@ -231,6 +233,7 @@ atom exception_trace
atom extended
atom Eq='=:='
atom Eqeq='=='
+atom erl_tracer
atom erlang
atom ERROR='ERROR'
atom error_handler
@@ -243,6 +246,9 @@ atom exact_reductions
atom exclusive
atom exit_status
atom existing
+atom existing_processes
+atom existing_ports
+atom existing
atom exiting
atom exports
atom external
@@ -267,6 +273,10 @@ atom garbage_collecting
atom garbage_collection
atom garbage_collection_info
atom gc_end
+atom gc_major_end
+atom gc_major_start
+atom gc_minor_end
+atom gc_minor_start
atom gc_start
atom Ge='>='
atom generational
@@ -353,6 +363,7 @@ atom match
atom match_limit
atom match_limit_recursion
atom match_spec
+atom match_spec_result
atom max
atom maximum
atom max_tables max_processes
@@ -401,6 +412,8 @@ atom net_kernel_terminated
atom never_utf
atom new
atom new_index
+atom new_processes
+atom new_ports
atom new_uniq
atom newline
atom next
@@ -540,6 +553,7 @@ atom scheme
atom scientific
atom scope
atom seconds
+atom send_to_non_existing_process
atom sensitive
atom sequential_tracer
atom sequential_trace_token
@@ -561,6 +575,7 @@ atom size
atom sl_alloc
atom spawn_executable
atom spawn_driver
+atom spawned
atom ssl_tls
atom stack_size
atom start
@@ -569,6 +584,7 @@ atom static
atom stderr_to_stdout
atom stop
atom stream
+atom strict_monotonic
atom strict_monotonic_timestamp
atom sunrm
atom suspend
@@ -596,8 +612,9 @@ atom total_active_tasks
atom total_heap_size
atom total_run_queue_lengths
atom tpkt
-atom trace trace_ts traced
+atom trace trace_ts traced
atom trace_control_word
+atom trace_status
atom tracer
atom trap_exit
atom trim
diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c
index 0b47fc3586..40d44dda4c 100644
--- a/erts/emulator/beam/beam_bif_load.c
+++ b/erts/emulator/beam/beam_bif_load.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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.
@@ -38,7 +38,7 @@
#include "erl_thr_progress.h"
static void set_default_trace_pattern(Eterm module);
-static Eterm check_process_code(Process* rp, Module* modp, Uint flags, int *redsp);
+static Eterm check_process_code(Process* rp, Module* modp, Uint flags, int *redsp, int fcalls);
static void delete_code(Module* modp);
static void decrement_refc(BeamCodeHeader*);
static int any_heap_ref_ptrs(Eterm* start, Eterm* end, char* mod_start, Uint mod_size);
@@ -467,7 +467,7 @@ check_old_code_1(BIF_ALIST_1)
}
Eterm
-erts_check_process_code(Process *c_p, Eterm module, Uint flags, int *redsp)
+erts_check_process_code(Process *c_p, Eterm module, Uint flags, int *redsp, int fcalls)
{
Module* modp;
Eterm res;
@@ -483,7 +483,7 @@ erts_check_process_code(Process *c_p, Eterm module, Uint flags, int *redsp)
return am_false;
erts_rlock_old_code(code_ix);
res = (!modp->old.code_hdr ? am_false :
- check_process_code(c_p, modp, flags, redsp));
+ check_process_code(c_p, modp, flags, redsp, fcalls));
erts_runlock_old_code(code_ix);
return res;
@@ -506,7 +506,7 @@ BIF_RETTYPE erts_internal_check_process_code_2(BIF_ALIST_2)
goto badarg;
}
- res = erts_check_process_code(BIF_P, BIF_ARG_1, flags, &reds);
+ res = erts_check_process_code(BIF_P, BIF_ARG_1, flags, &reds, BIF_P->fcalls);
ASSERT(is_value(res));
@@ -625,8 +625,8 @@ BIF_RETTYPE call_on_load_function_1(BIF_ALIST_1)
{
Module* modp = erts_get_module(BIF_ARG_1, erts_active_code_ix());
- if (modp && modp->curr.code_hdr) {
- BIF_TRAP_CODE_PTR_0(BIF_P, modp->curr.code_hdr->on_load_function_ptr);
+ if (modp && modp->old.code_hdr) {
+ BIF_TRAP_CODE_PTR_0(BIF_P, modp->old.code_hdr->on_load_function_ptr);
}
else {
BIF_ERROR(BIF_P, BADARG);
@@ -651,14 +651,14 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2)
code_ix = erts_active_code_ix();
modp = erts_get_module(BIF_ARG_1, code_ix);
- if (!modp || !modp->curr.code_hdr) {
+ if (!modp || !modp->old.code_hdr) {
error:
erts_smp_thr_progress_unblock();
erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
erts_release_code_write_permission();
BIF_ERROR(BIF_P, BADARG);
}
- if (modp->curr.code_hdr->on_load_function_ptr == NULL) {
+ if (modp->old.code_hdr->on_load_function_ptr == NULL) {
goto error;
}
if (BIF_ARG_2 != am_false && BIF_ARG_2 != am_true) {
@@ -667,44 +667,55 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2)
if (BIF_ARG_2 == am_true) {
int i;
+ struct erl_module_instance t;
+
+ /*
+ * Swap old and new code.
+ */
+ t = modp->curr;
+ modp->curr = modp->old;
+ modp->old = t;
/*
* The on_load function succeded. Fix up export entries.
*/
for (i = 0; i < export_list_size(code_ix); i++) {
Export *ep = export_list(i,code_ix);
- if (ep != NULL &&
- ep->code[0] == BIF_ARG_1 &&
- ep->code[4] != 0) {
+ if (ep == NULL || ep->code[0] != BIF_ARG_1) {
+ continue;
+ }
+ if (ep->code[4] != 0) {
ep->addressv[code_ix] = (void *) ep->code[4];
ep->code[4] = 0;
+ } else {
+ if (ep->addressv[code_ix] == ep->code+3 &&
+ ep->code[3] == (BeamInstr) em_apply_bif) {
+ continue;
+ }
+ ep->addressv[code_ix] = ep->code+3;
+ ep->code[3] = (BeamInstr) em_call_error_handler;
}
}
modp->curr.code_hdr->on_load_function_ptr = NULL;
set_default_trace_pattern(BIF_ARG_1);
} else if (BIF_ARG_2 == am_false) {
- BeamInstr* code;
- BeamInstr* end;
+ int i;
/*
- * The on_load function failed. Remove the loaded code.
- * This is an combination of delete and purge. We purge
- * the current code; the old code is not touched.
+ * The on_load function failed. Remove references to the
+ * code that is about to be purged from the export entries.
*/
- erts_total_code_size -= modp->curr.code_length;
- code = (BeamInstr*) modp->curr.code_hdr;
- end = (BeamInstr *) ((char *)code + modp->curr.code_length);
- erts_cleanup_funs_on_purge(code, end);
- beam_catches_delmod(modp->curr.catches, code, modp->curr.code_length,
- erts_active_code_ix());
- if (modp->curr.code_hdr->literals_start) {
- erts_free(ERTS_ALC_T_LITERAL, modp->curr.code_hdr->literals_start);
- }
- erts_free(ERTS_ALC_T_CODE, modp->curr.code_hdr);
- modp->curr.code_hdr = NULL;
- modp->curr.code_length = 0;
- modp->curr.catches = BEAM_CATCHES_NIL;
- erts_remove_from_ranges(code);
+
+ for (i = 0; i < export_list_size(code_ix); i++) {
+ Export *ep = export_list(i,code_ix);
+ if (ep == NULL || ep->code[0] != BIF_ARG_1) {
+ continue;
+ }
+ if (ep->code[3] == (BeamInstr) em_apply_bif) {
+ continue;
+ }
+ ep->code[4] = 0;
+ }
}
erts_smp_thr_progress_unblock();
erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
@@ -719,13 +730,13 @@ set_default_trace_pattern(Eterm module)
Binary *match_spec;
Binary *meta_match_spec;
struct trace_pattern_flags trace_pattern_flags;
- Eterm meta_tracer_pid;
+ ErtsTracer meta_tracer;
erts_get_default_trace_pattern(&trace_pattern_is_on,
&match_spec,
&meta_match_spec,
&trace_pattern_flags,
- &meta_tracer_pid);
+ &meta_tracer);
if (trace_pattern_is_on) {
Eterm mfa[1];
mfa[0] = module;
@@ -733,7 +744,7 @@ set_default_trace_pattern(Eterm module)
match_spec,
meta_match_spec,
1, trace_pattern_flags,
- meta_tracer_pid, 1);
+ meta_tracer, 1);
}
}
@@ -753,7 +764,7 @@ check_mod_funs(Process *p, ErlOffHeap *off_heap, char *area, size_t area_size)
static Eterm
-check_process_code(Process* rp, Module* modp, Uint flags, int *redsp)
+check_process_code(Process* rp, Module* modp, Uint flags, int *redsp, int fcalls)
{
BeamInstr* start;
char* literals;
@@ -832,7 +843,7 @@ check_process_code(Process* rp, Module* modp, Uint flags, int *redsp)
/*
* Message queue can contains funs, but (at least currently) no
- * constants. If we got references to this module from the message
+ * literals. If we got references to this module from the message
* queue, a GC cannot remove these...
*/
@@ -853,7 +864,7 @@ check_process_code(Process* rp, Module* modp, Uint flags, int *redsp)
for (; hfrag; hfrag = hfrag->next) {
if (check_mod_funs(rp, &hfrag->off_heap, mod_start, mod_size))
return am_true;
- /* Should not contain any constants... */
+ /* Should not contain any literals... */
ASSERT(!any_heap_refs(&hfrag->mem[0],
&hfrag->mem[hfrag->used_size],
literals,
@@ -908,7 +919,7 @@ check_process_code(Process* rp, Module* modp, Uint flags, int *redsp)
#ifdef DEBUG
/*
* Message buffer fragments should not have any references
- * to constants, and off heap lists should already have
+ * to literals, and off heap lists should already have
* been moved into process off heap structure.
*/
for (msgp = rp->msg_frag; msgp; msgp = msgp->next) {
@@ -945,7 +956,7 @@ check_process_code(Process* rp, Module* modp, Uint flags, int *redsp)
need_gc &= ~done_gc;
/*
- * Try to get rid of constants by by garbage collecting.
+ * Try to get rid of literals by by garbage collecting.
* Clear both fvalue and ftrace.
*/
@@ -955,7 +966,7 @@ check_process_code(Process* rp, Module* modp, Uint flags, int *redsp)
if (need_gc & ERTS_ORDINARY_GC__) {
FLAGS(rp) |= F_NEED_FULLSWEEP;
- *redsp += erts_garbage_collect_nobump(rp, 0, rp->arg_reg, rp->arity);
+ *redsp += erts_garbage_collect_nobump(rp, 0, rp->arg_reg, rp->arity, fcalls);
done_gc |= ERTS_ORDINARY_GC__;
}
if (need_gc & ERTS_LITERAL_GC__) {
@@ -1264,6 +1275,7 @@ delete_code(Module* modp)
modp->curr.code_length = 0;
modp->curr.catches = BEAM_CATCHES_NIL;
modp->curr.nif = NULL;
+
}
diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c
index 5d471d168b..1e30e8d8d1 100644
--- a/erts/emulator/beam/beam_bp.c
+++ b/erts/emulator/beam/beam_bp.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2000-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2000-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.
@@ -92,15 +92,15 @@ get_mtime(Process *c_p)
/*
** Helpers
*/
-static Eterm do_call_trace(Process* c_p, BeamInstr* I, Eterm* reg,
- int local, Binary* ms, Eterm tracer_pid);
+static ErtsTracer do_call_trace(Process* c_p, BeamInstr* I, Eterm* reg,
+ int local, Binary* ms, ErtsTracer tracer);
static void set_break(BpFunctions* f, Binary *match_spec, Uint break_flags,
- enum erts_break_op count_op, Eterm tracer_pid);
+ enum erts_break_op count_op, ErtsTracer tracer);
static void set_function_break(BeamInstr *pc,
Binary *match_spec,
Uint break_flags,
enum erts_break_op count_op,
- Eterm tracer_pid);
+ ErtsTracer tracer);
static void clear_break(BpFunctions* f, Uint break_flags);
static int clear_function_break(BeamInstr *pc, Uint break_flags);
@@ -108,7 +108,7 @@ static int clear_function_break(BeamInstr *pc, Uint break_flags);
static BpDataTime* get_time_break(BeamInstr *pc);
static GenericBpData* check_break(BeamInstr *pc, Uint break_flags);
-static void bp_meta_unref(BpMetaPid* bmp);
+static void bp_meta_unref(BpMetaTracer* bmt);
static void bp_count_unref(BpCount* bcp);
static void bp_time_unref(BpDataTime* bdt);
static void consolidate_bp_data(Module* modp, BeamInstr* pc, int local);
@@ -248,7 +248,10 @@ erts_bp_match_export(BpFunctions* f, Eterm mfa[3], int specified)
void
erts_bp_free_matched_functions(BpFunctions* f)
{
- Free(f->matching);
+ if (f->matching) {
+ Free(f->matching);
+ }
+ else ASSERT(f->matched == 0);
}
void
@@ -302,7 +305,7 @@ consolidate_bp_data(Module* modp, BeamInstr* pc, int local)
MatchSetUnref(dst->local_ms);
}
if (flags & ERTS_BPF_META_TRACE) {
- bp_meta_unref(dst->meta_pid);
+ bp_meta_unref(dst->meta_tracer);
MatchSetUnref(dst->meta_ms);
}
if (flags & ERTS_BPF_COUNT) {
@@ -343,8 +346,8 @@ consolidate_bp_data(Module* modp, BeamInstr* pc, int local)
MatchSetRef(dst->local_ms);
}
if (flags & ERTS_BPF_META_TRACE) {
- dst->meta_pid = src->meta_pid;
- erts_refc_inc(&dst->meta_pid->refc, 1);
+ dst->meta_tracer = src->meta_tracer;
+ erts_refc_inc(&dst->meta_tracer->refc, 1);
dst->meta_ms = src->meta_ms;
MatchSetRef(dst->meta_ms);
}
@@ -436,13 +439,13 @@ uninstall_breakpoint(BeamInstr* pc)
void
erts_set_trace_break(BpFunctions* f, Binary *match_spec)
{
- set_break(f, match_spec, ERTS_BPF_LOCAL_TRACE, 0, am_true);
+ set_break(f, match_spec, ERTS_BPF_LOCAL_TRACE, 0, erts_tracer_true);
}
void
-erts_set_mtrace_break(BpFunctions* f, Binary *match_spec, Eterm tracer_pid)
+erts_set_mtrace_break(BpFunctions* f, Binary *match_spec, ErtsTracer tracer)
{
- set_break(f, match_spec, ERTS_BPF_META_TRACE, 0, tracer_pid);
+ set_break(f, match_spec, ERTS_BPF_META_TRACE, 0, tracer);
}
void
@@ -450,13 +453,13 @@ erts_set_call_trace_bif(BeamInstr *pc, Binary *match_spec, int local)
{
Uint flags = local ? ERTS_BPF_LOCAL_TRACE : ERTS_BPF_GLOBAL_TRACE;
- set_function_break(pc, match_spec, flags, 0, NIL);
+ set_function_break(pc, match_spec, flags, 0, erts_tracer_nil);
}
void
-erts_set_mtrace_bif(BeamInstr *pc, Binary *match_spec, Eterm tracer_pid)
+erts_set_mtrace_bif(BeamInstr *pc, Binary *match_spec, ErtsTracer tracer)
{
- set_function_break(pc, match_spec, ERTS_BPF_META_TRACE, 0, tracer_pid);
+ set_function_break(pc, match_spec, ERTS_BPF_META_TRACE, 0, tracer);
}
void
@@ -464,7 +467,7 @@ erts_set_time_trace_bif(BeamInstr *pc, enum erts_break_op count_op)
{
set_function_break(pc, NULL,
ERTS_BPF_TIME_TRACE|ERTS_BPF_TIME_TRACE_ACTIVE,
- count_op, NIL);
+ count_op, erts_tracer_nil);
}
void
@@ -474,21 +477,21 @@ erts_clear_time_trace_bif(BeamInstr *pc) {
void
erts_set_debug_break(BpFunctions* f) {
- set_break(f, NULL, ERTS_BPF_DEBUG, 0, NIL);
+ set_break(f, NULL, ERTS_BPF_DEBUG, 0, erts_tracer_nil);
}
void
erts_set_count_break(BpFunctions* f, enum erts_break_op count_op)
{
set_break(f, 0, ERTS_BPF_COUNT|ERTS_BPF_COUNT_ACTIVE,
- count_op, NIL);
+ count_op, erts_tracer_nil);
}
void
erts_set_time_break(BpFunctions* f, enum erts_break_op count_op)
{
set_break(f, 0, ERTS_BPF_TIME_TRACE|ERTS_BPF_TIME_TRACE_ACTIVE,
- count_op, NIL);
+ count_op, erts_tracer_nil);
}
void
@@ -625,19 +628,26 @@ erts_generic_breakpoint(Process* c_p, BeamInstr* I, Eterm* reg)
if (bp_flags & ERTS_BPF_LOCAL_TRACE) {
ASSERT((bp_flags & ERTS_BPF_GLOBAL_TRACE) == 0);
- (void) do_call_trace(c_p, I, reg, 1, bp->local_ms, am_true);
+ (void) do_call_trace(c_p, I, reg, 1, bp->local_ms, erts_tracer_true);
} else if (bp_flags & ERTS_BPF_GLOBAL_TRACE) {
- (void) do_call_trace(c_p, I, reg, 0, bp->local_ms, am_true);
+ (void) do_call_trace(c_p, I, reg, 0, bp->local_ms, erts_tracer_true);
}
if (bp_flags & ERTS_BPF_META_TRACE) {
- Eterm old_pid;
- Eterm new_pid;
-
- old_pid = (Eterm) erts_smp_atomic_read_nob(&bp->meta_pid->pid);
- new_pid = do_call_trace(c_p, I, reg, 1, bp->meta_ms, old_pid);
- if (new_pid != old_pid) {
- erts_smp_atomic_set_nob(&bp->meta_pid->pid, new_pid);
+ ErtsTracer old_tracer, new_tracer;
+
+ old_tracer = erts_smp_atomic_read_nob(&bp->meta_tracer->tracer);
+
+ new_tracer = do_call_trace(c_p, I, reg, 1, bp->meta_ms, old_tracer);
+ if (!ERTS_TRACER_COMPARE(new_tracer, old_tracer)) {
+ if (old_tracer == erts_smp_atomic_cmpxchg_acqb(
+ &bp->meta_tracer->tracer,
+ (erts_aint_t)new_tracer,
+ (erts_aint_t)old_tracer)) {
+ ERTS_TRACER_CLEAR(&old_tracer);
+ } else {
+ ERTS_TRACER_CLEAR(&new_tracer);
+ }
}
}
@@ -645,7 +655,8 @@ erts_generic_breakpoint(Process* c_p, BeamInstr* I, Eterm* reg)
erts_smp_atomic_inc_nob(&bp->count->acount);
}
- if (bp_flags & ERTS_BPF_TIME_TRACE_ACTIVE && erts_is_tracer_proc_valid(c_p)) {
+ if (bp_flags & ERTS_BPF_TIME_TRACE_ACTIVE
+ && ERTS_TRACER_PROC_IS_ENABLED(c_p)) {
Eterm w;
erts_trace_time_call(c_p, I, bp->time);
w = (BeamInstr) *c_p->cp;
@@ -690,7 +701,7 @@ erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I)
Eterm (*func)(Process*, Eterm*, BeamInstr*);
Export* ep = bif_export[bif_index];
Uint32 flags = 0, flags_meta = 0;
- Eterm meta_tracer_pid = NIL;
+ ErtsTracer meta_tracer = erts_tracer_nil;
int applying = (I == &(ep->code[3])); /* Yup, the apply code for a bif
* is actually in the
* export entry */
@@ -718,23 +729,32 @@ erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I)
IS_TRACED_FL(p, F_TRACE_CALLS)) {
int local = !!(bp_flags & ERTS_BPF_LOCAL_TRACE);
flags = erts_call_trace(p, ep->code, bp->local_ms, args,
- local, &ERTS_TRACER_PROC(p));
+ local, &ERTS_TRACER(p));
}
if (bp_flags & ERTS_BPF_META_TRACE) {
- Eterm tpid1, tpid2;
+ ErtsTracer old_tracer;
- tpid1 = tpid2 =
- (Eterm) erts_smp_atomic_read_nob(&bp->meta_pid->pid);
+ meta_tracer = erts_smp_atomic_read_nob(&bp->meta_tracer->tracer);
+ old_tracer = meta_tracer;
flags_meta = erts_call_trace(p, ep->code, bp->meta_ms, args,
- 0, &tpid2);
- meta_tracer_pid = tpid2;
- if (tpid1 != tpid2) {
- erts_smp_atomic_set_nob(&bp->meta_pid->pid, tpid2);
+ 0, &meta_tracer);
+
+ if (!ERTS_TRACER_COMPARE(old_tracer, meta_tracer)) {
+ ErtsTracer new_tracer = erts_tracer_nil;
+ erts_tracer_update(&new_tracer, meta_tracer);
+ if (old_tracer == erts_smp_atomic_cmpxchg_acqb(
+ &bp->meta_tracer->tracer,
+ (erts_aint_t)new_tracer,
+ (erts_aint_t)old_tracer)) {
+ ERTS_TRACER_CLEAR(&old_tracer);
+ } else {
+ ERTS_TRACER_CLEAR(&new_tracer);
+ }
}
}
if (bp_flags & ERTS_BPF_TIME_TRACE_ACTIVE &&
IS_TRACED_FL(p, F_TRACE_CALLS) &&
- erts_is_tracer_proc_valid(p)) {
+ ERTS_TRACER_PROC_IS_ENABLED(p)) {
BeamInstr *pc = (BeamInstr *)ep->code+3;
erts_trace_time_call(p, pc, bp->time);
}
@@ -778,8 +798,6 @@ erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I)
if (reason != TRAP) {
Eterm class;
Eterm value = p->fvalue;
- DeclareTmpHeapNoproc(nocatch,3);
- UseTmpHeapNoproc(3);
/* Expand error value like in handle_error() */
if (reason & EXF_ARGLIST) {
Eterm *tp;
@@ -788,7 +806,8 @@ erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I)
value = tp[1];
}
if ((reason & EXF_THROWN) && (p->catches <= 0)) {
- value = TUPLE2(nocatch, am_nocatch, value);
+ Eterm *hp = HAlloc(p, 3);
+ value = TUPLE2(hp, am_nocatch, value);
reason = EXC_ERROR;
}
/* Note: expand_error_value() could theoretically
@@ -801,11 +820,11 @@ erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I)
if (flags_meta & MATCH_SET_EXCEPTION_TRACE) {
erts_trace_exception(p, ep->code, class, value,
- &meta_tracer_pid);
+ &meta_tracer);
}
if (flags & MATCH_SET_EXCEPTION_TRACE) {
erts_trace_exception(p, ep->code, class, value,
- &ERTS_TRACER_PROC(p));
+ &ERTS_TRACER(p));
}
if ((flags & MATCH_SET_RETURN_TO_TRACE) && p->catches > 0) {
/* can only happen if(local)*/
@@ -827,7 +846,6 @@ erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I)
}
}
}
- UnUseTmpHeapNoproc(3);
if ((flags_meta|flags) & MATCH_SET_EXCEPTION_TRACE) {
erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL_MINOR);
ERTS_TRACE_FLAGS(p) |= F_EXCEPTION_TRACE;
@@ -836,11 +854,11 @@ erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I)
}
} else {
if (flags_meta & MATCH_SET_RX_TRACE) {
- erts_trace_return(p, ep->code, result, &meta_tracer_pid);
+ erts_trace_return(p, ep->code, result, &meta_tracer);
}
/* MATCH_SET_RETURN_TO_TRACE cannot occur if(meta) */
if (flags & MATCH_SET_RX_TRACE) {
- erts_trace_return(p, ep->code, result, &ERTS_TRACER_PROC(p));
+ erts_trace_return(p, ep->code, result, &ERTS_TRACER(p));
}
if (flags & MATCH_SET_RETURN_TO_TRACE) {
/* can only happen if(local)*/
@@ -857,9 +875,9 @@ erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr* I)
return result;
}
-static Eterm
+static ErtsTracer
do_call_trace(Process* c_p, BeamInstr* I, Eterm* reg,
- int local, Binary* ms, Eterm tracer_pid)
+ int local, Binary* ms, ErtsTracer tracer)
{
Eterm* cpp;
int return_to_trace = 0;
@@ -899,7 +917,7 @@ do_call_trace(Process* c_p, BeamInstr* I, Eterm* reg,
ASSERT(is_CP(*cpp));
}
ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
- flags = erts_call_trace(c_p, I-3, ms, reg, local, &tracer_pid);
+ flags = erts_call_trace(c_p, I-3, ms, reg, local, &tracer);
ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
if (cpp) {
c_p->cp = cp_save;
@@ -910,7 +928,7 @@ do_call_trace(Process* c_p, BeamInstr* I, Eterm* reg,
need += 1;
}
if (flags & MATCH_SET_RX_TRACE) {
- need += 3;
+ need += 3 + size_object(tracer);
}
if (need) {
ASSERT(c_p->htop <= E && E <= c_p->hend);
@@ -926,14 +944,15 @@ do_call_trace(Process* c_p, BeamInstr* I, Eterm* reg,
E[0] = make_cp(c_p->cp);
c_p->cp = beam_return_to_trace;
}
- if (flags & MATCH_SET_RX_TRACE) {
+ if (flags & MATCH_SET_RX_TRACE)
+ {
E -= 3;
+ c_p->stop = E;
ASSERT(c_p->htop <= E && E <= c_p->hend);
ASSERT(is_CP((Eterm) (UWord) (I - 3)));
- ASSERT(am_true == tracer_pid ||
- is_internal_pid(tracer_pid) || is_internal_port(tracer_pid));
+ ASSERT(IS_TRACER_VALID(tracer));
E[2] = make_cp(c_p->cp);
- E[1] = tracer_pid;
+ E[1] = copy_object(tracer, c_p);
E[0] = make_cp(I - 3); /* We ARE at the beginning of an
instruction,
the funcinfo is above i. */
@@ -942,9 +961,9 @@ do_call_trace(Process* c_p, BeamInstr* I, Eterm* reg,
erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
ERTS_TRACE_FLAGS(c_p) |= F_EXCEPTION_TRACE;
erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
- }
- c_p->stop = E;
- return tracer_pid;
+ } else
+ c_p->stop = E;
+ return tracer;
}
void
@@ -974,7 +993,7 @@ erts_trace_time_call(Process* c_p, BeamInstr* I, BpDataTime* bdt)
if (pbt == 0) {
/* First call of process to instrumented function */
pbt = Alloc(sizeof(process_breakpoint_time_t));
- (void) ERTS_PROC_SET_CALL_TIME(c_p, ERTS_PROC_LOCK_MAIN, pbt);
+ (void) ERTS_PROC_SET_CALL_TIME(c_p, pbt);
} else {
ASSERT(pbt->pc);
/* add time to previous code */
@@ -1098,9 +1117,9 @@ erts_is_trace_break(BeamInstr *pc, Binary **match_spec_ret, int local)
return 0;
}
-int
+int
erts_is_mtrace_break(BeamInstr *pc, Binary **match_spec_ret,
- Eterm *tracer_pid_ret)
+ ErtsTracer *tracer_ret)
{
GenericBpData* bp = check_break(pc, ERTS_BPF_META_TRACE);
@@ -1108,9 +1127,8 @@ erts_is_mtrace_break(BeamInstr *pc, Binary **match_spec_ret,
if (match_spec_ret) {
*match_spec_ret = bp->meta_ms;
}
- if (tracer_pid_ret) {
- *tracer_pid_ret =
- (Eterm) erts_smp_atomic_read_nob(&bp->meta_pid->pid);
+ if (tracer_ret) {
+ *tracer_ret = erts_smp_atomic_read_nob(&bp->meta_tracer->tracer);
}
return 1;
}
@@ -1391,7 +1409,7 @@ void erts_schedule_time_break(Process *p, Uint schedule) {
static void
set_break(BpFunctions* f, Binary *match_spec, Uint break_flags,
- enum erts_break_op count_op, Eterm tracer_pid)
+ enum erts_break_op count_op, ErtsTracer tracer)
{
Uint i;
Uint n;
@@ -1400,13 +1418,13 @@ set_break(BpFunctions* f, Binary *match_spec, Uint break_flags,
for (i = 0; i < n; i++) {
BeamInstr* pc = f->matching[i].pc;
set_function_break(pc, match_spec, break_flags,
- count_op, tracer_pid);
+ count_op, tracer);
}
}
static void
set_function_break(BeamInstr *pc, Binary *match_spec, Uint break_flags,
- enum erts_break_op count_op, Eterm tracer_pid)
+ enum erts_break_op count_op, ErtsTracer tracer)
{
GenericBp* g;
GenericBpData* bp;
@@ -1417,7 +1435,7 @@ set_function_break(BeamInstr *pc, Binary *match_spec, Uint break_flags,
g = (GenericBp *) pc[-4];
if (g == 0) {
int i;
- if (count_op == erts_break_reset || count_op == erts_break_stop) {
+ if (count_op == ERTS_BREAK_RESTART || count_op == ERTS_BREAK_PAUSE) {
/* Do not insert a new breakpoint */
return;
}
@@ -1439,9 +1457,9 @@ set_function_break(BeamInstr *pc, Binary *match_spec, Uint break_flags,
MatchSetUnref(bp->local_ms);
} else if (common & ERTS_BPF_META_TRACE) {
MatchSetUnref(bp->meta_ms);
- bp_meta_unref(bp->meta_pid);
+ bp_meta_unref(bp->meta_tracer);
} else if (common & ERTS_BPF_COUNT) {
- if (count_op == erts_break_stop) {
+ if (count_op == ERTS_BREAK_PAUSE) {
bp->flags &= ~ERTS_BPF_COUNT_ACTIVE;
} else {
bp->flags |= ERTS_BPF_COUNT_ACTIVE;
@@ -1453,7 +1471,7 @@ set_function_break(BeamInstr *pc, Binary *match_spec, Uint break_flags,
BpDataTime* bdt = bp->time;
Uint i = 0;
- if (count_op == erts_break_stop) {
+ if (count_op == ERTS_BREAK_PAUSE) {
bp->flags &= ~ERTS_BPF_TIME_TRACE_ACTIVE;
} else {
bp->flags |= ERTS_BPF_TIME_TRACE_ACTIVE;
@@ -1474,13 +1492,15 @@ set_function_break(BeamInstr *pc, Binary *match_spec, Uint break_flags,
MatchSetRef(match_spec);
bp->local_ms = match_spec;
} else if (break_flags & ERTS_BPF_META_TRACE) {
- BpMetaPid* bmp;
+ BpMetaTracer* bmt;
+ ErtsTracer meta_tracer = erts_tracer_nil;
MatchSetRef(match_spec);
bp->meta_ms = match_spec;
- bmp = Alloc(sizeof(BpMetaPid));
- erts_refc_init(&bmp->refc, 1);
- erts_smp_atomic_init_nob(&bmp->pid, tracer_pid);
- bp->meta_pid = bmp;
+ bmt = Alloc(sizeof(BpMetaTracer));
+ erts_refc_init(&bmt->refc, 1);
+ erts_tracer_update(&meta_tracer, tracer); /* copy tracer */
+ erts_smp_atomic_init_nob(&bmt->tracer, (erts_aint_t)meta_tracer);
+ bp->meta_tracer = bmt;
} else if (break_flags & ERTS_BPF_COUNT) {
BpCount* bcp;
@@ -1544,7 +1564,7 @@ clear_function_break(BeamInstr *pc, Uint break_flags)
}
if (common & ERTS_BPF_META_TRACE) {
MatchSetUnref(bp->meta_ms);
- bp_meta_unref(bp->meta_pid);
+ bp_meta_unref(bp->meta_tracer);
}
if (common & ERTS_BPF_COUNT) {
ASSERT((bp->flags & ERTS_BPF_COUNT_ACTIVE) == 0);
@@ -1560,10 +1580,12 @@ clear_function_break(BeamInstr *pc, Uint break_flags)
}
static void
-bp_meta_unref(BpMetaPid* bmp)
+bp_meta_unref(BpMetaTracer* bmt)
{
- if (erts_refc_dectest(&bmp->refc, 0) <= 0) {
- Free(bmp);
+ if (erts_refc_dectest(&bmt->refc, 0) <= 0) {
+ ErtsTracer trc = erts_smp_atomic_read_nob(&bmt->tracer);
+ ERTS_TRACER_CLEAR(&trc);
+ Free(bmt);
}
}
@@ -1598,9 +1620,7 @@ bp_time_unref(BpDataTime* bdt)
h_p = erts_pid2proc(NULL, 0, item->pid,
ERTS_PROC_LOCK_MAIN);
if (h_p) {
- pbt = ERTS_PROC_SET_CALL_TIME(h_p,
- ERTS_PROC_LOCK_MAIN,
- NULL);
+ pbt = ERTS_PROC_SET_CALL_TIME(h_p, NULL);
if (pbt) {
Free(pbt);
}
diff --git a/erts/emulator/beam/beam_bp.h b/erts/emulator/beam/beam_bp.h
index 2b89d6fc71..9c2fc007a2 100644
--- a/erts/emulator/beam/beam_bp.h
+++ b/erts/emulator/beam/beam_bp.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2000-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2000-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.
@@ -55,15 +55,15 @@ typedef struct {
} BpCount;
typedef struct {
- erts_smp_atomic_t pid;
+ erts_smp_atomic_t tracer;
erts_refc_t refc;
-} BpMetaPid;
+} BpMetaTracer;
typedef struct generic_bp_data {
Uint flags;
Binary* local_ms; /* Match spec for local call trace */
Binary* meta_ms; /* Match spec for meta trace */
- BpMetaPid* meta_pid; /* Meta trace pid */
+ BpMetaTracer* meta_tracer; /* Meta tracer */
BpCount* count; /* For call count */
BpDataTime* time; /* For time trace */
} GenericBpData;
@@ -86,10 +86,10 @@ typedef struct generic_bp {
#endif
enum erts_break_op{
- erts_break_nop = 0, /* Must be false */
- erts_break_set = !0, /* Must be true */
- erts_break_reset,
- erts_break_stop
+ ERTS_BREAK_NOP = 0, /* Must be false */
+ ERTS_BREAK_SET = !0, /* Must be true */
+ ERTS_BREAK_RESTART,
+ ERTS_BREAK_PAUSE
};
typedef Uint32 ErtsBpIndex;
@@ -132,10 +132,10 @@ void erts_set_call_trace_bif(BeamInstr *pc, Binary *match_spec, int local);
void erts_clear_call_trace_bif(BeamInstr *pc, int local);
void erts_set_mtrace_break(BpFunctions *f, Binary *match_spec,
- Eterm tracer_pid);
+ ErtsTracer tracer);
void erts_clear_mtrace_break(BpFunctions *f);
void erts_set_mtrace_bif(BeamInstr *pc, Binary *match_spec,
- Eterm tracer_pid);
+ ErtsTracer tracer);
void erts_clear_mtrace_bif(BeamInstr *pc);
void erts_set_debug_break(BpFunctions *f);
@@ -150,13 +150,13 @@ void erts_clear_export_break(Module *modp, BeamInstr* pc);
BeamInstr erts_generic_breakpoint(Process* c_p, BeamInstr* I, Eterm* reg);
BeamInstr erts_trace_break(Process *p, BeamInstr *pc, Eterm *args,
- Uint32 *ret_flags, Eterm *tracer_pid);
+ Uint32 *ret_flags, ErtsTracer *tracer);
int erts_is_trace_break(BeamInstr *pc, Binary **match_spec_ret, int local);
int erts_is_mtrace_break(BeamInstr *pc, Binary **match_spec_ret,
- Eterm *tracer_pid_rte);
+ ErtsTracer *tracer_ret);
int erts_is_mtrace_bif(BeamInstr *pc, Binary **match_spec_ret,
- Eterm *tracer_pid_ret);
+ ErtsTracer *tracer_ret);
int erts_is_native_break(BeamInstr *pc);
int erts_is_count_break(BeamInstr *pc, Uint *count_ret);
int erts_is_time_break(Process *p, BeamInstr *pc, Eterm *call_time);
@@ -173,19 +173,7 @@ void erts_clear_time_trace_bif(BeamInstr *pc);
BeamInstr *erts_find_local_func(Eterm mfa[3]);
-ERTS_GLB_INLINE Uint erts_bp_sched2ix(void);
-
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
-ERTS_GLB_INLINE Uint erts_bp_sched2ix(void)
-{
-#ifdef ERTS_SMP
- ErtsSchedulerData *esdp;
- esdp = erts_get_scheduler_data();
- return esdp->no - 1;
-#else
- return 0;
-#endif
-}
extern erts_smp_atomic32_t erts_active_bp_index;
extern erts_smp_atomic32_t erts_staging_bp_index;
diff --git a/erts/emulator/beam/beam_catches.c b/erts/emulator/beam/beam_catches.c
index 7a1f4901aa..cd592c7e5e 100644
--- a/erts/emulator/beam/beam_catches.c
+++ b/erts/emulator/beam/beam_catches.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2000-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2000-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.
diff --git a/erts/emulator/beam/beam_catches.h b/erts/emulator/beam/beam_catches.h
index 59ee64d033..8eb2165ac9 100644
--- a/erts/emulator/beam/beam_catches.h
+++ b/erts/emulator/beam/beam_catches.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2000-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2000-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.
diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c
index e37bd4d78c..a4ad3e7886 100644
--- a/erts/emulator/beam/beam_debug.c
+++ b/erts/emulator/beam/beam_debug.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
@@ -431,7 +431,7 @@ print_op(int to, void *to_arg, int op, int size, BeamInstr* addr)
packed >>= 10;
break;
case '0': /* Tight shift */
- *ap++ = packed & (BEAM_TIGHT_MASK / sizeof(Eterm));
+ *ap++ = packed & BEAM_TIGHT_MASK;
packed >>= BEAM_TIGHT_SHIFT;
break;
case '6': /* Shift 16 steps */
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index a390422040..99eb26bec5 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -308,7 +308,8 @@ void** beam_ops;
if (E - HTOP < (needed + (HeapNeed))) { \
SWAPOUT; \
PROCESS_MAIN_CHK_LOCKS(c_p); \
- FCALLS -= erts_garbage_collect_nobump(c_p, needed + (HeapNeed), reg, (M)); \
+ FCALLS -= erts_garbage_collect_nobump(c_p, needed + (HeapNeed), \
+ reg, (M), FCALLS); \
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); \
PROCESS_MAIN_CHK_LOCKS(c_p); \
SWAPIN; \
@@ -360,7 +361,7 @@ void** beam_ops;
if ((E - HTOP < need) || (MSO(c_p).overhead + (VNh) >= BIN_VHEAP_SZ(c_p))) {\
SWAPOUT; \
PROCESS_MAIN_CHK_LOCKS(c_p); \
- FCALLS -= erts_garbage_collect_nobump(c_p, need, reg, (Live)); \
+ FCALLS -= erts_garbage_collect_nobump(c_p, need, reg, (Live), FCALLS); \
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); \
PROCESS_MAIN_CHK_LOCKS(c_p); \
SWAPIN; \
@@ -381,7 +382,7 @@ void** beam_ops;
if (E - HTOP < need) { \
SWAPOUT; \
PROCESS_MAIN_CHK_LOCKS(c_p); \
- FCALLS -= erts_garbage_collect_nobump(c_p, need, reg, (Live));\
+ FCALLS -= erts_garbage_collect_nobump(c_p, need, reg, (Live), FCALLS); \
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); \
PROCESS_MAIN_CHK_LOCKS(c_p); \
SWAPIN; \
@@ -402,7 +403,7 @@ void** beam_ops;
SWAPOUT; \
reg[Live] = Extra; \
PROCESS_MAIN_CHK_LOCKS(c_p); \
- FCALLS -= erts_garbage_collect_nobump(c_p, need, reg, (Live)+1); \
+ FCALLS -= erts_garbage_collect_nobump(c_p, need, reg, (Live)+1, FCALLS); \
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); \
PROCESS_MAIN_CHK_LOCKS(c_p); \
Extra = reg[Live]; \
@@ -702,6 +703,17 @@ void** beam_ops;
dst[1] = E2; \
} while (0)
+#define GetTupleElement2Y(Src, Element, D1, D2) \
+ do { \
+ Eterm* src; \
+ Eterm E1, E2; \
+ src = ADD_BYTE_OFFSET(tuple_val(Src), (Element)); \
+ E1 = src[0]; \
+ E2 = src[1]; \
+ D1 = E1; \
+ D2 = E2; \
+ } while (0)
+
#define GetTupleElement3(Src, Element, Dest) \
do { \
Eterm* src; \
@@ -1185,6 +1197,25 @@ init_emulator(void)
#define DTRACE_NIF_RETURN(p, m, f, a) do {} while (0)
#endif /* USE_VM_PROBES */
+#ifdef DEBUG
+#define ERTS_DBG_CHK_REDS(P, FC) \
+ do { \
+ if (ERTS_PROC_GET_SAVED_CALLS_BUF((P))) { \
+ ASSERT(FC <= 0); \
+ ASSERT(ERTS_PROC_GET_SCHDATA(c_p)->virtual_reds \
+ <= 0 - (FC)); \
+ } \
+ else { \
+ ASSERT(FC <= CONTEXT_REDS); \
+ ASSERT(ERTS_PROC_GET_SCHDATA(c_p)->virtual_reds \
+ <= CONTEXT_REDS - (FC)); \
+ } \
+} while (0)
+#else
+#define ERTS_DBG_CHK_REDS(P, FC)
+#endif
+
+
/*
* process_main() is called twice:
* The first call performs some initialisation, including exporting
@@ -1279,7 +1310,12 @@ void process_main(void)
goto do_schedule1;
do_schedule:
- reds_used = REDS_IN(c_p) - FCALLS;
+ ASSERT(c_p->debug_reds_in == REDS_IN(c_p));
+ if (!ERTS_PROC_GET_SAVED_CALLS_BUF(c_p))
+ reds_used = REDS_IN(c_p) - FCALLS;
+ else
+ reds_used = REDS_IN(c_p) - (CONTEXT_REDS + FCALLS);
+ ASSERT(reds_used >= 0);
do_schedule1:
if (start_time != 0) {
@@ -1299,6 +1335,7 @@ void process_main(void)
ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
c_p = schedule(c_p, reds_used);
+ ASSERT(!(c_p->flags & F_HIPE_MODE));
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
start_time = 0;
#ifdef DEBUG
@@ -1337,16 +1374,21 @@ void process_main(void)
SET_I(c_p->i);
- reds = c_p->fcalls;
- if (ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)
- && (ERTS_TRACE_FLAGS(c_p) & F_SENSITIVE) == 0) {
- neg_o_reds = -reds;
- FCALLS = REDS_IN(c_p) = 0;
+ REDS_IN(c_p) = reds = c_p->fcalls;
+#ifdef DEBUG
+ c_p->debug_reds_in = reds;
+#endif
+
+ if (ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)) {
+ neg_o_reds = -CONTEXT_REDS;
+ FCALLS = neg_o_reds + reds;
} else {
neg_o_reds = 0;
- FCALLS = REDS_IN(c_p) = reds;
+ FCALLS = reds;
}
+ ERTS_DBG_CHK_REDS(c_p, FCALLS);
+
next = (BeamInstr *) *I;
SWAPIN;
ASSERT(VALID_INSTR(next));
@@ -1759,7 +1801,7 @@ void process_main(void)
if (E - HTOP < 3) {
SWAPOUT;
PROCESS_MAIN_CHK_LOCKS(c_p);
- FCALLS -= erts_garbage_collect_nobump(c_p, 3, reg+2, 1);
+ FCALLS -= erts_garbage_collect_nobump(c_p, 3, reg+2, 1, FCALLS);
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
PROCESS_MAIN_CHK_LOCKS(c_p);
SWAPIN;
@@ -1854,6 +1896,7 @@ void process_main(void)
c_p->flags |= F_DELAY_GC;
loop_rec__:
+
PROCESS_MAIN_CHK_LOCKS(c_p);
msgp = PEEK_MESSAGE(c_p);
@@ -1996,6 +2039,8 @@ void process_main(void)
ERTS_VBUMP_LEAVE_REDS_INTERNAL(c_p, 5, FCALLS);
}
+ ERTS_DBG_CHK_REDS(c_p, FCALLS);
+
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
PROCESS_MAIN_CHK_LOCKS(c_p);
NextPF(0, next);
@@ -2155,7 +2200,7 @@ void process_main(void)
PreFetch(0, next);
if (IS_TRACED_FL(c_p, F_TRACE_RECEIVE)) {
- trace_receive(c_p, am_timeout);
+ trace_receive(c_p, am_clock_service, am_timeout, NULL);
}
if (ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)) {
save_calls(c_p, &exp_timeout);
@@ -2524,6 +2569,7 @@ do { \
GetArg1(2, tmp_reg[0]);
bf = (BifFunction) Arg(1);
+ ERTS_DBG_CHK_REDS(c_p, FCALLS);
c_p->fcalls = FCALLS;
PROCESS_MAIN_CHK_LOCKS(c_p);
ASSERT(!ERTS_PROC_IS_EXITING(c_p));
@@ -2533,6 +2579,7 @@ do { \
PROCESS_MAIN_CHK_LOCKS(c_p);
ERTS_HOLE_CHECK(c_p);
FCALLS = c_p->fcalls;
+ ERTS_DBG_CHK_REDS(c_p, FCALLS);
if (is_value(result)) {
StoreBifResult(3, result);
}
@@ -2553,6 +2600,7 @@ do { \
GetArg1(1, tmp_reg[0]);
bf = (BifFunction) Arg(0);
+ ERTS_DBG_CHK_REDS(c_p, FCALLS);
c_p->fcalls = FCALLS;
PROCESS_MAIN_CHK_LOCKS(c_p);
ASSERT(!ERTS_PROC_IS_EXITING(c_p));
@@ -2562,6 +2610,7 @@ do { \
PROCESS_MAIN_CHK_LOCKS(c_p);
ERTS_HOLE_CHECK(c_p);
FCALLS = c_p->fcalls;
+ ERTS_DBG_CHK_REDS(c_p, FCALLS);
if (is_value(result)) {
StoreBifResult(2, result);
}
@@ -2580,6 +2629,7 @@ do { \
GetArg1(2, x(live));
bf = (GcBifFunction) Arg(1);
+ ERTS_DBG_CHK_REDS(c_p, FCALLS);
c_p->fcalls = FCALLS;
SWAPOUT;
PROCESS_MAIN_CHK_LOCKS(c_p);
@@ -2591,6 +2641,7 @@ do { \
SWAPIN;
ERTS_HOLE_CHECK(c_p);
FCALLS = c_p->fcalls;
+ ERTS_DBG_CHK_REDS(c_p, FCALLS);
if (is_value(result)) {
StoreBifResult(4, result);
}
@@ -2619,6 +2670,7 @@ do { \
*/
live++;
bf = (GcBifFunction) Arg(1);
+ ERTS_DBG_CHK_REDS(c_p, FCALLS);
c_p->fcalls = FCALLS;
SWAPOUT;
PROCESS_MAIN_CHK_LOCKS(c_p);
@@ -2630,6 +2682,7 @@ do { \
SWAPIN;
ERTS_HOLE_CHECK(c_p);
FCALLS = c_p->fcalls;
+ ERTS_DBG_CHK_REDS(c_p, FCALLS);
if (is_value(result)) {
StoreBifResult(5, result);
}
@@ -2660,6 +2713,7 @@ do { \
*/
live += 2;
bf = (GcBifFunction) Arg(1);
+ ERTS_DBG_CHK_REDS(c_p, FCALLS);
c_p->fcalls = FCALLS;
SWAPOUT;
PROCESS_MAIN_CHK_LOCKS(c_p);
@@ -2671,6 +2725,7 @@ do { \
SWAPIN;
ERTS_HOLE_CHECK(c_p);
FCALLS = c_p->fcalls;
+ ERTS_DBG_CHK_REDS(c_p, FCALLS);
if (is_value(result)) {
StoreBifResult(5, result);
}
@@ -2697,6 +2752,7 @@ do { \
GetArg2(2, tmp_reg[0], tmp_reg[1]);
bf = (BifFunction) Arg(1);
+ ERTS_DBG_CHK_REDS(c_p, FCALLS);
c_p->fcalls = FCALLS;
PROCESS_MAIN_CHK_LOCKS(c_p);
ASSERT(!ERTS_PROC_IS_EXITING(c_p));
@@ -2706,6 +2762,7 @@ do { \
PROCESS_MAIN_CHK_LOCKS(c_p);
ERTS_HOLE_CHECK(c_p);
FCALLS = c_p->fcalls;
+ ERTS_DBG_CHK_REDS(c_p, FCALLS);
if (is_value(result)) {
StoreBifResult(4, result);
}
@@ -2764,6 +2821,7 @@ do { \
bf = GET_BIF_ADDRESS(Arg(0));
PRE_BIF_SWAPOUT(c_p);
+ ERTS_DBG_CHK_REDS(c_p, FCALLS);
c_p->fcalls = FCALLS - 1;
if (FCALLS <= 0) {
save_calls(c_p, (Export *) Arg(0));
@@ -2785,6 +2843,7 @@ do { \
PROCESS_MAIN_CHK_LOCKS(c_p);
HTOP = HEAP_TOP(c_p);
FCALLS = c_p->fcalls;
+ ERTS_DBG_CHK_REDS(c_p, FCALLS);
/* We have to update the cache if we are enabled in order
to make sure no book keeping is done after we disabled
msacc. We don't always do this as it is quite expensive. */
@@ -3313,8 +3372,13 @@ do { \
* (beacuse the code for the Dispatch() macro becomes shorter that way).
*/
- reds_used = REDS_IN(c_p) - FCALLS + 1;
-
+ ASSERT(c_p->debug_reds_in == REDS_IN(c_p));
+ if (!ERTS_PROC_GET_SAVED_CALLS_BUF(c_p))
+ reds_used = REDS_IN(c_p) - FCALLS;
+ else
+ reds_used = REDS_IN(c_p) - (CONTEXT_REDS + FCALLS);
+ ASSERT(reds_used >= 0);
+
/*
* Save the argument registers and everything else.
*/
@@ -3346,7 +3410,7 @@ do { \
OpCase(normal_exit): {
SWAPOUT;
c_p->freason = EXC_NORMAL;
- c_p->arity = 0; /* In case this process will ever be garbed again. */
+ c_p->arity = 0; /* In case this process will never be garbed again. */
ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
erts_do_exit_process(c_p, am_normal);
ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
@@ -3360,48 +3424,18 @@ do { \
goto do_schedule;
}
- OpCase(raise_ss): {
- /* This was not done very well in R10-0; then, we passed the tag in
- the first argument and hoped that the existing c_p->ftrace was
- still correct. But the ftrace-object already includes the tag
- (or rather, the freason). Now, we pass the original ftrace in
- the first argument. We also handle atom tags in the first
- argument for backwards compatibility.
- */
- Eterm raise_val1;
- Eterm raise_val2;
- GetArg2(0, raise_val1, raise_val2);
- c_p->fvalue = raise_val2;
- if (c_p->freason == EXC_NULL) {
- /* a safety check for the R10-0 case; should not happen */
- c_p->ftrace = NIL;
- c_p->freason = EXC_ERROR;
- }
- /* for R10-0 code, keep existing c_p->ftrace and hope it's correct */
- switch (raise_val1) {
- case am_throw:
- c_p->freason = EXC_THROWN & ~EXF_SAVETRACE;
- break;
- case am_error:
- c_p->freason = EXC_ERROR & ~EXF_SAVETRACE;
- break;
- case am_exit:
- c_p->freason = EXC_EXIT & ~EXF_SAVETRACE;
- break;
- default:
- {/* R10-1 and later
- XXX note: should do sanity check on given trace if it can be
- passed from a user! Currently only expecting generated calls.
- */
- struct StackTrace *s;
- c_p->ftrace = raise_val1;
- s = get_trace_from_exc(raise_val1);
- if (s == NULL) {
- c_p->freason = EXC_ERROR;
- } else {
- c_p->freason = PRIMARY_EXCEPTION(s->freason);
- }
- }
+ OpCase(i_raise): {
+ Eterm raise_trace = x(2);
+ Eterm raise_value = x(1);
+ struct StackTrace *s;
+
+ c_p->fvalue = raise_value;
+ c_p->ftrace = raise_trace;
+ s = get_trace_from_exc(raise_trace);
+ if (s == NULL) {
+ c_p->freason = EXC_ERROR;
+ } else {
+ c_p->freason = PRIMARY_EXCEPTION(s->freason);
}
goto find_func_info;
}
@@ -3490,7 +3524,7 @@ do { \
typedef Eterm NifF(struct enif_environment_t*, int argc, Eterm argv[]);
NifF* fp = vbf = (NifF*) I[1];
struct enif_environment_t env;
- erts_pre_nif(&env, c_p, (struct erl_module_nif*)I[2]);
+ erts_pre_nif(&env, c_p, (struct erl_module_nif*)I[2], NULL);
live_hf_end = c_p->mbuf;
nif_bif_result = (*fp)(&env, bif_nif_arity, reg);
if (env.exception_thrown)
@@ -3533,6 +3567,7 @@ do { \
DTRACE_BIF_ENTRY(c_p, (Eterm)I[-3], (Eterm)I[-2], (Uint)I[-1]);
SWAPOUT;
+ ERTS_DBG_CHK_REDS(c_p, FCALLS - 1);
c_p->fcalls = FCALLS - 1;
vbf = (BifFunction) Arg(0);
PROCESS_MAIN_CHK_LOCKS(c_p);
@@ -3568,6 +3603,7 @@ do { \
}
SWAPIN; /* There might have been a garbage collection. */
FCALLS = c_p->fcalls;
+ ERTS_DBG_CHK_REDS(c_p, FCALLS);
if (is_value(nif_bif_result)) {
r(0) = nif_bif_result;
CHECK_TERM(r(0));
@@ -4102,7 +4138,7 @@ do { \
StoreBifResult(1, result);
}
- OpCase(i_bs_put_utf16_jIs): {
+ OpCase(bs_put_utf16_jIs): {
Eterm arg;
GetArg1(2, arg);
@@ -4618,7 +4654,7 @@ do { \
SWAPOUT; /* Needed for shared heap */
ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
- erts_trace_return(c_p, code, r(0), E+1/*Process tracer*/);
+ erts_trace_return(c_p, code, r(0), ERTS_TRACER_FROM_ETERM(E+1)/* tracer */);
ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
SWAPIN;
c_p->cp = NULL;
@@ -4630,9 +4666,9 @@ do { \
OpCase(i_generic_breakpoint): {
BeamInstr real_I;
ASSERT(I[-5] == (BeamInstr) BeamOp(op_i_func_info_IaaI));
- SWAPOUT;
+ HEAVY_SWAPOUT;
real_I = erts_generic_breakpoint(c_p, I, reg);
- SWAPIN;
+ HEAVY_SWAPIN;
ASSERT(VALID_INSTR(real_I));
Goto(real_I);
}
@@ -4809,6 +4845,7 @@ do { \
{
#define HIPE_MODE_SWITCH(Cmd) \
SWAPOUT; \
+ ERTS_DBG_CHK_REDS(c_p, FCALLS); \
c_p->fcalls = FCALLS; \
c_p->def_arg_reg[4] = -neg_o_reds; \
c_p = hipe_mode_switch(c_p, Cmd, reg); \
@@ -4847,6 +4884,9 @@ do { \
#undef HIPE_MODE_SWITCH
L_post_hipe_mode_switch:
+#ifdef DEBUG
+ pid = c_p->common.id; /* may have switched process... */
+#endif
reg = ERTS_PROC_GET_SCHDATA(c_p)->x_reg_array;
freg = ERTS_PROC_GET_SCHDATA(c_p)->f_reg_array;
ERL_BITS_RELOAD_STATEP(c_p);
@@ -4854,6 +4894,7 @@ do { \
neg_o_reds = -c_p->def_arg_reg[4];
FCALLS = c_p->fcalls;
SWAPIN;
+ ERTS_DBG_CHK_REDS(c_p, FCALLS);
switch( c_p->def_arg_reg[3] ) {
case HIPE_MODE_SWITCH_RES_RETURN:
ASSERT(is_value(reg[0]));
@@ -5258,7 +5299,8 @@ next_catch(Process* c_p, Eterm *reg) {
BeamInstr *cpp = c_p->cp;
if (cpp == beam_exception_trace) {
erts_trace_exception(c_p, cp_val(ptr[0]),
- reg[1], reg[2], ptr+1);
+ reg[1], reg[2],
+ ERTS_TRACER_FROM_ETERM(ptr+1));
/* Skip return_trace parameters */
ptr += 2;
} else if (cpp == beam_return_trace) {
@@ -5285,7 +5327,8 @@ next_catch(Process* c_p, Eterm *reg) {
}
if (cp_val(*prev) == beam_exception_trace) {
erts_trace_exception(c_p, cp_val(ptr[0]),
- reg[1], reg[2], ptr+1);
+ reg[1], reg[2],
+ ERTS_TRACER_FROM_ETERM(ptr+1));
}
/* Skip return_trace parameters */
ptr += 2;
@@ -6079,7 +6122,7 @@ erts_hibernate(Process* c_p, Eterm module, Eterm function, Eterm args, Eterm* re
return -1;
}
#else /* ERTS_SMP */
- ERTS_SMP_MSGQ_MV_INQ2PRIVQ(c_p);
+ ERTS_SMP_MSGQ_MV_INQ2PRIVQ(c_p);
if (!c_p->msg.len)
#endif
erts_smp_atomic32_read_band_relb(&c_p->state, ~ERTS_PSFLG_ACTIVE);
@@ -6856,7 +6899,7 @@ erts_current_reductions(Process *current, Process *p)
if (current != p) {
return 0;
} else if (current->fcalls < 0 && ERTS_PROC_GET_SAVED_CALLS_BUF(current)) {
- return -current->fcalls;
+ return current->fcalls + CONTEXT_REDS;
} else {
return REDS_IN(current) - current->fcalls;
}
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index f115df935f..95489d9a63 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -32,6 +32,7 @@
#include "bif.h"
#include "external.h"
#include "beam_load.h"
+#include "beam_bp.h"
#include "big.h"
#include "erl_bits.h"
#include "beam_catches.h"
@@ -479,9 +480,9 @@ static void free_loader_state(Binary* magic);
static ErlHeapFragment* new_literal_fragment(Uint size);
static void free_literal_fragment(ErlHeapFragment*);
static void loader_state_dtor(Binary* magic);
-static Eterm insert_new_code(Process *c_p, ErtsProcLocks c_p_locks,
- Eterm group_leader, Eterm module,
- BeamCodeHeader* code, Uint size);
+static Eterm stub_insert_new_code(Process *c_p, ErtsProcLocks c_p_locks,
+ Eterm group_leader, Eterm module,
+ BeamCodeHeader* code, Uint size);
static int init_iff_file(LoaderState* stp, byte* code, Uint size);
static int scan_iff_file(LoaderState* stp, Uint* chunk_types,
Uint num_types, Uint num_mandatory);
@@ -513,7 +514,7 @@ static GenOp* gen_get_map_element(LoaderState* stp, GenOpArg Fail, GenOpArg Src,
static int freeze_code(LoaderState* stp);
-static void final_touch(LoaderState* stp);
+static void final_touch(LoaderState* stp, struct erl_module_instance* inst_p);
static void short_file(int line, LoaderState* stp, unsigned needed);
static void load_printf(int line, LoaderState* context, char *fmt, ...);
static int transform_engine(LoaderState* st);
@@ -766,8 +767,11 @@ Eterm
erts_finish_loading(Binary* magic, Process* c_p,
ErtsProcLocks c_p_locks, Eterm* modp)
{
- Eterm retval;
+ Eterm retval = NIL;
LoaderState* stp = ERTS_MAGIC_BIN_DATA(magic);
+ Module* mod_tab_p;
+ struct erl_module_instance* inst_p;
+ Uint size;
/*
* No other process may run since we will update the export
@@ -776,27 +780,80 @@ erts_finish_loading(Binary* magic, Process* c_p,
ERTS_SMP_LC_ASSERT(erts_initialized == 0 || erts_has_code_write_permission() ||
erts_smp_thr_progress_is_blocking());
-
/*
* Make current code for the module old and insert the new code
* as current. This will fail if there already exists old code
* for the module.
*/
+ mod_tab_p = erts_put_module(stp->module);
CHKBLK(ERTS_ALC_T_CODE,stp->code);
- retval = insert_new_code(c_p, c_p_locks, stp->group_leader, stp->module,
- stp->hdr, stp->loaded_size);
- if (retval != NIL) {
- goto load_error;
+ if (!stp->on_load) {
+ /*
+ * Normal case -- no -on_load() function.
+ */
+ retval = beam_make_current_old(c_p, c_p_locks, stp->module);
+ ASSERT(retval == NIL);
+ } else {
+ ErtsCodeIndex code_ix = erts_staging_code_ix();
+ Eterm module = stp->module;
+ int i;
+
+ /*
+ * There is an -on_load() function. We will keep the current
+ * code, but we must turn off any tracing.
+ */
+
+ for (i = 0; i < export_list_size(code_ix); i++) {
+ Export *ep = export_list(i, code_ix);
+ if (ep == NULL || ep->code[0] != module) {
+ continue;
+ }
+ if (ep->addressv[code_ix] == ep->code+3) {
+ if (ep->code[3] == (BeamInstr) em_apply_bif) {
+ continue;
+ } else if (ep->code[3] ==
+ (BeamInstr) BeamOp(op_i_generic_breakpoint)) {
+ ERTS_SMP_LC_ASSERT(erts_smp_thr_progress_is_blocking());
+ ASSERT(mod_tab_p->curr.num_traced_exports > 0);
+ erts_clear_export_break(mod_tab_p, ep->code+3);
+ ep->addressv[code_ix] = (BeamInstr *) ep->code[4];
+ ep->code[4] = 0;
+ }
+ ASSERT(ep->code[4] == 0);
+ }
+ }
+ ASSERT(mod_tab_p->curr.num_breakpoints == 0);
+ ASSERT(mod_tab_p->curr.num_traced_exports == 0);
}
/*
+ * Update module table.
+ */
+
+ size = stp->loaded_size;
+ erts_total_code_size += size;
+ if (stp->on_load) {
+ inst_p = &mod_tab_p->old;
+ } else {
+ inst_p = &mod_tab_p->curr;
+ }
+ inst_p->code_hdr = stp->hdr;
+ inst_p->code_length = size;
+
+ /*
+ * Update ranges (used for finding a function from a PC value).
+ */
+
+ erts_update_ranges((BeamInstr*)inst_p->code_hdr, size);
+
+ /*
* Ready for the final touch: fixing the export table entries for
* exported and imported functions. This can't fail.
*/
CHKBLK(ERTS_ALC_T_CODE,stp->code);
- final_touch(stp);
+ final_touch(stp, inst_p);
/*
* Loading succeded.
@@ -820,7 +877,6 @@ erts_finish_loading(Binary* magic, Process* c_p,
retval = am_on_load;
}
- load_error:
free_loader_state(magic);
return retval;
}
@@ -1026,9 +1082,9 @@ loader_state_dtor(Binary* magic)
}
static Eterm
-insert_new_code(Process *c_p, ErtsProcLocks c_p_locks,
- Eterm group_leader, Eterm module, BeamCodeHeader* code_hdr,
- Uint size)
+stub_insert_new_code(Process *c_p, ErtsProcLocks c_p_locks,
+ Eterm group_leader, Eterm module,
+ BeamCodeHeader* code_hdr, Uint size)
{
Module* modp;
Eterm retval;
@@ -1548,7 +1604,7 @@ read_literal_table(LoaderState* stp)
erts_factory_heap_frag_init(&factory,
new_literal_fragment(heap_size));
factory.alloc_type = ERTS_ALC_T_PREPARED_CODE;
- val = erts_decode_ext(&factory, &p);
+ val = erts_decode_ext(&factory, &p, 0);
if (is_non_value(val)) {
LoadError1(stp, "literal %d: bad external format", i);
@@ -1559,7 +1615,7 @@ read_literal_table(LoaderState* stp)
}
else {
erts_factory_dummy_init(&factory);
- val = erts_decode_ext(&factory, &p);
+ val = erts_decode_ext(&factory, &p, 0);
if (is_non_value(val)) {
LoadError1(stp, "literal %d: bad external format", i);
}
@@ -2028,42 +2084,47 @@ load_code(LoaderState* stp)
ASSERT(arity == last_op->arity);
do_transform:
- if (stp->genop == NULL) {
- last_op_next = NULL;
- goto get_next_instr;
- }
-
+ ASSERT(stp->genop != NULL);
if (gen_opc[stp->genop->op].transform != -1) {
- int need;
- tmp_op = stp->genop;
-
- for (need = gen_opc[stp->genop->op].min_window-1; need > 0; need--) {
- if (tmp_op == NULL) {
- goto get_next_instr;
- }
- tmp_op = tmp_op->next;
+ if (stp->genop->next == NULL) {
+ /*
+ * Simple heuristic: Most transformations requires
+ * at least two instructions, so make sure that
+ * there are. That will reduce the number of
+ * TE_SHORT_WINDOWs.
+ */
+ goto get_next_instr;
}
switch (transform_engine(stp)) {
case TE_FAIL:
- last_op_next = NULL;
- last_op = NULL;
+ /*
+ * No transformation found. stp->genop != NULL and
+ * last_op_next is still valid. Go ahead and load
+ * the instruction.
+ */
break;
case TE_OK:
+ /*
+ * Some transformation was applied. last_op_next is
+ * no longer valid and stp->genop may be NULL.
+ * Try to transform again.
+ */
+ if (stp->genop == NULL) {
+ last_op_next = &stp->genop;
+ goto get_next_instr;
+ }
last_op_next = NULL;
- last_op = NULL;
goto do_transform;
case TE_SHORT_WINDOW:
- last_op_next = NULL;
- last_op = NULL;
+ /*
+ * No transformation applied. stp->genop != NULL and
+ * last_op_next is still valid. Fetch a new instruction
+ * before trying the transformation again.
+ */
goto get_next_instr;
}
}
- if (stp->genop == NULL) {
- last_op_next = NULL;
- goto get_next_instr;
- }
-
/*
* From the collected generic instruction, find the specific
* instruction.
@@ -2584,7 +2645,10 @@ load_code(LoaderState* stp)
{
GenOp* next = stp->genop->next;
FREE_GENOP(stp, stp->genop);
- stp->genop = next;
+ if ((stp->genop = next) == NULL) {
+ last_op_next = &stp->genop;
+ goto get_next_instr;
+ }
goto do_transform;
}
}
@@ -2728,10 +2792,10 @@ mixed_types(LoaderState* stp, GenOpArg Size, GenOpArg* Rest)
}
static int
-same_label(LoaderState* stp, GenOpArg Target, GenOpArg Label)
+is_killed_apply(LoaderState* stp, GenOpArg Reg, GenOpArg Live)
{
- return Target.type = TAG_f && Label.type == TAG_u &&
- Target.val == Label.val;
+ return Reg.type == TAG_x && Live.type == TAG_u &&
+ Live.val+2 <= Reg.val;
}
static int
@@ -4692,14 +4756,13 @@ freeze_code(LoaderState* stp)
}
static void
-final_touch(LoaderState* stp)
+final_touch(LoaderState* stp, struct erl_module_instance* inst_p)
{
int i;
int on_load = stp->on_load;
unsigned catches;
Uint index;
BeamInstr* codev = stp->codev;
- Module* modp;
/*
* Allocate catch indices and fix up all catch_yf instructions.
@@ -4714,8 +4777,7 @@ final_touch(LoaderState* stp)
codev[index+2] = make_catch(catches);
index = next;
}
- modp = erts_put_module(stp->module);
- modp->curr.catches = catches;
+ inst_p->catches = catches;
/*
* Export functions.
@@ -4735,10 +4797,10 @@ final_touch(LoaderState* stp)
ep->addressv[erts_staging_code_ix()] = address;
} else {
/*
- * Don't make any of the exported functions
- * callable yet.
+ * on_load: Don't make any of the exported functions
+ * callable yet. Keep any function in the current
+ * code callable.
*/
- ep->addressv[erts_staging_code_ix()] = ep->code+3;
ep->code[4] = (BeamInstr) address;
}
}
@@ -4798,31 +4860,25 @@ transform_engine(LoaderState* st)
Uint op;
int ap; /* Current argument. */
Uint* restart; /* Where to restart if current match fails. */
- GenOpArg def_vars[TE_MAX_VARS]; /* Default buffer for variables. */
- GenOpArg* var = def_vars;
- int num_vars = 0;
+ GenOpArg var[TE_MAX_VARS]; /* Buffer for variables. */
+ GenOpArg* rest_args = NULL;
+ int num_rest_args = 0;
int i; /* General index. */
Uint mask;
GenOp* instr;
+ GenOp* first = st->genop;
+ GenOp* keep = NULL;
Uint* pc;
- int rval;
static Uint restart_fail[1] = {TOP_fail};
- ASSERT(gen_opc[st->genop->op].transform != -1);
- pc = op_transform + gen_opc[st->genop->op].transform;
- restart = pc;
+ ASSERT(gen_opc[first->op].transform != -1);
+ restart = op_transform + gen_opc[first->op].transform;
restart:
- if (var != def_vars) {
- erts_free(ERTS_ALC_T_LOADER_TMP, (void *) var);
- var = def_vars;
- }
ASSERT(restart != NULL);
pc = restart;
ASSERT(*pc < NUM_TOPS); /* Valid instruction? */
- instr = st->genop;
-
-#define RETURN(r) rval = (r); goto do_return;
+ instr = first;
#ifdef DEBUG
restart = NULL;
@@ -4840,7 +4896,7 @@ transform_engine(LoaderState* st)
* We'll need at least one more instruction to decide whether
* this combination matches or not.
*/
- RETURN(TE_SHORT_WINDOW);
+ return TE_SHORT_WINDOW;
}
if (*pc++ != instr->op)
goto restart;
@@ -5002,19 +5058,9 @@ transform_engine(LoaderState* st)
#if defined(TOP_rest_args)
case TOP_rest_args:
{
- int n = *pc++;
int formal_arity = gen_opc[instr->op].arity;
- int j = formal_arity;
-
- num_vars = n + (instr->arity - formal_arity);
- var = erts_alloc(ERTS_ALC_T_LOADER_TMP,
- num_vars * sizeof(GenOpArg));
- for (i = 0; i < n; i++) {
- var[i] = def_vars[i];
- }
- while (i < num_vars) {
- var[i++] = instr->a[j++];
- }
+ num_rest_args = instr->arity - formal_arity;
+ rest_args = instr->a + formal_arity;
}
break;
#endif
@@ -5023,21 +5069,22 @@ transform_engine(LoaderState* st)
break;
case TOP_commit:
instr = instr->next; /* The next_instr was optimized away. */
-
- /*
- * The left-hand side of this transformation matched.
- * Delete all matched instructions.
- */
- while (st->genop != instr) {
- GenOp* next = st->genop->next;
- FREE_GENOP(st, st->genop);
- st->genop = next;
- }
+ keep = instr;
+ st->genop = instr;
#ifdef DEBUG
instr = 0;
#endif
break;
-
+#if defined(TOP_keep)
+ case TOP_keep:
+ /* Keep the current instruction unchanged. */
+ keep = instr;
+ st->genop = instr;
+#ifdef DEBUG
+ instr = 0;
+#endif
+ break;
+#endif
#if defined(TOP_call_end)
case TOP_call_end:
{
@@ -5062,22 +5109,19 @@ transform_engine(LoaderState* st)
lastp = &((*lastp)->next);
}
- instr = instr->next; /* The next_instr was optimized away. */
-
- /*
- * The left-hand side of this transformation matched.
- * Delete all matched instructions.
- */
- while (st->genop != instr) {
- GenOp* next = st->genop->next;
- FREE_GENOP(st, st->genop);
- st->genop = next;
- }
- *lastp = st->genop;
+ keep = instr->next; /* The next_instr was optimized away. */
+ *lastp = keep;
st->genop = new_instr;
}
- RETURN(TE_OK);
+ /* FALLTHROUGH */
#endif
+ case TOP_end:
+ while (first != keep) {
+ GenOp* next = first->next;
+ FREE_GENOP(st, first);
+ first = next;
+ }
+ return TE_OK;
case TOP_new_instr:
/*
* Note that the instructions are generated in reverse order.
@@ -5089,6 +5133,12 @@ transform_engine(LoaderState* st)
instr->arity = gen_opc[op].arity;
ap = 0;
break;
+#ifdef TOP_rename
+ case TOP_rename:
+ instr->op = op = *pc++;
+ instr->arity = gen_opc[op].arity;
+ return TE_OK;
+#endif
case TOP_store_type:
i = *pc++;
instr->a[ap].type = i;
@@ -5108,14 +5158,10 @@ transform_engine(LoaderState* st)
#if defined(TOP_store_rest_args)
case TOP_store_rest_args:
{
- int n = *pc++;
- int num_extra = num_vars - n;
-
- ASSERT(n <= num_vars);
- GENOP_ARITY(instr, instr->arity+num_extra);
+ GENOP_ARITY(instr, instr->arity+num_rest_args);
memcpy(instr->a, instr->def_args, ap*sizeof(GenOpArg));
- memcpy(instr->a+ap, var+n, num_extra*sizeof(GenOpArg));
- ap += num_extra;
+ memcpy(instr->a+ap, rest_args, num_rest_args*sizeof(GenOpArg));
+ ap += num_rest_args;
}
break;
#endif
@@ -5127,21 +5173,12 @@ transform_engine(LoaderState* st)
case TOP_try_me_else_fail:
restart = restart_fail;
break;
- case TOP_end:
- RETURN(TE_OK);
case TOP_fail:
- RETURN(TE_FAIL);
+ return TE_FAIL;
default:
ASSERT(0);
}
}
-#undef RETURN
-
- do_return:
- if (var != def_vars) {
- erts_free(ERTS_ALC_T_LOADER_TMP, (void *) var);
- }
- return rval;
}
static void
@@ -5719,7 +5756,7 @@ attributes_for_module(Process* p, /* Process whose heap to use. */
if (ext != NULL) {
ErtsHeapFactory factory;
erts_factory_proc_prealloc_init(&factory, p, code_hdr->attr_size_on_heap);
- result = erts_decode_ext(&factory, &ext);
+ result = erts_decode_ext(&factory, &ext, 0);
if (is_value(result)) {
erts_factory_close(&factory);
}
@@ -5742,7 +5779,7 @@ compilation_info_for_module(Process* p, /* Process whose heap to use. */
if (ext != NULL) {
ErtsHeapFactory factory;
erts_factory_proc_prealloc_init(&factory, p, code_hdr->compile_size_on_heap);
- result = erts_decode_ext(&factory, &ext);
+ result = erts_decode_ext(&factory, &ext, 0);
if (is_value(result)) {
erts_factory_close(&factory);
}
@@ -6438,7 +6475,8 @@ erts_make_stub_module(Process* p, Eterm Mod, Eterm Beam, Eterm Info)
* Insert the module in the module table.
*/
- rval = insert_new_code(p, 0, p->group_leader, Mod, code_hdr, code_size);
+ rval = stub_insert_new_code(p, 0, p->group_leader, Mod,
+ code_hdr, code_size);
if (rval != NIL) {
goto error;
}
diff --git a/erts/emulator/beam/beam_load.h b/erts/emulator/beam/beam_load.h
index 22ab71c868..fd2dd97fee 100644
--- a/erts/emulator/beam/beam_load.h
+++ b/erts/emulator/beam/beam_load.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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.
@@ -33,7 +33,6 @@ typedef struct gen_op_entry {
int specific;
int num_specific;
int transform;
- int min_window;
} GenOpEntry;
extern GenOpEntry gen_opc[];
diff --git a/erts/emulator/beam/beam_ranges.c b/erts/emulator/beam/beam_ranges.c
index 54c337ee72..55342a38c6 100644
--- a/erts/emulator/beam/beam_ranges.c
+++ b/erts/emulator/beam/beam_ranges.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2012. All Rights Reserved.
+ * Copyright Ericsson AB 2012-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.
diff --git a/erts/emulator/beam/benchmark.c b/erts/emulator/beam/benchmark.c
index 44f5c760c2..c8409784ef 100644
--- a/erts/emulator/beam/benchmark.c
+++ b/erts/emulator/beam/benchmark.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2002-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.
diff --git a/erts/emulator/beam/benchmark.h b/erts/emulator/beam/benchmark.h
index 0fb0b93f12..0272896f4f 100644
--- a/erts/emulator/beam/benchmark.h
+++ b/erts/emulator/beam/benchmark.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2002-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.
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index 37bb28c6f8..eed0702688 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -123,15 +123,12 @@ static int insert_internal_link(Process* p, Eterm rpid)
erts_add_link(&ERTS_P_LINKS(p), LINK_PID, rp->common.id);
erts_add_link(&ERTS_P_LINKS(rp), LINK_PID, p->common.id);
- ASSERT(is_nil(ERTS_TRACER_PROC(p))
- || is_internal_pid(ERTS_TRACER_PROC(p))
- || is_internal_port(ERTS_TRACER_PROC(p)));
+ ASSERT(IS_TRACER_VALID(ERTS_TRACER(p)));
if (IS_TRACED(p)) {
if (ERTS_TRACE_FLAGS(p) & (F_TRACE_SOL|F_TRACE_SOL1)) {
ERTS_TRACE_FLAGS(rp) |= (ERTS_TRACE_FLAGS(p) & TRACEE_FLAGS);
- ERTS_TRACER_PROC(rp) = ERTS_TRACER_PROC(p); /* maybe steal */
-
+ erts_tracer_replace(&rp->common, ERTS_TRACER(p));
if (ERTS_TRACE_FLAGS(p) & F_TRACE_SOL1) { /* maybe override */
ERTS_TRACE_FLAGS(rp) &= ~(F_TRACE_SOL1 | F_TRACE_SOL);
ERTS_TRACE_FLAGS(p) &= ~(F_TRACE_SOL1 | F_TRACE_SOL);
@@ -140,7 +137,8 @@ static int insert_internal_link(Process* p, Eterm rpid)
}
}
if (IS_TRACED_FL(rp, F_TRACE_PROCS))
- trace_proc(p, rp, am_getting_linked, p->common.id);
+ trace_proc(p, p == rp ? rp_locks : ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_LINK,
+ rp, am_getting_linked, p->common.id);
if (p == rp)
erts_smp_proc_unlock(p, rp_locks & ~ERTS_PROC_LOCK_MAIN);
@@ -159,7 +157,7 @@ BIF_RETTYPE link_1(BIF_ALIST_1)
DistEntry *dep;
if (IS_TRACED_FL(BIF_P, F_TRACE_PROCS)) {
- trace_proc(BIF_P, BIF_P, am_link, BIF_ARG_1);
+ trace_proc(BIF_P, ERTS_PROC_LOCK_MAIN, BIF_P, am_link, BIF_ARG_1);
}
/* check that the pid or port which is our argument is OK */
@@ -613,7 +611,7 @@ erts_queue_monitor_message(Process *p,
ref_copy = copy_struct(ref, ref_size, &hp, ohp);
tup = TUPLE5(hp, am_DOWN, ref_copy, type, item_copy, reason_copy);
- erts_queue_message(p, p_locksp, msgp, tup, NIL);
+ erts_queue_message(p, *p_locksp, msgp, tup, am_system);
}
static BIF_RETTYPE
@@ -1001,6 +999,7 @@ BIF_RETTYPE unlink_1(BIF_ALIST_1)
Process *rp;
DistEntry *dep;
ErtsLink *l = NULL, *rl = NULL;
+ ErtsProcLocks cp_locks = ERTS_PROC_LOCK_MAIN;
/*
* SMP specific note concerning incoming exit signals:
@@ -1015,7 +1014,7 @@ BIF_RETTYPE unlink_1(BIF_ALIST_1)
*/
if (IS_TRACED_FL(BIF_P, F_TRACE_PROCS)) {
- trace_proc(BIF_P, BIF_P, am_unlink, BIF_ARG_1);
+ trace_proc(BIF_P, cp_locks, BIF_P, am_unlink, BIF_ARG_1);
}
if (is_internal_port(BIF_ARG_1)) {
@@ -1120,10 +1119,10 @@ BIF_RETTYPE unlink_1(BIF_ALIST_1)
erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_LINK|ERTS_PROC_LOCK_STATUS);
+ cp_locks |= ERTS_PROC_LOCK_LINK|ERTS_PROC_LOCK_STATUS;
+
/* get process struct */
- rp = erts_pid2proc_opt(BIF_P, (ERTS_PROC_LOCK_MAIN
- | ERTS_PROC_LOCK_LINK
- | ERTS_PROC_LOCK_STATUS),
+ rp = erts_pid2proc_opt(BIF_P, cp_locks,
BIF_ARG_1, ERTS_PROC_LOCK_LINK,
ERTS_P2P_FLG_ALLOW_OTHER_X);
@@ -1149,14 +1148,17 @@ BIF_RETTYPE unlink_1(BIF_ALIST_1)
erts_destroy_link(rl);
if (IS_TRACED_FL(rp, F_TRACE_PROCS) && rl != NULL) {
- trace_proc(BIF_P, rp, am_getting_unlinked, BIF_P->common.id);
+ erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_STATUS);
+ cp_locks &= ~ERTS_PROC_LOCK_STATUS;
+ trace_proc(BIF_P, (ERTS_PROC_LOCK_MAIN | ERTS_PROC_LOCK_LINK),
+ rp, am_getting_unlinked, BIF_P->common.id);
}
if (rp != BIF_P)
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
}
- erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_LINK|ERTS_PROC_LOCK_STATUS);
+ erts_smp_proc_unlock(BIF_P, cp_locks & ~ERTS_PROC_LOCK_MAIN);
BIF_RET(am_true);
@@ -1567,7 +1569,32 @@ static BIF_RETTYPE process_flag_aux(Process *BIF_P,
scb->n = 0;
}
- scb = ERTS_PROC_SET_SAVED_CALLS_BUF(rp, ERTS_PROC_LOCK_MAIN, scb);
+#ifdef HIPE
+ if (rp->flags & F_HIPE_MODE) {
+ ASSERT(!ERTS_PROC_GET_SAVED_CALLS_BUF(rp));
+ scb = ERTS_PROC_SET_SUSPENDED_SAVED_CALLS_BUF(rp, scb);
+ }
+ else
+#endif
+ {
+#ifdef HIPE
+ ASSERT(!ERTS_PROC_GET_SUSPENDED_SAVED_CALLS_BUF(rp));
+#endif
+ scb = ERTS_PROC_SET_SAVED_CALLS_BUF(rp, scb);
+ if (rp == BIF_P && ((scb && i == 0) || (!scb && i != 0))) {
+ /* Adjust fcalls to match save calls setting... */
+ if (i == 0)
+ BIF_P->fcalls += CONTEXT_REDS; /* disabled it */
+ else
+ BIF_P->fcalls -= CONTEXT_REDS; /* enabled it */
+
+ /*
+ * Make sure we reschedule immediately so the
+ * change take effect at once.
+ */
+ ERTS_VBUMP_ALL_REDS(BIF_P);
+ }
+ }
if (!scb)
old_value = make_small(0);
@@ -1576,12 +1603,7 @@ static BIF_RETTYPE process_flag_aux(Process *BIF_P,
erts_free(ERTS_ALC_T_CALLS_BUF, (void *) scb);
}
- /* Make sure the process in question is rescheduled
- immediately, if it's us, so the call saving takes effect. */
- if (rp == BIF_P)
- BIF_RET2(old_value, CONTEXT_REDS);
- else
- BIF_RET(old_value);
+ BIF_RET(old_value);
}
error:
@@ -1595,9 +1617,7 @@ BIF_RETTYPE process_flag_2(BIF_ALIST_2)
if (is_not_atom(BIF_ARG_2)) {
goto error;
}
- old_value = erts_proc_set_error_handler(BIF_P,
- ERTS_PROC_LOCK_MAIN,
- BIF_ARG_2);
+ old_value = erts_proc_set_error_handler(BIF_P, BIF_ARG_2);
BIF_RET(old_value);
}
else if (BIF_ARG_1 == am_priority) {
@@ -1622,14 +1642,17 @@ BIF_RETTYPE process_flag_2(BIF_ALIST_2)
* true. For more info, see implementation of
* erts_send_exit_signal().
*/
+ erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCKS_XSIG_SEND);
if (trap_exit)
state = erts_smp_atomic32_read_bor_mb(&BIF_P->state,
ERTS_PSFLG_TRAP_EXIT);
else
state = erts_smp_atomic32_read_band_mb(&BIF_P->state,
~ERTS_PSFLG_TRAP_EXIT);
+ erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCKS_XSIG_SEND);
+
#ifdef ERTS_SMP
- if (ERTS_PROC_PENDING_EXIT(BIF_P)) {
+ if (state & ERTS_PSFLG_PENDING_EXIT) {
erts_handle_pending_exit(BIF_P, ERTS_PROC_LOCK_MAIN);
ERTS_BIF_EXITED(BIF_P);
}
@@ -1733,7 +1756,9 @@ BIF_RETTYPE process_flag_2(BIF_ALIST_2)
ERTS_TRACE_FLAGS(BIF_P) &= ~F_SENSITIVE;
}
erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCKS_ALL_MINOR);
- BIF_RET(old_value);
+ /* make sure to bump all reds so that we get
+ rescheduled immediately so setting takes effect */
+ BIF_RET2(old_value, CONTEXT_REDS);
}
else if (BIF_ARG_1 == am_monitor_nodes) {
/*
@@ -1772,10 +1797,18 @@ BIF_RETTYPE process_flag_3(BIF_ALIST_3)
Process *rp;
Eterm res;
- if ((rp = erts_pid2proc(BIF_P, ERTS_PROC_LOCK_MAIN,
- BIF_ARG_1, ERTS_PROC_LOCK_MAIN)) == NULL) {
+#ifdef ERTS_SMP
+ rp = erts_pid2proc_not_running(BIF_P, ERTS_PROC_LOCK_MAIN,
+ BIF_ARG_1, ERTS_PROC_LOCK_MAIN);
+ if (rp == ERTS_PROC_LOCK_BUSY)
+ ERTS_BIF_YIELD3(bif_export[BIF_process_flag_3], BIF_P,
+ BIF_ARG_1, BIF_ARG_2, BIF_ARG_3);
+#else
+ rp = erts_proc_lookup(BIF_ARG_1);
+#endif
+
+ if (!rp)
BIF_ERROR(BIF_P, BADARG);
- }
res = process_flag_aux(BIF_P, rp, BIF_ARG_2, BIF_ARG_3);
@@ -1908,7 +1941,7 @@ static Sint remote_send(Process *p, DistEntry *dep,
}
if (res >= 0) {
- if (IS_TRACED(p))
+ if (IS_TRACED_FL(p, F_TRACE_SEND))
trace_send(p, full_to, msg);
if (ERTS_PROC_GET_SAVED_CALLS_BUF(p))
save_calls(p, &exp_send);
@@ -1927,7 +1960,7 @@ do_send(Process *p, Eterm to, Eterm msg, Eterm *refp, ErtsSendContext* ctx)
Eterm* tp;
if (is_internal_pid(to)) {
- if (IS_TRACED(p))
+ if (IS_TRACED_FL(p, F_TRACE_SEND))
trace_send(p, to, msg);
if (ERTS_PROC_GET_SAVED_CALLS_BUF(p))
save_calls(p, &exp_send);
@@ -1956,7 +1989,7 @@ do_send(Process *p, Eterm to, Eterm msg, Eterm *refp, ErtsSendContext* ctx)
rp = erts_proc_lookup_raw(id);
if (rp) {
- if (IS_TRACED(p))
+ if (IS_TRACED_FL(p, F_TRACE_SEND))
trace_send(p, to, msg);
if (ERTS_PROC_GET_SAVED_CALLS_BUF(p))
save_calls(p, &exp_send);
@@ -1972,7 +2005,7 @@ do_send(Process *p, Eterm to, Eterm msg, Eterm *refp, ErtsSendContext* ctx)
goto port_common;
}
- if (IS_TRACED(p))
+ if (IS_TRACED_FL(p, F_TRACE_SEND))
trace_send(p, to, msg);
if (ERTS_PROC_GET_SAVED_CALLS_BUF(p))
save_calls(p, &exp_send);
@@ -2003,11 +2036,20 @@ do_send(Process *p, Eterm to, Eterm msg, Eterm *refp, ErtsSendContext* ctx)
port_common:
ret_val = 0;
-
+
if (pt) {
int ps_flags = ctx->suspend ? 0 : ERTS_PORT_SIG_FLG_NOSUSPEND;
*refp = NIL;
+ if (IS_TRACED_FL(p, F_TRACE_SEND)) /* trace once only !! */
+ trace_send(p, portid, msg);
+
+ if (have_seqtrace(SEQ_TRACE_TOKEN(p))) {
+ seq_trace_update_send(p);
+ seq_trace_output(SEQ_TRACE_TOKEN(p), msg,
+ SEQ_TRACE_SEND, portid, p);
+ }
+
switch (erts_port_command(p, ps_flags, pt, msg, refp)) {
case ERTS_PORT_OP_CALLER_EXIT:
/* We are exiting... */
@@ -2040,18 +2082,10 @@ do_send(Process *p, Eterm to, Eterm msg, Eterm *refp, ErtsSendContext* ctx)
break;
}
}
-
- if (IS_TRACED(p)) /* trace once only !! */
- trace_send(p, portid, msg);
+
if (ERTS_PROC_GET_SAVED_CALLS_BUF(p))
save_calls(p, &exp_send);
-
- if (have_seqtrace(SEQ_TRACE_TOKEN(p))) {
- seq_trace_update_send(p);
- seq_trace_output(SEQ_TRACE_TOKEN(p), msg,
- SEQ_TRACE_SEND, portid, p);
- }
-
+
if (ERTS_PROC_IS_EXITING(p)) {
KILL_CATCHES(p); /* Must exit */
return SEND_USER_ERROR;
@@ -2074,7 +2108,7 @@ do_send(Process *p, Eterm to, Eterm msg, Eterm *refp, ErtsSendContext* ctx)
if (dep == erts_this_dist_entry) {
Eterm id;
erts_deref_dist_entry(dep);
- if (IS_TRACED(p))
+ if (IS_TRACED_FL(p, F_TRACE_SEND))
trace_send(p, to, msg);
if (ERTS_PROC_GET_SAVED_CALLS_BUF(p))
save_calls(p, &exp_send);
@@ -2105,7 +2139,7 @@ do_send(Process *p, Eterm to, Eterm msg, Eterm *refp, ErtsSendContext* ctx)
}
return ret;
} else {
- if (IS_TRACED(p)) /* XXX Is this really neccessary ??? */
+ if (IS_TRACED_FL(p, F_TRACE_SEND))
trace_send(p, to, msg);
if (ERTS_PROC_GET_SAVED_CALLS_BUF(p))
save_calls(p, &exp_send);
@@ -4336,12 +4370,34 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2)
} else if (BIF_ARG_1 == am_trace_control_word) {
BIF_RET(db_set_trace_control_word(BIF_P, BIF_ARG_2));
} else if (BIF_ARG_1 == am_sequential_tracer) {
- Eterm old_value = erts_set_system_seq_tracer(BIF_P,
- ERTS_PROC_LOCK_MAIN,
- BIF_ARG_2);
- if (old_value != THE_NON_VALUE) {
- BIF_RET(old_value);
- }
+ ErtsTracer new_seq_tracer, old_seq_tracer;
+ Eterm ret;
+
+ if (BIF_ARG_2 == am_false)
+ new_seq_tracer = erts_tracer_nil;
+ else
+ new_seq_tracer = erts_term_to_tracer(THE_NON_VALUE, BIF_ARG_2);
+
+ if (new_seq_tracer == THE_NON_VALUE)
+ goto error;
+
+ old_seq_tracer = erts_set_system_seq_tracer(BIF_P,
+ ERTS_PROC_LOCK_MAIN,
+ new_seq_tracer);
+
+ ERTS_TRACER_CLEAR(&new_seq_tracer);
+
+ if (old_seq_tracer == THE_NON_VALUE)
+ goto error;
+
+ if (ERTS_TRACER_IS_NIL(old_seq_tracer))
+ BIF_RET(am_false);
+
+ ret = erts_tracer_to_term(BIF_P, old_seq_tracer);
+
+ ERTS_TRACER_CLEAR(&old_seq_tracer);
+
+ BIF_RET(ret);
} else if (BIF_ARG_1 == make_small(1)) {
int i, max;
ErtsMessage* mp;
@@ -4678,7 +4734,7 @@ skip_current_msgq(Process *c_p)
res = 0;
}
else {
- ERTS_SMP_MSGQ_MV_INQ2PRIVQ(c_p);
+ ERTS_SMP_MSGQ_MV_INQ2PRIVQ(c_p);
c_p->msg.save = c_p->msg.last;
res = 1;
}
diff --git a/erts/emulator/beam/bif.h b/erts/emulator/beam/bif.h
index 46af552b39..5d751dd67d 100644
--- a/erts/emulator/beam/bif.h
+++ b/erts/emulator/beam/bif.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -52,6 +52,7 @@ extern Export *erts_convert_time_unit_trap;
(p)->fcalls = 0; \
else \
(p)->fcalls = -CONTEXT_REDS; \
+ ASSERT(ERTS_BIF_REDS_LEFT((p)) == 0); \
} while(0)
#define ERTS_VBUMP_ALL_REDS_INTERNAL(p, fcalls) \
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index a6670c10e8..872f0f9b2a 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2013. All Rights Reserved.
+# Copyright Ericsson AB 1996-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.
@@ -181,9 +181,8 @@ bif erlang:port_set_data/2
bif erlang:port_get_data/1
# Tracing & debugging.
-bif erlang:trace_pattern/2
-bif erlang:trace_pattern/3
-bif erlang:trace/3
+bif erts_internal:trace_pattern/3
+bif erts_internal:trace/3
bif erlang:trace_info/2
bif erlang:trace_delivered/1
bif erlang:seq_trace/2
@@ -653,6 +652,8 @@ bif erts_debug:size_shared/1
bif erts_debug:copy_shared/1
bif erlang:has_prepared_code_on_load/1
+bif maps:take/2
+
#
# Obsolete
#
diff --git a/erts/emulator/beam/big.c b/erts/emulator/beam/big.c
index c738a9ecf5..4baee7900b 100644
--- a/erts/emulator/beam/big.c
+++ b/erts/emulator/beam/big.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/beam/big.h b/erts/emulator/beam/big.h
index ee51e5d313..464acd67f6 100644
--- a/erts/emulator/beam/big.h
+++ b/erts/emulator/beam/big.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/beam/binary.c b/erts/emulator/beam/binary.c
index 3fd284b589..cfd8fbe2f5 100644
--- a/erts/emulator/beam/binary.c
+++ b/erts/emulator/beam/binary.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c
index 8c039ef132..d02c6828f9 100644
--- a/erts/emulator/beam/break.c
+++ b/erts/emulator/beam/break.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -347,8 +347,11 @@ print_process_info(int to, void *to_arg, Process *p)
static void
print_garb_info(int to, void *to_arg, Process* p)
{
+#ifdef ERTS_SMP
/* ERTS_SMP: A scheduler is probably concurrently doing gc... */
-#ifndef ERTS_SMP
+ if (!ERTS_IS_CRASH_DUMPING)
+ return;
+#endif
erts_print(to, to_arg, "New heap start: %bpX\n", p->heap);
erts_print(to, to_arg, "New heap top: %bpX\n", p->htop);
erts_print(to, to_arg, "Stack top: %bpX\n", p->stop);
@@ -356,7 +359,6 @@ print_garb_info(int to, void *to_arg, Process* p)
erts_print(to, to_arg, "Old heap start: %bpX\n", OLD_HEAP(p));
erts_print(to, to_arg, "Old heap top: %bpX\n", OLD_HTOP(p));
erts_print(to, to_arg, "Old heap end: %bpX\n", OLD_HEND(p));
-#endif
}
void
@@ -684,7 +686,7 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args)
crash dump. */
erts_thr_progress_fatal_error_block(&tpd_buf);
-#ifdef ERTS_THR_HAVE_SIG_FUNCS
+#ifdef ERTS_SYS_SUSPEND_SIGNAL
/*
* We suspend all scheduler threads so that we can dump some
* data about the currently running processes and scheduler data.
@@ -818,7 +820,7 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args)
#ifdef ERTS_SMP
-#if defined(ERTS_THR_HAVE_SIG_FUNCS)
+#ifdef ERTS_SYS_SUSPEND_SIGNAL
/* We resume all schedulers so that we are in a known safe state
when we write the rest of the crash dump */
diff --git a/erts/emulator/beam/code_ix.c b/erts/emulator/beam/code_ix.c
index 1b0968c55c..ec6267711b 100644
--- a/erts/emulator/beam/code_ix.c
+++ b/erts/emulator/beam/code_ix.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2012. All Rights Reserved.
+ * Copyright Ericsson AB 2012-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.
@@ -94,6 +94,7 @@ void erts_commit_staging_code_ix(void)
ix = (ix + 1) % ERTS_NUM_CODE_IX;
erts_smp_atomic32_set_nob(&the_staging_code_index, ix);
export_staging_unlock();
+ erts_tracer_nif_clear();
CIX_TRACE("activate");
}
diff --git a/erts/emulator/beam/code_ix.h b/erts/emulator/beam/code_ix.h
index 7a66211a5b..584a605771 100644
--- a/erts/emulator/beam/code_ix.h
+++ b/erts/emulator/beam/code_ix.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2012-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2012-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.
diff --git a/erts/emulator/beam/copy.c b/erts/emulator/beam/copy.c
index b38ebe066b..ccc4cbad43 100644
--- a/erts/emulator/beam/copy.c
+++ b/erts/emulator/beam/copy.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2012. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index fa385f105d..09c83f1117 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -337,7 +337,7 @@ static void doit_link_net_exits_sub(ErtsLink *sublnk, void *vlnecp)
erts_destroy_link(rlnk);
if (xres >= 0 && IS_TRACED_FL(rp, F_TRACE_PROCS)) {
/* We didn't exit the process and it is traced */
- trace_proc(NULL, rp, am_getting_unlinked, sublnk->pid);
+ trace_proc(NULL, 0, rp, am_getting_unlinked, sublnk->pid);
}
}
erts_smp_proc_unlock(rp, rp_locks);
@@ -397,7 +397,7 @@ static void doit_node_link_net_exits(ErtsLink *lnk, void *vnecp)
msgp = erts_alloc_message_heap(rp, &rp_locks,
3, &hp, &ohp);
tup = TUPLE2(hp, am_nodedown, name);
- erts_queue_message(rp, &rp_locks, msgp, tup, NIL);
+ erts_queue_message(rp, rp_locks, msgp, tup, am_system);
}
erts_smp_proc_unlock(rp, rp_locks);
}
@@ -906,9 +906,9 @@ erts_dsig_send_msg(Eterm remote, Eterm message, ErtsSendContext* ctx)
if (token != NIL)
ctl = TUPLE4(&ctx->ctl_heap[0],
- make_small(DOP_SEND_TT), am_Cookie, remote, token);
+ make_small(DOP_SEND_TT), am_Empty, remote, token);
else
- ctl = TUPLE3(&ctx->ctl_heap[0], make_small(DOP_SEND), am_Cookie, remote);
+ ctl = TUPLE3(&ctx->ctl_heap[0], make_small(DOP_SEND), am_Empty, remote);
DTRACE6(message_send, sender_name, receiver_name,
msize, tok_label, tok_lastcnt, tok_serial);
DTRACE7(message_send_remote, sender_name, node_name, receiver_name,
@@ -963,10 +963,10 @@ erts_dsig_send_reg_msg(Eterm remote_name, Eterm message,
if (token != NIL)
ctl = TUPLE5(&ctx->ctl_heap[0], make_small(DOP_REG_SEND_TT),
- sender->common.id, am_Cookie, remote_name, token);
+ sender->common.id, am_Empty, remote_name, token);
else
ctl = TUPLE4(&ctx->ctl_heap[0], make_small(DOP_REG_SEND),
- sender->common.id, am_Cookie, remote_name);
+ sender->common.id, am_Empty, remote_name);
DTRACE6(message_send, sender_name, receiver_name,
msize, tok_label, tok_lastcnt, tok_serial);
DTRACE7(message_send_remote, sender_name, node_name, receiver_name,
@@ -1275,7 +1275,7 @@ int erts_net_message(Port *prt,
erts_smp_de_links_unlock(dep);
if (IS_TRACED_FL(rp, F_TRACE_PROCS))
- trace_proc(NULL, rp, am_getting_linked, from);
+ trace_proc(NULL, 0, rp, am_getting_linked, from);
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
break;
@@ -1300,7 +1300,7 @@ int erts_net_message(Port *prt,
lnk = erts_remove_link(&ERTS_P_LINKS(rp), from);
if (IS_TRACED_FL(rp, F_TRACE_PROCS) && lnk != NULL) {
- trace_proc(NULL, rp, am_getting_unlinked, from);
+ trace_proc(NULL, 0, rp, am_getting_unlinked, from);
}
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
@@ -1456,7 +1456,7 @@ int erts_net_message(Port *prt,
token = copy_struct(token, token_size, &hp, ohp);
}
- erts_queue_dist_message(rp, &locks, ede_copy, token);
+ erts_queue_dist_message(rp, locks, ede_copy, token, from);
if (locks)
erts_smp_proc_unlock(rp, locks);
}
@@ -1505,7 +1505,7 @@ int erts_net_message(Port *prt,
token = copy_struct(token, token_size, &hp, ohp);
}
- erts_queue_dist_message(rp, &locks, ede_copy, token);
+ erts_queue_dist_message(rp, locks, ede_copy, token, tuple[2]);
if (locks)
erts_smp_proc_unlock(rp, locks);
}
@@ -1628,7 +1628,11 @@ int erts_net_message(Port *prt,
ERTS_XSIG_FLG_IGN_KILL);
if (xres >= 0 && IS_TRACED_FL(rp, F_TRACE_PROCS)) {
/* We didn't exit the process and it is traced */
- trace_proc(NULL, rp, am_getting_unlinked, from);
+ if (rp_locks & ERTS_PROC_LOCKS_XSIG_SEND) {
+ erts_smp_proc_unlock(rp, ERTS_PROC_LOCKS_XSIG_SEND);
+ rp_locks &= ~ERTS_PROC_LOCKS_XSIG_SEND;
+ }
+ trace_proc(NULL, 0, rp, am_getting_unlinked, from);
}
}
erts_smp_proc_unlock(rp, rp_locks);
@@ -1719,7 +1723,7 @@ decode_error:
}
data_error:
UnUseTmpHeapNoproc(DIST_CTL_DEFAULT_SIZE);
- erts_deliver_port_exit(prt, dep->cid, am_killed, 0);
+ erts_deliver_port_exit(prt, dep->cid, am_killed, 0, 1);
ERTS_SMP_CHK_NO_PROC_LOCKS;
return -1;
}
@@ -1963,7 +1967,7 @@ dist_port_command(Port *prt, ErtsDistOutputBuf *obuf)
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
if (size > (Uint) INT_MAX)
- erts_exit(ERTS_ABORT_EXIT,
+ erts_exit(ERTS_DUMP_EXIT,
"Absurdly large distribution output data buffer "
"(%beu bytes) passed.\n",
size);
@@ -2003,7 +2007,7 @@ dist_port_commandv(Port *prt, ErtsDistOutputBuf *obuf)
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
if (size > (Uint) INT_MAX)
- erts_exit(ERTS_ABORT_EXIT,
+ erts_exit(ERTS_DUMP_EXIT,
"Absurdly large distribution output data buffer "
"(%beu bytes) passed.\n",
size);
@@ -2089,7 +2093,7 @@ erts_dist_command(Port *prt, int reds_limit)
erts_smp_de_runlock(dep);
if (status & ERTS_DE_SFLG_EXITING) {
- erts_deliver_port_exit(prt, prt->common.id, am_killed, 0);
+ erts_deliver_port_exit(prt, prt->common.id, am_killed, 0, 1);
erts_deref_dist_entry(dep);
return reds + ERTS_PORT_REDS_DIST_CMD_EXIT;
}
@@ -3313,7 +3317,7 @@ send_nodes_mon_msg(Process *rp,
}
ASSERT(hend == hp);
- erts_queue_message(rp, rp_locksp, mp, msg, NIL);
+ erts_queue_message(rp, *rp_locksp, mp, msg, am_system);
}
static void
diff --git a/erts/emulator/beam/dist.h b/erts/emulator/beam/dist.h
index fb777d9ac1..e82b416286 100644
--- a/erts/emulator/beam/dist.h
+++ b/erts/emulator/beam/dist.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -43,6 +43,7 @@
#define DFLAG_INTERNAL_TAGS 0x8000
#define DFLAG_UTF8_ATOMS 0x10000
#define DFLAG_MAP_TAG 0x20000
+#define DFLAG_BIG_CREATION 0x40000
/* All flags that should be enabled when term_to_binary/1 is used. */
#define TERM_TO_BINARY_DFLAGS (DFLAG_EXTENDED_REFERENCES \
@@ -51,7 +52,8 @@
| DFLAG_EXTENDED_PIDS_PORTS \
| DFLAG_EXPORT_PTR_TAG \
| DFLAG_BIT_BINARIES \
- | DFLAG_MAP_TAG)
+ | DFLAG_MAP_TAG \
+ | DFLAG_BIG_CREATION)
/* opcodes used in distribution messages */
#define DOP_LINK 1
diff --git a/erts/emulator/beam/dtrace-wrapper.h b/erts/emulator/beam/dtrace-wrapper.h
index d343dc5ab0..6f70d5961e 100644
--- a/erts/emulator/beam/dtrace-wrapper.h
+++ b/erts/emulator/beam/dtrace-wrapper.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Dustin Sallings, Michal Ptaszek, Scott Lystig Fritchie 2011-2012.
+ * Copyright Dustin Sallings, Michal Ptaszek, Scott Lystig Fritchie 2011-2016.
* All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/erts/emulator/beam/elib_memmove.c b/erts/emulator/beam/elib_memmove.c
index d4ca30158e..2f45f69026 100644
--- a/erts/emulator/beam/elib_memmove.c
+++ b/erts/emulator/beam/elib_memmove.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/beam/erl_afit_alloc.c b/erts/emulator/beam/erl_afit_alloc.c
index 4b0541c10e..eda3ad870a 100644
--- a/erts/emulator/beam/erl_afit_alloc.c
+++ b/erts/emulator/beam/erl_afit_alloc.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/beam/erl_afit_alloc.h b/erts/emulator/beam/erl_afit_alloc.h
index ef050ff50e..74258e284a 100644
--- a/erts/emulator/beam/erl_afit_alloc.h
+++ b/erts/emulator/beam/erl_afit_alloc.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c
index 490e0c0915..c367d4162c 100644
--- a/erts/emulator/beam/erl_alloc.c
+++ b/erts/emulator/beam/erl_alloc.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2002-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.
@@ -30,6 +30,7 @@
#endif
#define ERTS_ALLOC_C__
#define ERTS_ALC_INTERNAL__
+#define ERTS_WANT_MEM_MAPPERS
#include "sys.h"
#define ERL_THREADS_EMU_INTERNAL__
#include "erl_threads.h"
@@ -131,8 +132,16 @@ static ErtsAllocatorState_t ets_alloc_state;
static ErtsAllocatorState_t driver_alloc_state;
static ErtsAllocatorState_t fix_alloc_state;
static ErtsAllocatorState_t literal_alloc_state;
+#ifdef ERTS_ALC_A_EXEC
+static ErtsAllocatorState_t exec_alloc_state;
+#endif
static ErtsAllocatorState_t test_alloc_state;
+#define ERTS_ALC_INFO_A_ALLOC_UTIL (ERTS_ALC_A_MAX + 1)
+#define ERTS_ALC_INFO_A_MSEG_ALLOC (ERTS_ALC_A_MAX + 2)
+#define ERTS_ALC_INFO_A_ERTS_MMAP (ERTS_ALC_A_MAX + 3)
+#define ERTS_ALC_INFO_A_MAX ERTS_ALC_INFO_A_ERTS_MMAP
+
typedef struct {
erts_smp_atomic32_t refc;
int only_sz;
@@ -141,13 +150,9 @@ typedef struct {
Process *proc;
Eterm ref;
Eterm ref_heap[REF_THING_SIZE];
- int allocs[ERTS_ALC_A_MAX-ERTS_ALC_A_MIN+1+2];
+ int allocs[ERTS_ALC_INFO_A_MAX - ERTS_ALC_A_MIN + 1 + 1];
} ErtsAllocInfoReq;
-#define ERTS_ALC_INFO_A_ALLOC_UTIL (ERTS_ALC_A_MAX + 1)
-#define ERTS_ALC_INFO_A_MSEG_ALLOC (ERTS_ALC_A_MAX + 2)
-#define ERTS_ALC_INFO_A_MAX ERTS_ALC_INFO_A_MSEG_ALLOC
-
ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(aireq,
ErtsAllocInfoReq,
5,
@@ -216,6 +221,7 @@ typedef struct {
struct au_init driver_alloc;
struct au_init fix_alloc;
struct au_init literal_alloc;
+ struct au_init exec_alloc;
struct au_init test_alloc;
} erts_alc_hndl_args_init_t;
@@ -307,9 +313,9 @@ set_default_literal_alloc_opts(struct au_init *ip)
ip->init.util.name_prefix = "literal_";
ip->init.util.alloc_no = ERTS_ALC_A_LITERAL;
#ifndef SMALL_MEMORY
- ip->init.util.mmbcs = 2*1024*1024; /* Main carrier size */
+ ip->init.util.mmbcs = 1024*1024; /* Main carrier size */
#else
- ip->init.util.mmbcs = 1*1024*1024; /* Main carrier size */
+ ip->init.util.mmbcs = 256*1024; /* Main carrier size */
#endif
ip->init.util.ts = ERTS_ALC_MTA_LITERAL;
ip->init.util.asbcst = 0;
@@ -329,15 +335,48 @@ set_default_literal_alloc_opts(struct au_init *ip)
ip->init.util.sys_dealloc = &erts_alcu_literal_32_sys_dealloc;
#elif defined(ARCH_64)
# ifdef ERTS_HAVE_OS_PHYSICAL_MEMORY_RESERVATION
- ip->init.util.mseg_alloc = &erts_alcu_literal_64_mseg_alloc;
- ip->init.util.mseg_realloc = &erts_alcu_literal_64_mseg_realloc;
- ip->init.util.mseg_dealloc = &erts_alcu_literal_64_mseg_dealloc;
+ ip->init.util.mseg_alloc = &erts_alcu_mmapper_mseg_alloc;
+ ip->init.util.mseg_realloc = &erts_alcu_mmapper_mseg_realloc;
+ ip->init.util.mseg_dealloc = &erts_alcu_mmapper_mseg_dealloc;
+ ip->init.util.mseg_mmapper = &erts_literal_mmapper;
# endif
#else
# error Unknown architecture
#endif
}
+#ifdef ERTS_ALC_A_EXEC
+static void
+set_default_exec_alloc_opts(struct au_init *ip)
+{
+ SET_DEFAULT_ALLOC_OPTS(ip);
+ ip->enable = 1;
+ ip->thr_spec = 0;
+ ip->disable_allowed = 0;
+ ip->thr_spec_allowed = 0;
+ ip->carrier_migration_allowed = 0;
+ ip->atype = BESTFIT;
+ ip->init.bf.ao = 1;
+ ip->init.util.ramv = 0;
+ ip->init.util.mmsbc = 0;
+ ip->init.util.sbct = ~((UWord) 0);
+ ip->init.util.name_prefix = "exec_";
+ ip->init.util.alloc_no = ERTS_ALC_A_EXEC;
+ ip->init.util.mmbcs = 0; /* No main carrier */
+ ip->init.util.ts = ERTS_ALC_MTA_EXEC;
+ ip->init.util.asbcst = 0;
+ ip->init.util.rsbcst = 0;
+ ip->init.util.rsbcmt = 0;
+ ip->init.util.rmbcmt = 0;
+ ip->init.util.acul = 0;
+
+ ip->init.util.mseg_alloc = &erts_alcu_mmapper_mseg_alloc;
+ ip->init.util.mseg_realloc = &erts_alcu_mmapper_mseg_realloc;
+ ip->init.util.mseg_dealloc = &erts_alcu_mmapper_mseg_dealloc;
+ ip->init.util.mseg_mmapper = &erts_exec_mmapper;
+}
+#endif /* ERTS_ALC_A_EXEC */
+
static void
set_default_temp_alloc_opts(struct au_init *ip)
{
@@ -659,6 +698,9 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
set_default_fix_alloc_opts(&init.fix_alloc,
fix_type_sizes);
set_default_literal_alloc_opts(&init.literal_alloc);
+#ifdef ERTS_ALC_A_EXEC
+ set_default_exec_alloc_opts(&init.exec_alloc);
+#endif
set_default_test_alloc_opts(&init.test_alloc);
if (argc && argv)
@@ -688,6 +730,9 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
init.driver_alloc.thr_spec = 0;
init.fix_alloc.thr_spec = 0;
init.literal_alloc.thr_spec = 0;
+#ifdef ERTS_ALC_A_EXEC
+ init.exec_alloc.thr_spec = 0;
+#endif
#endif
/* Make adjustments for carrier migration support */
@@ -701,6 +746,9 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
adjust_carrier_migration_support(&init.driver_alloc);
adjust_carrier_migration_support(&init.fix_alloc);
adjust_carrier_migration_support(&init.literal_alloc);
+#ifdef ERTS_ALC_A_EXEC
+ adjust_carrier_migration_support(&init.exec_alloc);
+#endif
if (init.erts_alloc_config) {
/* Adjust flags that erts_alloc_config won't like */
@@ -716,6 +764,9 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
init.driver_alloc.thr_spec = 0;
init.fix_alloc.thr_spec = 0;
init.literal_alloc.thr_spec = 0;
+#ifdef ERTS_ALC_A_EXEC
+ init.exec_alloc.thr_spec = 0;
+#endif
/* No carrier migration */
init.temp_alloc.init.util.acul = 0;
@@ -728,6 +779,9 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
init.driver_alloc.init.util.acul = 0;
init.fix_alloc.init.util.acul = 0;
init.literal_alloc.init.util.acul = 0;
+#ifdef ERTS_ALC_A_EXEC
+ init.exec_alloc.init.util.acul = 0;
+#endif
}
#ifdef ERTS_SMP
@@ -745,6 +799,9 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
adjust_tpref(&init.driver_alloc, erts_no_schedulers);
adjust_tpref(&init.fix_alloc, erts_no_schedulers);
adjust_tpref(&init.literal_alloc, erts_no_schedulers);
+#ifdef ERTS_ALC_A_EXEC
+ adjust_tpref(&init.exec_alloc, erts_no_schedulers);
+#endif
#else
/* No thread specific if not smp */
@@ -764,6 +821,9 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
refuse_af_strategy(&init.driver_alloc);
refuse_af_strategy(&init.fix_alloc);
refuse_af_strategy(&init.literal_alloc);
+#ifdef ERTS_ALC_A_EXEC
+ refuse_af_strategy(&init.exec_alloc);
+#endif
#ifdef ERTS_SMP
if (!init.temp_alloc.thr_spec)
@@ -808,6 +868,9 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
set_au_allocator(ERTS_ALC_A_DRIVER, &init.driver_alloc, ncpu);
set_au_allocator(ERTS_ALC_A_FIXED_SIZE, &init.fix_alloc, ncpu);
set_au_allocator(ERTS_ALC_A_LITERAL, &init.literal_alloc, ncpu);
+#ifdef ERTS_ALC_A_EXEC
+ set_au_allocator(ERTS_ALC_A_EXEC, &init.exec_alloc, ncpu);
+#endif
set_au_allocator(ERTS_ALC_A_TEST, &init.test_alloc, ncpu);
for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) {
@@ -864,7 +927,11 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop)
start_au_allocator(ERTS_ALC_A_LITERAL,
&init.literal_alloc,
&literal_alloc_state);
-
+#ifdef ERTS_ALC_A_EXEC
+ start_au_allocator(ERTS_ALC_A_EXEC,
+ &init.exec_alloc,
+ &exec_alloc_state);
+#endif
start_au_allocator(ERTS_ALC_A_TEST,
&init.test_alloc,
&test_alloc_state);
@@ -1499,6 +1566,16 @@ handle_args(int *argc, char **argv, erts_alc_hndl_args_init_t *init)
else
handle_au_arg(&init->literal_alloc, &argv[i][3], argv, &i, 0);
break;
+ case 'X':
+ if (has_prefix("scs", argv[i]+3)) {
+#ifdef ERTS_ALC_A_EXEC
+ init->mseg.exec_mmap.scs =
+#endif
+ get_mb_value(argv[i]+6, argv, &i);
+ }
+ else
+ handle_au_arg(&init->exec_alloc, &argv[i][3], argv, &i, 0);
+ break;
case 'D':
handle_au_arg(&init->std_alloc, &argv[i][3], argv, &i, 0);
break;
@@ -1949,7 +2026,7 @@ erts_alc_fatal_error(int error, int func, ErtsAlcType_t n, ...)
va_start(argp, n);
size = va_arg(argp, Uint);
va_end(argp);
- erts_exit(1,
+ erts_exit(ERTS_DUMP_EXIT,
"%s: Cannot %s %lu bytes of memory (of type \"%s\").\n",
allctr_str, op, size, t_str);
break;
@@ -2764,10 +2841,18 @@ erts_allocator_info(int to, void *arg)
int i;
for (i = 0; i <= max; i++) {
erts_print(to, arg, "=allocator:mseg_alloc[%d]\n", i);
- erts_mseg_info(i, &to, arg, 0, NULL, NULL);
+ erts_mseg_info(i, &to, arg, 0, 0, NULL, NULL);
}
- erts_print(to, arg, "=allocator:mseg_alloc.erts_mmap\n");
+ erts_print(to, arg, "=allocator:erts_mmap.default_mmap\n");
erts_mmap_info(&erts_dflt_mmapper, &to, arg, NULL, NULL, &emis);
+#if defined(ARCH_64) && defined(ERTS_HAVE_OS_PHYSICAL_MEMORY_RESERVATION)
+ erts_print(to, arg, "=allocator:erts_mmap.literal_mmap\n");
+ erts_mmap_info(&erts_literal_mmapper, &to, arg, NULL, NULL, &emis);
+#endif
+#ifdef ERTS_ALC_A_EXEC
+ erts_print(to, arg, "=allocator:erts_mmap.exec_mmap\n");
+ erts_mmap_info(&erts_exec_mmapper, &to, arg, NULL, NULL, &emis);
+#endif
}
#endif
@@ -2878,6 +2963,11 @@ erts_allocator_options(void *proc)
atoms[length] = am_atom_put("alloc_util", 10);
terms[length++] = erts_alcu_au_info_options(NULL, NULL, hpp, szp);
+#if HAVE_ERTS_MMAP
+ atoms[length] = ERTS_MAKE_AM("erts_mmap");
+ terms[length++] = erts_mmap_info_options(&erts_dflt_mmapper, NULL, NULL,
+ NULL, hpp, szp);
+#endif
{
Eterm o[3], v[3];
o[0] = am_atom_put("m", 1);
@@ -2914,7 +3004,12 @@ erts_allocator_options(void *proc)
#if ERTS_HAVE_ERTS_SYS_ALIGNED_ALLOC
terms[length++] = am_atom_put("sys_aligned_alloc", 17);
#endif
-
+#if defined(ARCH_64) && defined(ERTS_HAVE_OS_PHYSICAL_MEMORY_RESERVATION)
+ terms[length++] = ERTS_MAKE_AM("literal_mmap");
+#endif
+#ifdef ERTS_ALC_A_EXEC
+ terms[length++] = ERTS_MAKE_AM("exec_mmap");
+#endif
features = length ? erts_bld_list(hpp, szp, length, terms) : NIL;
#if defined(__GLIBC__)
@@ -2999,7 +3094,15 @@ reply_alloc_info(void *vair)
Uint sz, *szp;
ErlOffHeap *ohp = NULL;
ErtsMessage *mp = NULL;
- struct erts_mmap_info_struct emis;
+#if HAVE_ERTS_MMAP
+ struct erts_mmap_info_struct mmap_info_dflt;
+# if defined(ARCH_64) && defined(ERTS_HAVE_OS_PHYSICAL_MEMORY_RESERVATION)
+ struct erts_mmap_info_struct mmap_info_literal;
+# endif
+# ifdef ERTS_ALC_A_EXEC
+ struct erts_mmap_info_struct mmap_info_exec;
+# endif
+#endif
int i;
Eterm (*info_func)(Allctr_t *,
int,
@@ -3105,26 +3208,53 @@ reply_alloc_info(void *vair)
make_small(0),
ainfo);
break;
+ case ERTS_ALC_INFO_A_ERTS_MMAP:
+ alloc_atom = erts_bld_atom(hpp, szp, "erts_mmap");
+#if HAVE_ERTS_MMAP
+ ainfo = (air->only_sz ? NIL :
+ erts_mmap_info(&erts_dflt_mmapper, NULL, NULL,
+ hpp, szp, &mmap_info_dflt));
+ ainfo = erts_bld_tuple3(hpp, szp,
+ alloc_atom,
+ erts_bld_atom(hpp,szp,"default_mmap"),
+ ainfo);
+# if defined(ARCH_64) && defined(ERTS_HAVE_OS_PHYSICAL_MEMORY_RESERVATION)
+ ai_list = erts_bld_cons(hpp, szp,
+ ainfo, ai_list);
+ ainfo = (air->only_sz ? NIL :
+ erts_mmap_info(&erts_literal_mmapper, NULL, NULL,
+ hpp, szp, &mmap_info_literal));
+ ainfo = erts_bld_tuple3(hpp, szp,
+ alloc_atom,
+ erts_bld_atom(hpp,szp,"literal_mmap"),
+ ainfo);
+# endif
+# ifdef ERTS_ALC_A_EXEC
+ ai_list = erts_bld_cons(hpp, szp,
+ ainfo, ai_list);
+ ainfo = (air->only_sz ? NIL :
+ erts_mmap_info(&erts_exec_mmapper, NULL, NULL,
+ hpp, szp, &mmap_info_exec));
+ ainfo = erts_bld_tuple3(hpp, szp,
+ alloc_atom,
+ erts_bld_atom(hpp,szp,"exec_mmap"),
+ ainfo);
+# endif
+#else /* !HAVE_ERTS_MMAP */
+ ainfo = erts_bld_tuple2(hpp, szp, alloc_atom,
+ am_false);
+#endif
+ break;
case ERTS_ALC_INFO_A_MSEG_ALLOC:
alloc_atom = erts_bld_atom(hpp, szp, "mseg_alloc");
#if HAVE_ERTS_MSEG
- ainfo = (air->only_sz
- ? NIL
- : erts_mseg_info(0, NULL, NULL, hpp != NULL,
- hpp, szp));
+ ainfo = erts_mseg_info(0, NULL, NULL, hpp != NULL,
+ air->only_sz, hpp, szp);
ainfo = erts_bld_tuple3(hpp, szp,
alloc_atom,
make_small(0),
ainfo);
- ai_list = erts_bld_cons(hpp, szp,
- ainfo, ai_list);
- ainfo = (air->only_sz ? NIL :
- erts_mmap_info(&erts_dflt_mmapper, NULL, NULL, hpp, szp, &emis));
- ainfo = erts_bld_tuple3(hpp, szp,
- alloc_atom,
- erts_bld_atom(hpp,szp,"erts_mmap"),
- ainfo);
#else
ainfo = erts_bld_tuple2(hpp, szp, alloc_atom,
am_false);
@@ -3156,15 +3286,14 @@ reply_alloc_info(void *vair)
}
switch (ai) {
case ERTS_ALC_A_SYSTEM:
- case ERTS_ALC_INFO_A_ALLOC_UTIL:
+ case ERTS_ALC_INFO_A_ALLOC_UTIL:
+ case ERTS_ALC_INFO_A_ERTS_MMAP:
break;
case ERTS_ALC_INFO_A_MSEG_ALLOC:
#if HAVE_ERTS_MSEG && defined(ERTS_SMP)
alloc_atom = erts_bld_atom(hpp, szp, "mseg_alloc");
- ainfo = (air->only_sz
- ? NIL
- : erts_mseg_info(sched_id, NULL, NULL,
- hpp != NULL, hpp, szp));
+ ainfo = erts_mseg_info(sched_id, NULL, NULL,
+ hpp != NULL, air->only_sz, hpp, szp);
ainfo = erts_bld_tuple(hpp, szp, 3,
alloc_atom,
make_small(sched_id),
@@ -3210,7 +3339,7 @@ reply_alloc_info(void *vair)
if (hp != hp_end)
erts_shrink_message_heap(&mp, rp, hp_start, hp, hp_end, &msg, 1);
- erts_queue_message(rp, &rp_locks, mp, msg, NIL);
+ erts_queue_message(rp, rp_locks, mp, msg, am_system);
if (air->req_sched == sched_id)
rp_locks &= ~ERTS_PROC_LOCK_MAIN;
@@ -3230,7 +3359,7 @@ erts_request_alloc_info(struct process *c_p,
int internal)
{
ErtsAllocInfoReq *air = aireq_alloc();
- Eterm req_ai[ERTS_ALC_A_MAX+1+2] = {0};
+ Eterm req_ai[ERTS_ALC_INFO_A_MAX+1] = {0};
Eterm alist;
Eterm *hp;
int airix = 0, ai;
@@ -3266,6 +3395,10 @@ erts_request_alloc_info(struct process *c_p,
ai = ERTS_ALC_INFO_A_MSEG_ALLOC;
goto save_alloc;
}
+ if (erts_is_atom_str("erts_mmap", alloc, 0)) {
+ ai = ERTS_ALC_INFO_A_ERTS_MMAP;
+ goto save_alloc;
+ }
if (erts_is_atom_str("alloc_util", alloc, 0)) {
ai = ERTS_ALC_INFO_A_ALLOC_UTIL;
save_alloc:
diff --git a/erts/emulator/beam/erl_alloc.h b/erts/emulator/beam/erl_alloc.h
index 71e4713624..925a081a02 100644
--- a/erts/emulator/beam/erl_alloc.h
+++ b/erts/emulator/beam/erl_alloc.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2002-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.
@@ -235,9 +235,9 @@ void *erts_alloc(ErtsAlcType_t type, Uint size)
void *res;
ERTS_MSACC_PUSH_AND_SET_STATE_X(ERTS_MSACC_STATE_ALLOC);
res = (*erts_allctrs[ERTS_ALC_T2A(type)].alloc)(
- ERTS_ALC_T2N(type),
- erts_allctrs[ERTS_ALC_T2A(type)].extra,
- size);
+ ERTS_ALC_T2N(type),
+ erts_allctrs[ERTS_ALC_T2A(type)].extra,
+ size);
if (!res)
erts_alloc_n_enomem(ERTS_ALC_T2N(type), size);
ERTS_MSACC_POP_STATE_X();
@@ -564,5 +564,3 @@ NAME##_free(TYPE *p) \
#undef ERTS_ALC_ATTRIBUTES
#endif /* #ifndef ERL_ALLOC_H__ */
-
-
diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types
index 2932adca84..ba216c7eb4 100644
--- a/erts/emulator/beam/erl_alloc.types
+++ b/erts/emulator/beam/erl_alloc.types
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2014. All Rights Reserved.
+# Copyright Ericsson AB 2003-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.
@@ -87,6 +87,9 @@ allocator EHEAP true eheap_alloc
allocator ETS true ets_alloc
allocator FIXED_SIZE true fix_alloc
allocator LITERAL true literal_alloc
++if exec_alloc
+allocator EXEC true exec_alloc
++endif
+else # Non smp build
@@ -98,6 +101,9 @@ allocator EHEAP false eheap_alloc
allocator ETS false ets_alloc
allocator FIXED_SIZE false fix_alloc
allocator LITERAL false literal_alloc
++if exec_alloc
+allocator EXEC false exec_alloc
++endif
+endif
@@ -258,7 +264,6 @@ type PRTSD STANDARD SYSTEM port_specific_data
type CPUDATA LONG_LIVED SYSTEM cpu_data
type TMP_CPU_IDS SHORT_LIVED SYSTEM tmp_cpu_ids
type EXT_TERM_DATA SHORT_LIVED PROCESSES external_term_data
-type ZLIB STANDARD SYSTEM zlib
type CPU_GRPS_MAP LONG_LIVED SYSTEM cpu_groups_map
type AUX_WORK_TMO LONG_LIVED SYSTEM aux_work_timeouts
type MISC_AUX_WORK_Q LONG_LIVED SYSTEM misc_aux_work_q
@@ -270,6 +275,9 @@ type PROC_SYS_TSK SHORT_LIVED PROCESSES proc_sys_task
type PROC_SYS_TSK_QS SHORT_LIVED PROCESSES proc_sys_task_queues
type NEW_TIME_OFFSET SHORT_LIVED SYSTEM new_time_offset
type IOB_REQ SHORT_LIVED SYSTEM io_bytes_request
+type TRACER_NIF LONG_LIVED SYSTEM tracer_nif
+type TRACE_MSG_QUEUE SHORT_LIVED SYSTEM trace_message_queue
+type SCHED_ASYNC_JOB SHORT_LIVED SYSTEM async_calls
+if threads_no_smp
# Need thread safe allocs, but std_alloc and fix_alloc are not;
@@ -288,8 +296,10 @@ type THR_Q_LL LONG_LIVED SYSTEM long_lived_thr_queue
+if smp
type ASYNC SHORT_LIVED SYSTEM async
+type ZLIB STANDARD SYSTEM zlib
+else
-# sl_alloc is not thread safe in non smp build; therefore, we use driver_alloc
+# sl/std_alloc is not thread safe in non smp build; therefore, we use driver_alloc
+type ZLIB DRIVER SYSTEM zlib
type ASYNC DRIVER SYSTEM async
+endif
@@ -335,14 +345,22 @@ type SL_MPATHS SHORT_LIVED SYSTEM sl_migration_paths
# Currently most hipe code use this type.
type HIPE SYSTEM SYSTEM hipe_data
++if exec_alloc
+type HIPE_EXEC EXEC CODE hipe_code
+endif
++endif
+
+
+
+if heap_frag_elim_test
type SSB SHORT_LIVED PROCESSES ssb
+endif
+type DEBUG SHORT_LIVED SYSTEM debugging
+
type DDLL_PROCESS STANDARD SYSTEM ddll_processes
type MONITOR_LH STANDARD PROCESSES monitor_lh
type NLINK_LH STANDARD PROCESSES nlink_lh
diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c
index 5e7dd7cce8..2995f2f822 100644
--- a/erts/emulator/beam/erl_alloc_util.c
+++ b/erts/emulator/beam/erl_alloc_util.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2002-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.
@@ -52,6 +52,7 @@
#ifdef ERTS_ENABLE_LOCK_COUNT
#include "erl_lock_count.h"
#endif
+#include "lttng-wrapper.h"
#if defined(ERTS_ALLOC_UTIL_HARD_DEBUG) && defined(__GNUC__)
#warning "* * * * * * * * * *"
@@ -858,28 +859,36 @@ void*
erts_alcu_literal_32_mseg_alloc(Allctr_t *allctr, Uint *size_p, Uint flags)
{
void* res;
- ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL
- && !allctr->t && allctr->thread_safe);
+ Uint sz = ERTS_SUPERALIGNED_CEILING(*size_p);
+ ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL &&
+ allctr->t == 0);
+ ERTS_SMP_LC_ASSERT(allctr->thread_safe);
- res = erts_alcu_mseg_alloc(allctr, size_p, flags);
- if (res)
- set_literal_range(res, *size_p);
+ res = erts_alcu_mseg_alloc(allctr, &sz, flags);
+ if (res) {
+ set_literal_range(res, sz);
+ *size_p = sz;
+ }
return res;
}
void*
erts_alcu_literal_32_mseg_realloc(Allctr_t *allctr, void *seg,
- Uint old_size, Uint *new_size_p)
+ Uint old_size, Uint *new_size_p)
{
void* res;
- ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL
- && !allctr->t && allctr->thread_safe);
+ Uint new_sz = ERTS_SUPERALIGNED_CEILING(*new_size_p);
+ ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL &&
+ allctr->t == 0);
+ ERTS_SMP_LC_ASSERT(allctr->thread_safe);
if (seg && old_size)
clear_literal_range(seg, old_size);
- res = erts_alcu_mseg_realloc(allctr, seg, old_size, new_size_p);
- if (res)
- set_literal_range(res, *new_size_p);
+ res = erts_alcu_mseg_realloc(allctr, seg, old_size, &new_sz);
+ if (res) {
+ set_literal_range(res, new_sz);
+ *new_size_p = new_sz;
+ }
return res;
}
@@ -887,8 +896,9 @@ void
erts_alcu_literal_32_mseg_dealloc(Allctr_t *allctr, void *seg, Uint size,
Uint flags)
{
- ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL
- && !allctr->t && allctr->thread_safe);
+ ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL &&
+ allctr->t == 0);
+ ERTS_SMP_LC_ASSERT(allctr->thread_safe);
erts_alcu_mseg_dealloc(allctr, seg, size, flags);
@@ -897,8 +907,9 @@ erts_alcu_literal_32_mseg_dealloc(Allctr_t *allctr, void *seg, Uint size,
#elif defined(ARCH_64) && defined(ERTS_HAVE_OS_PHYSICAL_MEMORY_RESERVATION)
+/* Used by literal allocator that has its own mmapper (super carrier) */
void*
-erts_alcu_literal_64_mseg_alloc(Allctr_t *allctr, Uint *size_p, Uint flags)
+erts_alcu_mmapper_mseg_alloc(Allctr_t *allctr, Uint *size_p, Uint flags)
{
void* res;
UWord size = (UWord) *size_p;
@@ -906,33 +917,33 @@ erts_alcu_literal_64_mseg_alloc(Allctr_t *allctr, Uint *size_p, Uint flags)
if (flags & ERTS_MSEG_FLG_2POW)
mmap_flags |= ERTS_MMAPFLG_SUPERALIGNED;
- res = erts_mmap(&erts_literal_mmapper, mmap_flags, &size);
+ res = erts_mmap(allctr->mseg_mmapper, mmap_flags, &size);
*size_p = (Uint)size;
INC_CC(allctr->calls.mseg_alloc);
return res;
}
void*
-erts_alcu_literal_64_mseg_realloc(Allctr_t *allctr, void *seg,
+erts_alcu_mmapper_mseg_realloc(Allctr_t *allctr, void *seg,
Uint old_size, Uint *new_size_p)
{
void *res;
UWord new_size = (UWord) *new_size_p;
- res = erts_mremap(&erts_literal_mmapper, ERTS_MSEG_FLG_NONE, seg, old_size, &new_size);
+ res = erts_mremap(allctr->mseg_mmapper, ERTS_MSEG_FLG_NONE, seg, old_size, &new_size);
*new_size_p = (Uint) new_size;
INC_CC(allctr->calls.mseg_realloc);
return res;
}
void
-erts_alcu_literal_64_mseg_dealloc(Allctr_t *allctr, void *seg, Uint size,
+erts_alcu_mmapper_mseg_dealloc(Allctr_t *allctr, void *seg, Uint size,
Uint flags)
{
Uint32 mmap_flags = ERTS_MMAPFLG_SUPERCARRIER_ONLY;
if (flags & ERTS_MSEG_FLG_2POW)
mmap_flags |= ERTS_MMAPFLG_SUPERALIGNED;
- erts_munmap(&erts_literal_mmapper, mmap_flags, seg, (UWord)size);
+ erts_munmap(allctr->mseg_mmapper, mmap_flags, seg, (UWord)size);
INC_CC(allctr->calls.mseg_dealloc);
}
#endif /* ARCH_64 && ERTS_HAVE_OS_PHYSICAL_MEMORY_RESERVATION */
@@ -940,9 +951,10 @@ erts_alcu_literal_64_mseg_dealloc(Allctr_t *allctr, void *seg, Uint size,
#endif /* HAVE_ERTS_MSEG */
void*
-erts_alcu_sys_alloc(Allctr_t *allctr, Uint size, int superalign)
+erts_alcu_sys_alloc(Allctr_t *allctr, Uint* size_p, int superalign)
{
void *res;
+ const Uint size = *size_p;
#if ERTS_SA_MB_CARRIERS && ERTS_HAVE_ERTS_SYS_ALIGNED_ALLOC
if (superalign)
res = erts_sys_aligned_alloc(ERTS_SACRR_UNIT_SZ, size);
@@ -956,9 +968,10 @@ erts_alcu_sys_alloc(Allctr_t *allctr, Uint size, int superalign)
}
void*
-erts_alcu_sys_realloc(Allctr_t *allctr, void *ptr, Uint size, Uint old_size, int superalign)
+erts_alcu_sys_realloc(Allctr_t *allctr, void *ptr, Uint *size_p, Uint old_size, int superalign)
{
void *res;
+ const Uint size = *size_p;
#if ERTS_SA_MB_CARRIERS && ERTS_HAVE_ERTS_SYS_ALIGNED_ALLOC
if (superalign)
@@ -993,38 +1006,48 @@ erts_alcu_sys_dealloc(Allctr_t *allctr, void *ptr, Uint size, int superalign)
#ifdef ARCH_32
void*
-erts_alcu_literal_32_sys_alloc(Allctr_t *allctr, Uint size, int superalign)
+erts_alcu_literal_32_sys_alloc(Allctr_t *allctr, Uint* size_p, int superalign)
{
void* res;
- ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL
- && !allctr->t && allctr->thread_safe);
+ Uint size = ERTS_SUPERALIGNED_CEILING(*size_p);
+ ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL &&
+ allctr->t == 0);
+ ERTS_SMP_LC_ASSERT(allctr->thread_safe);
- res = erts_alcu_sys_alloc(allctr, size, 1);
- if (res)
+ res = erts_alcu_sys_alloc(allctr, &size, 1);
+ if (res) {
set_literal_range(res, size);
+ *size_p = size;
+ }
return res;
}
void*
-erts_alcu_literal_32_sys_realloc(Allctr_t *allctr, void *ptr, Uint size, Uint old_size, int superalign)
+erts_alcu_literal_32_sys_realloc(Allctr_t *allctr, void *ptr, Uint* size_p, Uint old_size, int superalign)
{
void* res;
- ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL
- && !allctr->t && allctr->thread_safe);
+ Uint size = ERTS_SUPERALIGNED_CEILING(*size_p);
+
+ ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL &&
+ allctr->t == 0);
+ ERTS_SMP_LC_ASSERT(allctr->thread_safe);
if (ptr && old_size)
clear_literal_range(ptr, old_size);
- res = erts_alcu_sys_realloc(allctr, ptr, size, old_size, 1);
- if (res)
+ res = erts_alcu_sys_realloc(allctr, ptr, &size, old_size, 1);
+ if (res) {
set_literal_range(res, size);
+ *size_p = size;
+ }
return res;
}
void
erts_alcu_literal_32_sys_dealloc(Allctr_t *allctr, void *ptr, Uint size, int superalign)
{
- ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL
- && !allctr->t && allctr->thread_safe);
+ ERTS_LC_ASSERT(allctr->alloc_no == ERTS_ALC_A_LITERAL &&
+ allctr->t == 0);
+ ERTS_SMP_LC_ASSERT(allctr->thread_safe);
erts_alcu_sys_dealloc(allctr, ptr, size, 1);
@@ -3125,6 +3148,7 @@ cpool_insert(Allctr_t *allctr, Carrier_t *crr)
erts_smp_atomic_set_wb(&crr->allctr,
((erts_aint_t) allctr)|ERTS_CRR_ALCTR_FLG_IN_POOL);
+ LTTNG3(carrier_pool_put, ERTS_ALC_A2AD(allctr->alloc_no), allctr->ix, CARRIER_SZ(crr));
}
static void
@@ -3240,6 +3264,7 @@ cpool_fetch(Allctr_t *allctr, UWord size)
first_old_traitor = allctr->cpool.traitor_list.next;
cpool_entrance = NULL;
+ LTTNG3(carrier_pool_get, ERTS_ALC_A2AD(allctr->alloc_no), allctr->ix, (unsigned long)size);
/*
* Search my own pooled_list,
* i.e my abandoned carriers that were in the pool last time I checked.
@@ -3861,12 +3886,12 @@ create_carrier(Allctr_t *allctr, Uint umem_sz, UWord flags)
? UNIT_CEILING(bcrr_sz)
: SYS_ALLOC_CARRIER_CEILING(bcrr_sz));
- crr = (Carrier_t *) allctr->sys_alloc(allctr, crr_sz, flags & CFLG_MBC);
+ crr = (Carrier_t *) allctr->sys_alloc(allctr, &crr_sz, flags & CFLG_MBC);
if (!crr) {
if (crr_sz > UNIT_CEILING(bcrr_sz)) {
crr_sz = UNIT_CEILING(bcrr_sz);
- crr = (Carrier_t *) allctr->sys_alloc(allctr, crr_sz, flags & CFLG_MBC);
+ crr = (Carrier_t *) allctr->sys_alloc(allctr, &crr_sz, flags & CFLG_MBC);
}
if (!crr) {
#if HAVE_ERTS_MSEG
@@ -3925,6 +3950,21 @@ create_carrier(Allctr_t *allctr, Uint umem_sz, UWord flags)
}
+#ifdef USE_LTTNG_VM_TRACEPOINTS
+ if (LTTNG_ENABLED(carrier_create)) {
+ lttng_decl_carrier_stats(mbc_stats);
+ lttng_decl_carrier_stats(sbc_stats);
+ LTTNG_CARRIER_STATS_TO_LTTNG_STATS(&(allctr->mbcs), mbc_stats);
+ LTTNG_CARRIER_STATS_TO_LTTNG_STATS(&(allctr->sbcs), sbc_stats);
+ LTTNG5(carrier_create,
+ ERTS_ALC_A2AD(allctr->alloc_no),
+ allctr->ix,
+ crr_sz,
+ mbc_stats,
+ sbc_stats);
+ }
+#endif
+
DEBUG_SAVE_ALIGNMENT(crr);
return blk;
}
@@ -4009,7 +4049,7 @@ resize_carrier(Allctr_t *allctr, Block_t *old_blk, Uint umem_sz, UWord flags)
new_crr = (Carrier_t *) allctr->sys_realloc(allctr,
(void *) old_crr,
- new_crr_sz,
+ &new_crr_sz,
old_crr_sz,
0);
if (new_crr) {
@@ -4030,7 +4070,7 @@ resize_carrier(Allctr_t *allctr, Block_t *old_blk, Uint umem_sz, UWord flags)
new_crr_sz = UNIT_CEILING(new_crr_sz);
new_crr = (Carrier_t *) allctr->sys_realloc(allctr,
(void *) old_crr,
- new_crr_sz,
+ &new_crr_sz,
old_crr_sz,
0);
if (new_crr)
@@ -4148,6 +4188,21 @@ destroy_carrier(Allctr_t *allctr, Block_t *blk, Carrier_t **busy_pcrr_pp)
allctr->remove_mbc(allctr, crr);
}
+#ifdef USE_LTTNG_VM_TRACEPOINTS
+ if (LTTNG_ENABLED(carrier_destroy)) {
+ lttng_decl_carrier_stats(mbc_stats);
+ lttng_decl_carrier_stats(sbc_stats);
+ LTTNG_CARRIER_STATS_TO_LTTNG_STATS(&(allctr->mbcs), mbc_stats);
+ LTTNG_CARRIER_STATS_TO_LTTNG_STATS(&(allctr->sbcs), sbc_stats);
+ LTTNG5(carrier_destroy,
+ ERTS_ALC_A2AD(allctr->alloc_no),
+ allctr->ix,
+ crr_sz,
+ mbc_stats,
+ sbc_stats);
+ }
+#endif
+
#ifdef ERTS_SMP
schedule_dealloc_carrier(allctr, crr);
#else
@@ -6094,6 +6149,7 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
allctr->mseg_alloc = init->mseg_alloc;
allctr->mseg_realloc = init->mseg_realloc;
allctr->mseg_dealloc = init->mseg_dealloc;
+ allctr->mseg_mmapper = init->mseg_mmapper;
}
else {
ASSERT(!init->mseg_realloc && !init->mseg_dealloc);
diff --git a/erts/emulator/beam/erl_alloc_util.h b/erts/emulator/beam/erl_alloc_util.h
index b7d717ed23..f50f09907a 100644
--- a/erts/emulator/beam/erl_alloc_util.h
+++ b/erts/emulator/beam/erl_alloc_util.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2002-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.
@@ -30,6 +30,7 @@
#endif
#include "erl_mseg.h"
+#include "lttng-wrapper.h"
#define ERTS_AU_PREF_ALLOC_BITS 11
#define ERTS_AU_MAX_PREF_ALLOC_INSTANCES (1 << ERTS_AU_PREF_ALLOC_BITS)
@@ -71,9 +72,10 @@ typedef struct {
void* (*mseg_alloc)(Allctr_t*, Uint *size_p, Uint flags);
void* (*mseg_realloc)(Allctr_t*, void *seg, Uint old_size, Uint *new_size_p);
void (*mseg_dealloc)(Allctr_t*, void *seg, Uint size, Uint flags);
+ ErtsMemMapper *mseg_mmapper;
#endif
- void* (*sys_alloc)(Allctr_t *allctr, Uint size, int superalign);
- void* (*sys_realloc)(Allctr_t *allctr, void *ptr, Uint size, Uint old_size, int superalign);
+ void* (*sys_alloc)(Allctr_t *allctr, Uint *size_p, int superalign);
+ void* (*sys_realloc)(Allctr_t *allctr, void *ptr, Uint *size_p, Uint old_size, int superalign);
void (*sys_dealloc)(Allctr_t *allctr, void *ptr, Uint size, int superalign);
} AllctrInit_t;
@@ -204,18 +206,18 @@ void* erts_alcu_literal_32_mseg_realloc(Allctr_t*, void *seg, Uint old_size, Uin
void erts_alcu_literal_32_mseg_dealloc(Allctr_t*, void *seg, Uint size, Uint flags);
# elif defined(ARCH_64) && defined(ERTS_HAVE_OS_PHYSICAL_MEMORY_RESERVATION)
-void* erts_alcu_literal_64_mseg_alloc(Allctr_t*, Uint *size_p, Uint flags);
-void* erts_alcu_literal_64_mseg_realloc(Allctr_t*, void *seg, Uint old_size, Uint *new_size_p);
-void erts_alcu_literal_64_mseg_dealloc(Allctr_t*, void *seg, Uint size, Uint flags);
+void* erts_alcu_mmapper_mseg_alloc(Allctr_t*, Uint *size_p, Uint flags);
+void* erts_alcu_mmapper_mseg_realloc(Allctr_t*, void *seg, Uint old_size, Uint *new_size_p);
+void erts_alcu_mmapper_mseg_dealloc(Allctr_t*, void *seg, Uint size, Uint flags);
# endif
#endif /* HAVE_ERTS_MSEG */
-void* erts_alcu_sys_alloc(Allctr_t*, Uint size, int superalign);
-void* erts_alcu_sys_realloc(Allctr_t*, void *ptr, Uint size, Uint old_size, int superalign);
+void* erts_alcu_sys_alloc(Allctr_t*, Uint *size_p, int superalign);
+void* erts_alcu_sys_realloc(Allctr_t*, void *ptr, Uint *size_p, Uint old_size, int superalign);
void erts_alcu_sys_dealloc(Allctr_t*, void *ptr, Uint size, int superalign);
#ifdef ARCH_32
-void* erts_alcu_literal_32_sys_alloc(Allctr_t*, Uint size, int superalign);
-void* erts_alcu_literal_32_sys_realloc(Allctr_t*, void *ptr, Uint size, Uint old_size, int superalign);
+void* erts_alcu_literal_32_sys_alloc(Allctr_t*, Uint *size_p, int superalign);
+void* erts_alcu_literal_32_sys_realloc(Allctr_t*, void *ptr, Uint *size_p, Uint old_size, int superalign);
void erts_alcu_literal_32_sys_dealloc(Allctr_t*, void *ptr, Uint size, int superalign);
#endif
@@ -417,6 +419,18 @@ typedef struct {
} blocks;
} CarriersStats_t;
+#ifdef USE_LTTNG_VM_TRACEPOINTS
+#define LTTNG_CARRIER_STATS_TO_LTTNG_STATS(CSP, LSP) \
+ do { \
+ (LSP)->carriers.size = (CSP)->curr.norm.mseg.size \
+ + (CSP)->curr.norm.sys_alloc.size; \
+ (LSP)->carriers.no = (CSP)->curr.norm.mseg.no \
+ + (CSP)->curr.norm.sys_alloc.no; \
+ (LSP)->blocks.size = (CSP)->blocks.curr.size; \
+ (LSP)->blocks.no = (CSP)->blocks.curr.no; \
+ } while (0)
+#endif
+
#ifdef ERTS_SMP
typedef union ErtsAllctrDDBlock_t_ ErtsAllctrDDBlock_t;
@@ -588,9 +602,10 @@ struct Allctr_t_ {
void* (*mseg_alloc)(Allctr_t*, Uint *size_p, Uint flags);
void* (*mseg_realloc)(Allctr_t*, void *seg, Uint old_size, Uint *new_size_p);
void (*mseg_dealloc)(Allctr_t*, void *seg, Uint size, Uint flags);
+ ErtsMemMapper *mseg_mmapper;
#endif
- void* (*sys_alloc)(Allctr_t *allctr, Uint size, int superalign);
- void* (*sys_realloc)(Allctr_t *allctr, void *ptr, Uint size, Uint old_size, int superalign);
+ void* (*sys_alloc)(Allctr_t *allctr, Uint *size_p, int superalign);
+ void* (*sys_realloc)(Allctr_t *allctr, void *ptr, Uint *size_p, Uint old_size, int superalign);
void (*sys_dealloc)(Allctr_t *allctr, void *ptr, Uint size, int superalign);
void (*init_atoms) (void);
diff --git a/erts/emulator/beam/erl_ao_firstfit_alloc.c b/erts/emulator/beam/erl_ao_firstfit_alloc.c
index 5cd067ff54..fbe4724047 100644
--- a/erts/emulator/beam/erl_ao_firstfit_alloc.c
+++ b/erts/emulator/beam/erl_ao_firstfit_alloc.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/beam/erl_ao_firstfit_alloc.h b/erts/emulator/beam/erl_ao_firstfit_alloc.h
index 4200f20622..7349c6ab19 100644
--- a/erts/emulator/beam/erl_ao_firstfit_alloc.h
+++ b/erts/emulator/beam/erl_ao_firstfit_alloc.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/beam/erl_arith.c b/erts/emulator/beam/erl_arith.c
index 3671025d22..861532f241 100644
--- a/erts/emulator/beam/erl_arith.c
+++ b/erts/emulator/beam/erl_arith.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2010. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/beam/erl_async.c b/erts/emulator/beam/erl_async.c
index cdeeb5281b..84254af0c2 100644
--- a/erts/emulator/beam/erl_async.c
+++ b/erts/emulator/beam/erl_async.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2000-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2000-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.
@@ -28,6 +28,7 @@
#include "erl_thr_queue.h"
#include "erl_async.h"
#include "dtrace-wrapper.h"
+#include "lttng-wrapper.h"
#define ERTS_MAX_ASYNC_READY_CALLS_IN_SEQ 20
@@ -281,6 +282,13 @@ static ERTS_INLINE void async_add(ErtsAsync *a, ErtsAsyncQ* q)
#endif
erts_thr_q_enqueue(&q->thr_q, a);
+#ifdef USE_LTTNG_VM_TRACEPOINTS
+ if (LTTNG_ENABLED(aio_pool_put)) {
+ lttng_decl_portbuf(port_str);
+ lttng_portid_to_str(a->port, port_str);
+ LTTNG2(aio_pool_put, port_str, -1);
+ }
+#endif
#ifdef USE_VM_PROBES
if (DTRACE_ENABLED(aio_pool_add)) {
DTRACE_CHARBUF(port_str, 16);
@@ -317,6 +325,14 @@ static ERTS_INLINE ErtsAsync *async_get(ErtsThrQ_t *q,
if (saved_fin_deq)
erts_thr_q_append_finalize_dequeue_data(&a->q.fin_deq, &fin_deq);
#endif
+#ifdef USE_LTTNG_VM_TRACEPOINTS
+ if (LTTNG_ENABLED(aio_pool_get)) {
+ lttng_decl_portbuf(port_str);
+ int length = erts_thr_q_length_dirty(q);
+ lttng_portid_to_str(a->port, port_str);
+ LTTNG2(aio_pool_get, port_str, length);
+ }
+#endif
#ifdef USE_VM_PROBES
if (DTRACE_ENABLED(aio_pool_get)) {
DTRACE_CHARBUF(port_str, 16);
diff --git a/erts/emulator/beam/erl_async.h b/erts/emulator/beam/erl_async.h
index 65538bcef0..473c7686e5 100644
--- a/erts/emulator/beam/erl_async.h
+++ b/erts/emulator/beam/erl_async.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
diff --git a/erts/emulator/beam/erl_bestfit_alloc.c b/erts/emulator/beam/erl_bestfit_alloc.c
index f39a18ac88..379cee39a1 100644
--- a/erts/emulator/beam/erl_bestfit_alloc.c
+++ b/erts/emulator/beam/erl_bestfit_alloc.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/beam/erl_bestfit_alloc.h b/erts/emulator/beam/erl_bestfit_alloc.h
index b315518b88..3a5f51f5dc 100644
--- a/erts/emulator/beam/erl_bestfit_alloc.h
+++ b/erts/emulator/beam/erl_bestfit_alloc.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/beam/erl_bif_binary.c b/erts/emulator/beam/erl_bif_binary.c
index aec72bd61a..6e10980b6b 100644
--- a/erts/emulator/beam/erl_bif_binary.c
+++ b/erts/emulator/beam/erl_bif_binary.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2013. All Rights Reserved.
+ * 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.
diff --git a/erts/emulator/beam/erl_bif_chksum.c b/erts/emulator/beam/erl_bif_chksum.c
index e3074d6309..9417803e14 100644
--- a/erts/emulator/beam/erl_bif_chksum.c
+++ b/erts/emulator/beam/erl_bif_chksum.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/emulator/beam/erl_bif_ddll.c b/erts/emulator/beam/erl_bif_ddll.c
index f006856b6a..ef77201544 100644
--- a/erts/emulator/beam/erl_bif_ddll.c
+++ b/erts/emulator/beam/erl_bif_ddll.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
@@ -48,6 +48,7 @@
#include "erl_version.h"
#include "erl_bif_unique.h"
#include "dtrace-wrapper.h"
+#include "lttng-wrapper.h"
#ifdef ERTS_SMP
#define DDLL_SMP 1
@@ -1619,6 +1620,7 @@ static int do_unload_driver_entry(DE_Handle *dh, Eterm *save_name)
if (q->finish) {
int fpe_was_unmasked = erts_block_fpe();
DTRACE1(driver_finish, q->name);
+ LTTNG1(driver_finish, q->name);
(*(q->finish))();
erts_unblock_fpe(fpe_was_unmasked);
}
@@ -1735,7 +1737,7 @@ static void notify_proc(Process *proc, Eterm ref, Eterm driver_name, Eterm type,
hp += REF_THING_SIZE;
mess = TUPLE5(hp,type,r,am_driver,driver_name,tag);
}
- erts_queue_message(proc, &rp_locks, mp, mess, am_undefined);
+ erts_queue_message(proc, rp_locks, mp, mess, am_system);
erts_smp_proc_unlock(proc, rp_locks);
ERTS_SMP_CHK_NO_PROC_LOCKS;
}
diff --git a/erts/emulator/beam/erl_bif_guard.c b/erts/emulator/beam/erl_bif_guard.c
index 4a9a6a5fcd..b42d2dc28b 100644
--- a/erts/emulator/beam/erl_bif_guard.c
+++ b/erts/emulator/beam/erl_bif_guard.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 8c748c9bf7..85cadafebc 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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.
@@ -22,6 +22,7 @@
# include "config.h"
#endif
+#define ERTS_WANT_MEM_MAPPERS
#include "sys.h"
#include "erl_vm.h"
#include "global.h"
@@ -126,6 +127,9 @@ static char erts_system_version[] = ("Erlang/OTP " ERLANG_OTP_RELEASE
#ifdef ERTS_FRMPTR
" [frame-pointer]"
#endif
+#ifdef USE_LTTNG
+ " [lttng]"
+#endif
#ifdef USE_DTRACE
" [dtrace]"
#endif
@@ -843,6 +847,7 @@ process_info_list(Process *c_p, Eterm pid, Eterm list, int always_wrap,
if (unlock_locks)
erts_smp_proc_unlock(rp, unlock_locks);
+
}
/*
@@ -1354,9 +1359,10 @@ process_info_aux(Process *BIF_P,
total_heap_size += rp->mbuf_sz;
- for (mp = rp->msg.first; mp; mp = mp->next)
- if (mp->data.attached)
- total_heap_size += erts_msg_attached_data_size(mp);
+ if (rp->flags & F_ON_HEAP_MSGQ)
+ for (mp = rp->msg.first; mp; mp = mp->next)
+ if (mp->data.attached)
+ total_heap_size += erts_msg_attached_data_size(mp);
(void) erts_bld_uint(NULL, &hsz, total_heap_size);
hp = HAlloc(BIF_P, hsz);
@@ -1480,7 +1486,7 @@ process_info_aux(Process *BIF_P,
}
case am_last_calls: {
- struct saved_calls *scb = ERTS_PROC_GET_SAVED_CALLS_BUF(BIF_P);
+ struct saved_calls *scb = ERTS_PROC_GET_SAVED_CALLS_BUF(rp);
if (!scb) {
hp = HAlloc(BIF_P, 3);
res = am_false;
@@ -2159,8 +2165,8 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
res = build_snifs_term(&hp, NULL, NIL);
BIF_RET(res);
} else if (BIF_ARG_1 == am_sequential_tracer) {
- val = erts_get_system_seq_tracer();
- ASSERT(is_internal_pid(val) || is_internal_port(val) || val==am_false);
+ ErtsTracer seq_tracer = erts_get_system_seq_tracer();
+ val = erts_tracer_to_term(BIF_P, seq_tracer);
hp = HAlloc(BIF_P, 3);
res = TUPLE2(hp, am_sequential_tracer, val);
BIF_RET(res);
@@ -2748,6 +2754,9 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
#elif defined(USE_SYSTEMTAP)
DECL_AM(systemtap);
BIF_RET(AM_systemtap);
+#elif defined(USE_LTTNG)
+ DECL_AM(lttng);
+ BIF_RET(AM_lttng);
#else
BIF_RET(am_none);
#endif
@@ -3546,7 +3555,7 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1)
BIF_RET(res);
}
else if (ERTS_IS_ATOM_STR("mmap", BIF_ARG_1)) {
- BIF_RET(erts_mmap_debug_info(&erts_dflt_mmapper, BIF_P));
+ BIF_RET(erts_mmap_debug_info(BIF_P));
}
else if (ERTS_IS_ATOM_STR("unique_monotonic_integer_state", BIF_ARG_1)) {
BIF_RET(erts_debug_get_unique_monotonic_integer_state(BIF_P));
diff --git a/erts/emulator/beam/erl_bif_lists.c b/erts/emulator/beam/erl_bif_lists.c
index fe64e76575..73d327da3e 100644
--- a/erts/emulator/beam/erl_bif_lists.c
+++ b/erts/emulator/beam/erl_bif_lists.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2011. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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.
@@ -40,32 +40,93 @@ static BIF_RETTYPE append(Process* p, Eterm A, Eterm B)
Eterm list;
Eterm copy;
Eterm last;
- size_t need;
- Eterm* hp;
+ Eterm* hp = NULL;
Sint i;
- if ((i = erts_list_length(A)) < 0) {
- BIF_ERROR(p, BADARG);
+ list = A;
+
+ if (is_nil(list)) {
+ BIF_RET(B);
}
- if (i == 0) {
- BIF_RET(B);
- } else if (is_nil(B)) {
- BIF_RET(A);
+
+ if (is_not_list(list)) {
+ BIF_ERROR(p, BADARG);
}
- need = 2*i;
- hp = HAlloc(p, need);
- list = A;
+ /* optimistic append on heap first */
+
+ if ((i = HeapWordsLeft(p) / 2) < 4) {
+ goto list_tail;
+ }
+
+ hp = HEAP_TOP(p);
copy = last = CONS(hp, CAR(list_val(list)), make_list(hp+2));
list = CDR(list_val(list));
- hp += 2;
+ hp += 2;
+ i -= 2; /* don't use the last 2 words (extra i--;) */
+
+ while(i-- && is_list(list)) {
+ Eterm* listp = list_val(list);
+ last = CONS(hp, CAR(listp), make_list(hp+2));
+ list = CDR(listp);
+ hp += 2;
+ }
+
+ /* A is proper and B is NIL return A as-is, don't update HTOP */
+
+ if (is_nil(list) && is_nil(B)) {
+ BIF_RET(A);
+ }
+
+ if (is_nil(list)) {
+ HEAP_TOP(p) = hp;
+ CDR(list_val(last)) = B;
+ BIF_RET(copy);
+ }
+
+list_tail:
+
+ if ((i = erts_list_length(list)) < 0) {
+ BIF_ERROR(p, BADARG);
+ }
+
+ /* remaining list was proper and B is NIL */
+ if (is_nil(B)) {
+ BIF_RET(A);
+ }
+
+ if (hp) {
+ /* Note: fall through case, already written
+ * on the heap.
+ * The last 2 words of the heap is not written yet
+ */
+ Eterm *hp_save = hp;
+ ASSERT(i != 0);
+ HEAP_TOP(p) = hp + 2;
+ if (i == 1) {
+ hp[0] = CAR(list_val(list));
+ hp[1] = B;
+ BIF_RET(copy);
+ }
+ hp = HAlloc(p, 2*(i - 1));
+ last = CONS(hp_save, CAR(list_val(list)), make_list(hp));
+ } else {
+ hp = HAlloc(p, 2*i);
+ copy = last = CONS(hp, CAR(list_val(list)), make_list(hp+2));
+ hp += 2;
+ }
+
+ list = CDR(list_val(list));
i--;
+
+ ASSERT(i > -1);
while(i--) {
- Eterm* listp = list_val(list);
- last = CONS(hp, CAR(listp), make_list(hp+2));
- list = CDR(listp);
- hp += 2;
+ Eterm* listp = list_val(list);
+ last = CONS(hp, CAR(listp), make_list(hp+2));
+ list = CDR(listp);
+ hp += 2;
}
+
CDR(list_val(last)) = B;
BIF_RET(copy);
}
diff --git a/erts/emulator/beam/erl_bif_op.c b/erts/emulator/beam/erl_bif_op.c
index 0f20ded1d6..aecb8bf0c1 100644
--- a/erts/emulator/beam/erl_bif_op.c
+++ b/erts/emulator/beam/erl_bif_op.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/beam/erl_bif_os.c b/erts/emulator/beam/erl_bif_os.c
index 2333ca0851..46777d3aa5 100644
--- a/erts/emulator/beam/erl_bif_os.c
+++ b/erts/emulator/beam/erl_bif_os.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2012. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c
index 86bcf43678..37f4e1de49 100644
--- a/erts/emulator/beam/erl_bif_port.c
+++ b/erts/emulator/beam/erl_bif_port.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
@@ -79,6 +79,7 @@ BIF_RETTYPE erts_internal_open_port_2(BIF_ALIST_2)
}
if (port->drv_ptr->flags & ERL_DRV_FLAG_USE_INIT_ACK) {
+
/* Copied from erl_port_task.c */
port->async_open_port = erts_alloc(ERTS_ALC_T_PRTSD,
sizeof(*port->async_open_port));
@@ -109,6 +110,10 @@ BIF_RETTYPE erts_internal_open_port_2(BIF_ALIST_2)
erts_add_link(&ERTS_P_LINKS(port), LINK_PID, BIF_P->common.id);
erts_add_link(&ERTS_P_LINKS(BIF_P), LINK_PID, port->common.id);
+ if (IS_TRACED_FL(BIF_P, F_TRACE_PROCS))
+ trace_proc(BIF_P, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_LINK, BIF_P,
+ am_link, port->common.id);
+
erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_LINK);
erts_port_release(port);
@@ -339,8 +344,7 @@ BIF_RETTYPE erts_internal_port_close_1(BIF_ALIST_1)
if (!prt)
BIF_RET(am_badarg);
-
- switch (erts_port_exit(BIF_P, 0, prt, prt->common.id, am_normal, &ref)) {
+ switch (erts_port_exit(BIF_P, 0, prt, BIF_P->common.id, am_normal, &ref)) {
case ERTS_PORT_OP_CALLER_EXIT:
case ERTS_PORT_OP_BADARG:
case ERTS_PORT_OP_DROPPED:
@@ -373,7 +377,7 @@ BIF_RETTYPE erts_internal_port_connect_2(BIF_ALIST_2)
ref = NIL;
#endif
- switch (erts_port_connect(BIF_P, 0, prt, prt->common.id, BIF_ARG_2, &ref)) {
+ switch (erts_port_connect(BIF_P, 0, prt, BIF_P->common.id, BIF_ARG_2, &ref)) {
case ERTS_PORT_OP_CALLER_EXIT:
case ERTS_PORT_OP_BADARG:
case ERTS_PORT_OP_DROPPED:
@@ -911,7 +915,7 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump)
}
if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) {
- trace_virtual_sched(p, am_out);
+ trace_sched(p, ERTS_PROC_LOCK_MAIN, am_out);
}
@@ -928,21 +932,22 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump)
DTRACE3(port_open, process_str, name_buf, port_str);
}
#endif
+
+ if (port && IS_TRACED_FL(port, F_TRACE_PORTS))
+ trace_port(port, am_getting_linked, p->common.id);
+
erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
+ if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) {
+ trace_sched(p, ERTS_PROC_LOCK_MAIN, am_in);
+ }
+
if (!port) {
DEBUGF(("open_driver returned (%d:%d)\n",
err_typep ? *err_typep : 4711,
err_nump ? *err_nump : 4711));
- if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) {
- trace_virtual_sched(p, am_in);
- }
goto do_return;
}
-
- if (IS_TRACED_FL(p, F_TRACE_SCHED_PROCS)) {
- trace_virtual_sched(p, am_in);
- }
if (linebuf && port->linebuf == NULL){
port->linebuf = allocate_linebuf(linebuf);
@@ -985,6 +990,8 @@ static char **convert_args(Eterm l)
}
n = erts_list_length(l);
+ if (n < 0)
+ return NULL;
/* We require at least one element in argv[0] + NULL at end */
pp = erts_alloc(ERTS_ALC_T_TMP, (n + 2) * sizeof(char **));
pp[i++] = erts_default_arg0;
diff --git a/erts/emulator/beam/erl_bif_re.c b/erts/emulator/beam/erl_bif_re.c
index 7f7cd376ac..f4daecd2a4 100644
--- a/erts/emulator/beam/erl_bif_re.c
+++ b/erts/emulator/beam/erl_bif_re.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c
index 71a7079b09..b65c0e303f 100644
--- a/erts/emulator/beam/erl_bif_trace.c
+++ b/erts/emulator/beam/erl_bif_trace.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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.
@@ -52,7 +52,7 @@ static int erts_default_trace_pattern_is_on;
static Binary *erts_default_match_spec;
static Binary *erts_default_meta_match_spec;
static struct trace_pattern_flags erts_default_trace_pattern_flags;
-static Eterm erts_default_meta_tracer_pid;
+static ErtsTracer erts_default_meta_tracer;
static struct { /* Protected by code write permission */
int current;
@@ -68,6 +68,9 @@ static struct { /* Protected by code write permission */
static Eterm
trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist);
+static int
+erts_set_tracing_event_pattern(Eterm event, Binary*, int on);
+
#ifdef ERTS_SMP
static void smp_bp_finisher(void* arg);
#endif
@@ -75,11 +78,11 @@ static BIF_RETTYPE
system_monitor(Process *p, Eterm monitor_pid, Eterm list);
static void new_seq_trace_token(Process* p); /* help func for seq_trace_2*/
-static int already_traced(Process *p, Process *tracee_p, Eterm tracer);
-static int port_already_traced(Process *p, Port *tracee_port, Eterm tracer);
static Eterm trace_info_pid(Process* p, Eterm pid_spec, Eterm key);
static Eterm trace_info_func(Process* p, Eterm pid_spec, Eterm key);
static Eterm trace_info_on_load(Process* p, Eterm key);
+static Eterm trace_info_event(Process* p, Eterm event, Eterm key);
+
static void reset_bif_trace(void);
static void setup_bif_trace(void);
@@ -87,28 +90,34 @@ static void install_exp_breakpoints(BpFunctions* f);
static void uninstall_exp_breakpoints(BpFunctions* f);
static void clean_export_entries(BpFunctions* f);
+ErtsTracingEvent erts_send_tracing[ERTS_NUM_BP_IX];
+ErtsTracingEvent erts_receive_tracing[ERTS_NUM_BP_IX];
+
void
erts_bif_trace_init(void)
{
+ int i;
+
erts_default_trace_pattern_is_on = 0;
erts_default_match_spec = NULL;
erts_default_meta_match_spec = NULL;
erts_default_trace_pattern_flags = erts_trace_pattern_flags_off;
- erts_default_meta_tracer_pid = NIL;
+ erts_default_meta_tracer = erts_tracer_nil;
+
+ for (i=0; i<ERTS_NUM_BP_IX; i++) {
+ erts_send_tracing[i].on = 1;
+ erts_send_tracing[i].match_spec = NULL;
+ erts_receive_tracing[i].on = 1;
+ erts_receive_tracing[i].match_spec = NULL;
+ }
}
/*
* Turn on/off call tracing for the given function(s).
*/
-
-Eterm
-trace_pattern_2(BIF_ALIST_2)
-{
- return trace_pattern(BIF_P, BIF_ARG_1, BIF_ARG_2, NIL);
-}
Eterm
-trace_pattern_3(BIF_ALIST_3)
+erts_internal_trace_pattern_3(BIF_ALIST_3)
{
return trace_pattern(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3);
}
@@ -125,11 +134,10 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist)
Eterm l;
struct trace_pattern_flags flags = erts_trace_pattern_flags_off;
int is_global;
- Process *meta_tracer_proc = p;
- Eterm meta_tracer_pid = p->common.id;
+ ErtsTracer meta_tracer = erts_tracer_nil;
if (!erts_try_seize_code_write_permission(p)) {
- ERTS_BIF_YIELD3(bif_export[BIF_trace_pattern_3], p, MFA, Pattern, flaglist);
+ ERTS_BIF_YIELD3(bif_export[BIF_erts_internal_trace_pattern_3], p, MFA, Pattern, flaglist);
}
finish_bp.current = -1;
@@ -146,45 +154,28 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist)
on = 1;
} else if (Pattern == am_restart) {
match_prog_set = NULL;
- on = erts_break_reset;
+ on = ERTS_BREAK_RESTART;
} else if (Pattern == am_pause) {
match_prog_set = NULL;
- on = erts_break_stop;
- } else if ((match_prog_set = erts_match_set_compile(p, Pattern)) != NULL) {
- MatchSetRef(match_prog_set);
- on = 1;
- } else{
- goto error;
+ on = ERTS_BREAK_PAUSE;
+ } else {
+ match_prog_set = erts_match_set_compile(p, Pattern, MFA);
+ if (match_prog_set) {
+ MatchSetRef(match_prog_set);
+ on = 1;
+ } else{
+ goto error;
+ }
}
is_global = 0;
for(l = flaglist; is_list(l); l = CDR(list_val(l))) {
if (is_tuple(CAR(list_val(l)))) {
- Eterm *tp = tuple_val(CAR(list_val(l)));
-
- if (arityval(tp[0]) != 2 || tp[1] != am_meta) {
- goto error;
- }
- meta_tracer_pid = tp[2];
- if (is_internal_pid(meta_tracer_pid)) {
- meta_tracer_proc = erts_pid2proc(NULL, 0, meta_tracer_pid, 0);
- if (!meta_tracer_proc) {
- goto error;
- }
- } else if (is_internal_port(meta_tracer_pid)) {
- Port *meta_tracer_port;
- meta_tracer_proc = NULL;
- meta_tracer_port = (erts_port_lookup(
- meta_tracer_pid,
- ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP));
- if (!meta_tracer_port)
- goto error;
- } else {
- goto error;
- }
- if (is_global) {
- goto error;
- }
+ meta_tracer = erts_term_to_tracer(am_meta, CAR(list_val(l)));
+ if (meta_tracer == THE_NON_VALUE) {
+ meta_tracer = erts_tracer_nil;
+ goto error;
+ }
flags.breakpoint = 1;
flags.meta = 1;
} else {
@@ -202,6 +193,8 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist)
}
flags.breakpoint = 1;
flags.meta = 1;
+ if (ERTS_TRACER_IS_NIL(meta_tracer))
+ meta_tracer = erts_term_to_tracer(THE_NON_VALUE, p->common.id);
break;
case am_global:
if (flags.breakpoint) {
@@ -252,14 +245,11 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist)
MatchSetUnref(erts_default_meta_match_spec);
erts_default_meta_match_spec = match_prog_set;
MatchSetRef(erts_default_meta_match_spec);
- erts_default_meta_tracer_pid = meta_tracer_pid;
- if (meta_tracer_proc) {
- ERTS_TRACE_FLAGS(meta_tracer_proc) |= F_TRACER;
- }
+ erts_tracer_update(&erts_default_meta_tracer, meta_tracer);
} else if (! flags.breakpoint) {
MatchSetUnref(erts_default_meta_match_spec);
erts_default_meta_match_spec = NULL;
- erts_default_meta_tracer_pid = NIL;
+ ERTS_TRACER_CLEAR(&erts_default_meta_tracer);
}
if (erts_default_trace_pattern_flags.breakpoint &&
flags.breakpoint) {
@@ -340,20 +330,23 @@ trace_pattern(Process* p, Eterm MFA, Eterm Pattern, Eterm flaglist)
if (is_small(mfa[2])) {
mfa[2] = signed_val(mfa[2]);
}
-
- if (meta_tracer_proc) {
- ERTS_TRACE_FLAGS(meta_tracer_proc) |= F_TRACER;
- }
matches = erts_set_trace_pattern(p, mfa, specified,
match_prog_set, match_prog_set,
- on, flags, meta_tracer_pid, 0);
+ on, flags, meta_tracer, 0);
+ } else if (is_atom(MFA)) {
+ if (is_global || flags.breakpoint || on > ERTS_BREAK_SET) {
+ goto error;
+ }
+ matches = erts_set_tracing_event_pattern(MFA, match_prog_set, on);
}
error:
MatchSetUnref(match_prog_set);
UnUseTmpHeap(3,p);
+ ERTS_TRACER_CLEAR(&meta_tracer);
+
#ifdef ERTS_SMP
if (finish_bp.current >= 0) {
ASSERT(matches >= 0);
@@ -404,7 +397,7 @@ erts_get_default_trace_pattern(int *trace_pattern_is_on,
Binary **match_spec,
Binary **meta_match_spec,
struct trace_pattern_flags *trace_pattern_flags,
- Eterm *meta_tracer_pid)
+ ErtsTracer *meta_tracer)
{
ERTS_SMP_LC_ASSERT(erts_has_code_write_permission() ||
erts_smp_thr_progress_is_blocking());
@@ -416,8 +409,8 @@ erts_get_default_trace_pattern(int *trace_pattern_is_on,
*meta_match_spec = erts_default_meta_match_spec;
if (trace_pattern_flags)
*trace_pattern_flags = erts_default_trace_pattern_flags;
- if (meta_tracer_pid)
- *meta_tracer_pid = erts_default_meta_tracer_pid;
+ if (meta_tracer)
+ *meta_tracer = erts_default_meta_tracer;
}
int erts_is_default_trace_enabled(void)
@@ -465,12 +458,12 @@ erts_trace_flag2bit(Eterm flag)
** occurred in the argument list.
*/
int
-erts_trace_flags(Eterm List,
- Uint *pMask, Eterm *pTracer, int *pCpuTimestamp)
+erts_trace_flags(Eterm List,
+ Uint *pMask, ErtsTracer *pTracer, int *pCpuTimestamp)
{
Eterm list = List;
Uint mask = 0;
- Eterm tracer = NIL;
+ ErtsTracer tracer = erts_tracer_nil;
int cpu_timestamp = 0;
while (is_list(list)) {
@@ -483,33 +476,73 @@ erts_trace_flags(Eterm List,
cpu_timestamp = !0;
#endif
} else if (is_tuple(item)) {
- Eterm* tp = tuple_val(item);
-
- if (arityval(tp[0]) != 2 || tp[1] != am_tracer) goto error;
- if (is_internal_pid(tp[2]) || is_internal_port(tp[2])) {
- tracer = tp[2];
- } else goto error;
+ tracer = erts_term_to_tracer(am_tracer, item);
+ if (tracer == THE_NON_VALUE)
+ goto error;
} else goto error;
list = CDR(list_val(list));
}
if (is_not_nil(list)) goto error;
- if (pMask && mask) *pMask = mask;
- if (pTracer && tracer != NIL) *pTracer = tracer;
- if (pCpuTimestamp && cpu_timestamp) *pCpuTimestamp = cpu_timestamp;
+ if (pMask && mask) *pMask = mask;
+ if (pTracer && !ERTS_TRACER_IS_NIL(tracer)) *pTracer = tracer;
+ if (pCpuTimestamp && cpu_timestamp) *pCpuTimestamp = cpu_timestamp;
return !0;
error:
return 0;
}
-Eterm trace_3(BIF_ALIST_3)
+static ERTS_INLINE int
+start_trace(Process *c_p, ErtsTracer tracer,
+ ErtsPTabElementCommon *common,
+ int on, int mask)
+{
+ /* We can use the common part of both port+proc without checking what it is
+ In the code below port is used for both proc and port */
+ Port *port = (Port*)common;
+
+ /*
+ * SMP build assumes that either system is blocked or:
+ * * main lock is held on c_p
+ * * all locks are held on port common
+ */
+
+ if (!ERTS_TRACER_IS_NIL(tracer)) {
+ if ((ERTS_TRACE_FLAGS(port) & TRACEE_FLAGS)
+ && !ERTS_TRACER_COMPARE(ERTS_TRACER(port), tracer)) {
+ /* This tracee is already being traced, and not by the
+ * tracer to be */
+ if (erts_is_tracer_proc_enabled(c_p, ERTS_PROC_LOCKS_ALL,
+ common, am_trace_status)) {
+ /* The tracer is still in use */
+ return 1;
+ }
+ /* Current tracer now invalid */
+ }
+ }
+
+ if (on)
+ ERTS_TRACE_FLAGS(port) |= mask;
+ else
+ ERTS_TRACE_FLAGS(port) &= ~mask;
+
+ if ((ERTS_TRACE_FLAGS(port) & TRACEE_FLAGS) == 0) {
+ tracer = erts_tracer_nil;
+ erts_tracer_replace(common, erts_tracer_nil);
+ } else if (!ERTS_TRACER_IS_NIL(tracer))
+ erts_tracer_replace(common, tracer);
+
+ return 0;
+}
+
+Eterm erts_internal_trace_3(BIF_ALIST_3)
{
Process* p = BIF_P;
Eterm pid_spec = BIF_ARG_1;
Eterm how = BIF_ARG_2;
Eterm list = BIF_ARG_3;
int on;
- Eterm tracer = NIL;
+ ErtsTracer tracer = erts_tracer_nil;
int matches = 0;
Uint mask = 0;
int cpu_ts = 0;
@@ -522,41 +555,24 @@ Eterm trace_3(BIF_ALIST_3)
}
if (!erts_try_seize_code_write_permission(BIF_P)) {
- ERTS_BIF_YIELD3(bif_export[BIF_trace_3], BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3);
+ ERTS_BIF_YIELD3(bif_export[BIF_erts_internal_trace_3],
+ BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3);
}
- if (is_nil(tracer) || is_internal_pid(tracer)) {
- Process *tracer_proc = erts_pid2proc(p,
- ERTS_PROC_LOCK_MAIN,
- is_nil(tracer) ? p->common.id : tracer,
- ERTS_PROC_LOCKS_ALL);
- if (!tracer_proc)
- goto error;
- ERTS_TRACE_FLAGS(tracer_proc) |= F_TRACER;
- erts_smp_proc_unlock(tracer_proc,
- (tracer_proc == p
- ? ERTS_PROC_LOCKS_ALL_MINOR
- : ERTS_PROC_LOCKS_ALL));
- } else if (is_internal_port(tracer)) {
- Port *tracer_port = erts_id2port_sflgs(tracer,
- p,
- ERTS_PROC_LOCK_MAIN,
- ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP);
- if (!tracer_port)
- goto error;
- ERTS_TRACE_FLAGS(tracer_port) |= F_TRACER;
- erts_port_release(tracer_port);
- } else
- goto error;
-
switch (how) {
case am_false:
on = 0;
break;
case am_true:
on = 1;
- if (is_nil(tracer))
- tracer = p->common.id;
+ if (ERTS_TRACER_IS_NIL(tracer))
+ tracer = erts_term_to_tracer(am_tracer, p->common.id);
+
+ if (tracer == THE_NON_VALUE) {
+ tracer = erts_tracer_nil;
+ goto error;
+ }
+
break;
default:
goto error;
@@ -575,34 +591,20 @@ Eterm trace_3(BIF_ALIST_3)
}
#endif
- if (pid_spec == tracer)
- goto error;
-
tracee_port = erts_id2port_sflgs(pid_spec,
p,
ERTS_PROC_LOCK_MAIN,
ERTS_PORT_SFLGS_INVALID_LOOKUP);
+
if (!tracee_port)
goto error;
-
- if (tracer != NIL && port_already_traced(p, tracee_port, tracer)) {
+
+ if (start_trace(p, tracer, &tracee_port->common, on, mask)) {
erts_port_release(tracee_port);
goto already_traced;
- }
-
- if (on)
- ERTS_TRACE_FLAGS(tracee_port) |= mask;
- else
- ERTS_TRACE_FLAGS(tracee_port) &= ~mask;
-
- if (!ERTS_TRACE_FLAGS(tracee_port))
- ERTS_TRACER_PROC(tracee_port) = NIL;
- else if (tracer != NIL)
- ERTS_TRACER_PROC(tracee_port) = tracer;
-
- erts_port_release(tracee_port);
-
- matches = 1;
+ }
+ erts_port_release(tracee_port);
+ matches = 1;
} else if (is_pid(pid_spec)) {
Process *tracee_p;
@@ -615,33 +617,19 @@ Eterm trace_3(BIF_ALIST_3)
* and not about to be tracing.
*/
- if (pid_spec == tracer)
- goto error;
-
tracee_p = erts_pid2proc(p, ERTS_PROC_LOCK_MAIN,
pid_spec, ERTS_PROC_LOCKS_ALL);
if (!tracee_p)
goto error;
- if (tracer != NIL && already_traced(p, tracee_p, tracer)) {
+ if (start_trace(tracee_p, tracer, &tracee_p->common, on, mask)) {
erts_smp_proc_unlock(tracee_p,
(tracee_p == p
? ERTS_PROC_LOCKS_ALL_MINOR
: ERTS_PROC_LOCKS_ALL));
goto already_traced;
- }
-
- if (on)
- ERTS_TRACE_FLAGS(tracee_p) |= mask;
- else
- ERTS_TRACE_FLAGS(tracee_p) &= ~mask;
-
- if ((ERTS_TRACE_FLAGS(tracee_p) & TRACEE_FLAGS) == 0)
- ERTS_TRACER_PROC(tracee_p) = NIL;
- else if (tracer != NIL)
- ERTS_TRACER_PROC(tracee_p) = tracer;
-
- erts_smp_proc_unlock(tracee_p,
+ }
+ erts_smp_proc_unlock(tracee_p,
(tracee_p == p
? ERTS_PROC_LOCKS_ALL_MINOR
: ERTS_PROC_LOCKS_ALL));
@@ -692,18 +680,27 @@ Eterm trace_3(BIF_ALIST_3)
}
#endif
- if (pid_spec == am_all || pid_spec == am_existing) {
+ if (pid_spec == am_all || pid_spec == am_existing ||
+ pid_spec == am_ports || pid_spec == am_processes ||
+ pid_spec == am_existing_ports || pid_spec == am_existing_processes
+ ) {
int i;
int procs = 0;
int ports = 0;
int mods = 0;
if (mask & (ERTS_PROC_TRACEE_FLAGS & ~ERTS_TRACEE_MODIFIER_FLAGS))
- procs = 1;
+ procs = pid_spec != am_ports && pid_spec != am_existing_ports;
if (mask & (ERTS_PORT_TRACEE_FLAGS & ~ERTS_TRACEE_MODIFIER_FLAGS))
- ports = 1;
- if (mask & ERTS_TRACEE_MODIFIER_FLAGS)
- mods = 1;
+ ports = pid_spec != am_processes && pid_spec != am_existing_processes;
+ if (mask & ERTS_TRACEE_MODIFIER_FLAGS) {
+ if (pid_spec == am_ports || pid_spec == am_existing_ports)
+ ports = 1;
+ else if (pid_spec == am_processes || pid_spec == am_existing_processes)
+ procs = 1;
+ else
+ mods = 1;
+ }
#ifdef ERTS_SMP
erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN);
@@ -719,22 +716,7 @@ Eterm trace_3(BIF_ALIST_3)
Process* tracee_p = erts_pix2proc(i);
if (! tracee_p)
continue;
- if (tracer != NIL) {
- if (tracee_p->common.id == tracer)
- continue;
- if (already_traced(NULL, tracee_p, tracer))
- continue;
- }
- if (on) {
- ERTS_TRACE_FLAGS(tracee_p) |= mask;
- } else {
- ERTS_TRACE_FLAGS(tracee_p) &= ~mask;
- }
- if(!(ERTS_TRACE_FLAGS(tracee_p) & TRACEE_FLAGS)) {
- ERTS_TRACER_PROC(tracee_p) = NIL;
- } else if (tracer != NIL) {
- ERTS_TRACER_PROC(tracee_p) = tracer;
- }
+ start_trace(p, tracer, &tracee_p->common, on, mask);
matches++;
}
}
@@ -749,33 +731,26 @@ Eterm trace_3(BIF_ALIST_3)
state = erts_atomic32_read_nob(&tracee_port->state);
if (state & ERTS_PORT_SFLGS_DEAD)
continue;
- if (tracer != NIL) {
- if (tracee_port->common.id == tracer)
- continue;
- if (port_already_traced(NULL, tracee_port, tracer))
- continue;
- }
-
- if (on) ERTS_TRACE_FLAGS(tracee_port) |= mask;
- else ERTS_TRACE_FLAGS(tracee_port) &= ~mask;
-
- if (!(ERTS_TRACE_FLAGS(tracee_port) & TRACEE_FLAGS)) {
- ERTS_TRACER_PROC(tracee_port) = NIL;
- } else if (tracer != NIL) {
- ERTS_TRACER_PROC(tracee_port) = tracer;
- }
- /* matches are not counted for ports since it would violate compatibility */
- /* This could be a reason to modify this function or make a new one. */
+ start_trace(p, tracer, &tracee_port->common, on, mask);
+ matches++;
}
}
}
- if (pid_spec == am_all || pid_spec == am_new) {
- Uint def_flags = mask;
- Eterm def_tracer = tracer;
+ if (pid_spec == am_all || pid_spec == am_new
+ || pid_spec == am_ports || pid_spec == am_processes
+ || pid_spec == am_new_ports || pid_spec == am_new_processes
+ ) {
ok = 1;
- erts_change_default_tracing(on, &def_flags, &def_tracer);
+ if (mask & ERTS_PROC_TRACEE_FLAGS &&
+ pid_spec != am_ports && pid_spec != am_new_ports)
+ erts_change_default_proc_tracing(
+ on, mask & ERTS_PROC_TRACEE_FLAGS, tracer);
+ if (mask & ERTS_PORT_TRACEE_FLAGS &&
+ pid_spec != am_processes && pid_spec != am_new_processes)
+ erts_change_default_port_tracing(
+ on, mask & ERTS_PORT_TRACEE_FLAGS, tracer);
#ifdef HAVE_ERTS_NOW_CPU
if (cpu_ts && !on) {
@@ -801,6 +776,7 @@ Eterm trace_3(BIF_ALIST_3)
}
#endif
erts_release_code_write_permission();
+ ERTS_TRACER_CLEAR(&tracer);
BIF_RET(make_small(matches));
@@ -810,6 +786,8 @@ Eterm trace_3(BIF_ALIST_3)
error:
+ ERTS_TRACER_CLEAR(&tracer);
+
#ifdef ERTS_SMP
if (system_blocked) {
erts_smp_thr_progress_unblock();
@@ -821,88 +799,6 @@ Eterm trace_3(BIF_ALIST_3)
BIF_ERROR(p, BADARG);
}
-/* Check that the process to be traced is not already traced
- * by a valid other tracer than the tracer to be.
- */
-static int port_already_traced(Process *c_p, Port *tracee_port, Eterm tracer)
-{
- /*
- * SMP build assumes that either system is blocked or:
- * * main lock is held on c_p
- * * all locks are held on port tracee_p
- */
- if ((ERTS_TRACE_FLAGS(tracee_port) & TRACEE_FLAGS)
- && ERTS_TRACER_PROC(tracee_port) != tracer) {
- /* This tracee is already being traced, and not by the
- * tracer to be */
- if (is_internal_port(ERTS_TRACER_PROC(tracee_port))) {
- if (!erts_is_valid_tracer_port(ERTS_TRACER_PROC(tracee_port))) {
- /* Current trace port now invalid
- * - discard it and approve the new. */
- goto remove_tracer;
- } else
- return 1;
- }
- else if(is_internal_pid(ERTS_TRACER_PROC(tracee_port))) {
- Process *tracer_p = erts_proc_lookup(ERTS_TRACER_PROC(tracee_port));
- if (!tracer_p) {
- /* Current trace process now invalid
- * - discard it and approve the new. */
- goto remove_tracer;
- } else
- return 1;
- }
- else {
- remove_tracer:
- ERTS_TRACE_FLAGS(tracee_port) &= ~TRACEE_FLAGS;
- ERTS_TRACER_PROC(tracee_port) = NIL;
- }
- }
- return 0;
-}
-
-/* Check that the process to be traced is not already traced
- * by a valid other tracer than the tracer to be.
- */
-static int already_traced(Process *c_p, Process *tracee_p, Eterm tracer)
-{
- /*
- * SMP build assumes that either system is blocked or:
- * * main lock is held on c_p
- * * all locks multiple are held on tracee_p
- */
- if ((ERTS_TRACE_FLAGS(tracee_p) & TRACEE_FLAGS)
- && ERTS_TRACER_PROC(tracee_p) != tracer) {
- /* This tracee is already being traced, and not by the
- * tracer to be */
- if (is_internal_port(ERTS_TRACER_PROC(tracee_p))) {
- if (!erts_is_valid_tracer_port(ERTS_TRACER_PROC(tracee_p))) {
- /* Current trace port now invalid
- * - discard it and approve the new. */
- goto remove_tracer;
- } else
- return 1;
- }
- else if(is_internal_pid(ERTS_TRACER_PROC(tracee_p))) {
- Process *tracer_p;
-
- tracer_p = erts_proc_lookup(ERTS_TRACER_PROC(tracee_p));
- if (!tracer_p) {
- /* Current trace process now invalid
- * - discard it and approve the new. */
- goto remove_tracer;
- } else
- return 1;
- }
- else {
- remove_tracer:
- ERTS_TRACE_FLAGS(tracee_p) &= ~TRACEE_FLAGS;
- ERTS_TRACER_PROC(tracee_p) = NIL;
- }
- }
- return 0;
-}
-
/*
* Return information about a process or an external function being traced.
*/
@@ -920,7 +816,9 @@ Eterm trace_info_2(BIF_ALIST_2)
if (What == am_on_load) {
res = trace_info_on_load(p, Key);
- } else if (is_atom(What) || is_pid(What)) {
+ } else if (What == am_send || What == am_receive) {
+ res = trace_info_event(p, What, Key);
+ } else if (is_atom(What) || is_pid(What) || is_port(What)) {
res = trace_info_pid(p, What, Key);
} else if (is_tuple(What)) {
res = trace_info_func(p, What, Key);
@@ -936,41 +834,52 @@ static Eterm
trace_info_pid(Process* p, Eterm pid_spec, Eterm key)
{
Eterm tracer;
- Uint trace_flags;
+ Uint trace_flags = am_false;
Eterm* hp;
- if (pid_spec == am_new) {
- erts_get_default_tracing(&trace_flags, &tracer);
+ if (pid_spec == am_new || pid_spec == am_new_processes) {
+ ErtsTracer def_tracer;
+ erts_get_default_proc_tracing(&trace_flags, &def_tracer);
+ tracer = erts_tracer_to_term(p, def_tracer);
+ ERTS_TRACER_CLEAR(&def_tracer);
+ } else if (pid_spec == am_new_ports) {
+ ErtsTracer def_tracer;
+ erts_get_default_port_tracing(&trace_flags, &def_tracer);
+ tracer = erts_tracer_to_term(p, def_tracer);
+ ERTS_TRACER_CLEAR(&def_tracer);
+ } else if (is_internal_port(pid_spec)) {
+ Port *tracee;
+ tracee = erts_id2port_sflgs(pid_spec, p, ERTS_PROC_LOCK_MAIN,
+ ERTS_PORT_SFLGS_INVALID_LOOKUP);
+
+ if (!tracee)
+ return am_undefined;
+
+ if (!ERTS_TRACER_IS_NIL(ERTS_TRACER(tracee)))
+ erts_is_tracer_proc_enabled(NULL, 0, &tracee->common, am_trace_status);
+
+ tracer = erts_tracer_to_term(p, ERTS_TRACER(tracee));
+ trace_flags = ERTS_TRACE_FLAGS(tracee);
+
+ erts_port_release(tracee);
+
} else if (is_internal_pid(pid_spec)) {
Process *tracee;
tracee = erts_pid2proc(p, ERTS_PROC_LOCK_MAIN,
- pid_spec, ERTS_PROC_LOCKS_ALL);
+ pid_spec, ERTS_PROC_LOCK_MAIN);
- if (!tracee) {
+ if (!tracee)
return am_undefined;
- } else {
- tracer = ERTS_TRACER_PROC(tracee);
- trace_flags = ERTS_TRACE_FLAGS(tracee);
- }
- if (is_internal_pid(tracer)) {
- if (!erts_proc_lookup(tracer)) {
- reset_tracer:
- ERTS_TRACE_FLAGS(tracee) &= ~TRACEE_FLAGS;
- trace_flags = ERTS_TRACE_FLAGS(tracee);
- tracer = ERTS_TRACER_PROC(tracee) = NIL;
- }
- }
- else if (is_internal_port(tracer)) {
- if (!erts_is_valid_tracer_port(tracer))
- goto reset_tracer;
- }
-#ifdef ERTS_SMP
- erts_smp_proc_unlock(tracee,
- (tracee == p
- ? ERTS_PROC_LOCKS_ALL_MINOR
- : ERTS_PROC_LOCKS_ALL));
-#endif
+ if (!ERTS_TRACER_IS_NIL(ERTS_TRACER(tracee)))
+ erts_is_tracer_proc_enabled(tracee, ERTS_PROC_LOCK_MAIN,
+ &tracee->common, am_trace_status);
+
+ tracer = erts_tracer_to_term(p, ERTS_TRACER(tracee));
+ trace_flags = ERTS_TRACE_FLAGS(tracee);
+
+ if (tracee != p)
+ erts_smp_proc_unlock(tracee, ERTS_PROC_LOCK_MAIN);
} else if (is_external_pid(pid_spec)
&& external_pid_dist_entry(pid_spec) == erts_this_dist_entry) {
return am_undefined;
@@ -1024,8 +933,10 @@ trace_info_pid(Process* p, Eterm pid_spec, Eterm key)
HRelease(p,limit,hp+3);
return TUPLE2(hp, key, flag_list);
} else if (key == am_tracer) {
- hp = HAlloc(p, 3);
- return TUPLE2(hp, key, tracer); /* Local pid or port */
+ if (tracer == am_false)
+ tracer = NIL;
+ hp = HAlloc(p, 3);
+ return TUPLE2(hp, key, tracer);
} else {
goto error;
}
@@ -1054,11 +965,11 @@ trace_info_pid(Process* p, Eterm pid_spec, Eterm key)
*/
static int function_is_traced(Process *p,
Eterm mfa[3],
- Binary **ms, /* out */
- Binary **ms_meta, /* out */
- Eterm *tracer_pid_meta, /* out */
- Uint *count, /* out */
- Eterm *call_time) /* out */
+ Binary **ms, /* out */
+ Binary **ms_meta, /* out */
+ ErtsTracer *tracer_pid_meta, /* out */
+ Uint *count, /* out */
+ Eterm *call_time) /* out */
{
Export e;
Export* ep;
@@ -1123,7 +1034,7 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key)
Eterm traced = am_false;
Eterm match_spec = am_false;
Eterm retval = am_false;
- Eterm meta = am_false;
+ ErtsTracer meta = erts_tracer_nil;
Eterm call_time = NIL;
int r;
@@ -1193,7 +1104,10 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key)
retval = match_spec;
break;
case am_meta:
- retval = meta;
+ retval = erts_tracer_to_term(p, meta);
+ if (retval == am_false)
+ /* backwards compatibility */
+ retval = NIL;
break;
case am_meta_match_spec:
if (r & FUNC_TRACE_META_TRACE) {
@@ -1216,7 +1130,8 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key)
}
break;
case am_all: {
- Eterm match_spec_meta = am_false, c = am_false, t, ct = am_false;
+ Eterm match_spec_meta = am_false, c = am_false, t, ct = am_false,
+ m = am_false;
if (ms) {
match_spec = MatchSetGetSource(ms);
@@ -1235,6 +1150,9 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key)
if (r & FUNC_TRACE_TIME_TRACE) {
ct = call_time;
}
+
+ m = erts_tracer_to_term(p, meta);
+
hp = HAlloc(p, (3+2)*6);
retval = NIL;
t = TUPLE2(hp, am_call_count, c); hp += 3;
@@ -1243,7 +1161,7 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key)
retval = CONS(hp, t, retval); hp += 2;
t = TUPLE2(hp, am_meta_match_spec, match_spec_meta); hp += 3;
retval = CONS(hp, t, retval); hp += 2;
- t = TUPLE2(hp, am_meta, meta); hp += 3;
+ t = TUPLE2(hp, am_meta, m); hp += 3;
retval = CONS(hp, t, retval); hp += 2;
t = TUPLE2(hp, am_match_spec, match_spec); hp += 3;
retval = CONS(hp, t, retval); hp += 2;
@@ -1306,7 +1224,8 @@ trace_info_on_load(Process* p, Eterm key)
case am_meta:
hp = HAlloc(p, 3);
if (erts_default_trace_pattern_flags.meta) {
- return TUPLE2(hp, key, erts_default_meta_tracer_pid);
+ ASSERT(!ERTS_TRACER_IS_NIL(erts_default_meta_tracer));
+ return TUPLE2(hp, key, erts_tracer_to_term(p, erts_default_meta_tracer));
} else {
return TUPLE2(hp, key, am_false);
}
@@ -1345,7 +1264,7 @@ trace_info_on_load(Process* p, Eterm key)
}
case am_all:
{
- Eterm match_spec = am_false, meta_match_spec = am_false, r = NIL, t;
+ Eterm match_spec = am_false, meta_match_spec = am_false, r = NIL, t, m;
if (erts_default_trace_pattern_flags.local ||
(! erts_default_trace_pattern_flags.breakpoint)) {
@@ -1363,6 +1282,8 @@ trace_info_on_load(Process* p, Eterm key)
MatchSetGetSource(erts_default_meta_match_spec);
meta_match_spec = copy_object(meta_match_spec, p);
}
+ m = (erts_default_trace_pattern_flags.meta
+ ? erts_tracer_to_term(p, erts_default_meta_tracer) : am_false);
hp = HAlloc(p, (3+2)*5 + 3);
t = TUPLE2(hp, am_call_count,
(erts_default_trace_pattern_flags.call_count
@@ -1370,9 +1291,7 @@ trace_info_on_load(Process* p, Eterm key)
r = CONS(hp, t, r); hp += 2;
t = TUPLE2(hp, am_meta_match_spec, meta_match_spec); hp += 3;
r = CONS(hp, t, r); hp += 2;
- t = TUPLE2(hp, am_meta,
- (erts_default_trace_pattern_flags.meta
- ? erts_default_meta_tracer_pid : am_false)); hp += 3;
+ t = TUPLE2(hp, am_meta, m); hp += 3;
r = CONS(hp, t, r); hp += 2;
t = TUPLE2(hp, am_match_spec, match_spec); hp += 3;
r = CONS(hp, t, r); hp += 2;
@@ -1388,6 +1307,42 @@ trace_info_on_load(Process* p, Eterm key)
}
}
+static Eterm
+trace_info_event(Process* p, Eterm event, Eterm key)
+{
+ ErtsTracingEvent* te;
+ Eterm retval;
+ Eterm* hp;
+
+ switch (event) {
+ case am_send: te = erts_send_tracing; break;
+ case am_receive: te = erts_receive_tracing; break;
+ default:
+ goto error;
+ }
+
+ if (key != am_match_spec)
+ goto error;
+
+ te = &te[erts_active_bp_ix()];
+
+ if (te->on) {
+ if (!te->match_spec)
+ retval = am_true;
+ else
+ retval = copy_object(MatchSetGetSource(te->match_spec), p);
+ }
+ else
+ retval = am_false;
+
+ hp = HAlloc(p, 3);
+ return TUPLE2(hp, key, retval);
+
+ error:
+ BIF_ERROR(p, BADARG);
+}
+
+
#undef FUNC_TRACE_NOEXIST
#undef FUNC_TRACE_UNTRACED
#undef FUNC_TRACE_GLOBAL_TRACE
@@ -1397,7 +1352,7 @@ int
erts_set_trace_pattern(Process*p, Eterm* mfa, int specified,
Binary* match_prog_set, Binary *meta_match_prog_set,
int on, struct trace_pattern_flags flags,
- Eterm meta_tracer_pid, int is_blocking)
+ ErtsTracer meta_tracer, int is_blocking)
{
const ErtsCodeIndex code_ix = erts_active_code_ix();
int matches = 0;
@@ -1415,7 +1370,7 @@ erts_set_trace_pattern(Process*p, Eterm* mfa, int specified,
for (i = 0; i < n; i++) {
BeamInstr* pc = fp[i].pc;
- Export* ep = (Export *)(((char *)(pc-3)) - offsetof(Export, code));
+ Export* ep = ErtsContainerStruct(pc, Export, code[3]);
if (on && !flags.breakpoint) {
/* Turn on global call tracing */
@@ -1487,7 +1442,7 @@ erts_set_trace_pattern(Process*p, Eterm* mfa, int specified,
}
if (flags.meta) {
erts_set_mtrace_bif(pc, meta_match_prog_set,
- meta_tracer_pid);
+ meta_tracer);
m = 1;
}
if (flags.call_time) {
@@ -1527,7 +1482,7 @@ erts_set_trace_pattern(Process*p, Eterm* mfa, int specified,
}
if (flags.meta) {
erts_set_mtrace_break(&finish_bp.f, meta_match_prog_set,
- meta_tracer_pid);
+ meta_tracer);
}
if (flags.call_count) {
erts_set_count_break(&finish_bp.f, on);
@@ -1576,12 +1531,57 @@ erts_set_trace_pattern(Process*p, Eterm* mfa, int specified,
}
int
+erts_set_tracing_event_pattern(Eterm event, Binary* match_spec, int on)
+{
+ ErtsBpIndex ix = erts_staging_bp_ix();
+ ErtsTracingEvent* st;
+
+ switch (event) {
+ case am_send: st = &erts_send_tracing[ix]; break;
+ case am_receive: st = &erts_receive_tracing[ix]; break;
+ default: return -1;
+ }
+
+ MatchSetUnref(st->match_spec);
+
+ st->on = on;
+ st->match_spec = match_spec;
+ MatchSetRef(match_spec);
+
+ finish_bp.current = 1; /* prepare phase not needed for event trace */
+ finish_bp.install = on;
+ finish_bp.e.matched = 0;
+ finish_bp.e.matching = NULL;
+ finish_bp.f.matched = 0;
+ finish_bp.f.matching = NULL;
+
+#ifndef ERTS_SMP
+ while (erts_finish_breakpointing()) {
+ /* Empty loop body */
+ }
+#endif
+ return 1;
+}
+
+static void
+consolidate_event_tracing(ErtsTracingEvent te[])
+{
+ ErtsTracingEvent* src = &te[erts_active_bp_ix()];
+ ErtsTracingEvent* dst = &te[erts_staging_bp_ix()];
+
+ MatchSetUnref(dst->match_spec);
+ dst->on = src->on;
+ dst->match_spec = src->match_spec;
+ MatchSetRef(dst->match_spec);
+}
+
+int
erts_finish_breakpointing(void)
{
ERTS_SMP_LC_ASSERT(erts_has_code_write_permission());
/*
- * Memory barriers will be issued for all processes *before*
+ * Memory barriers will be issued for all schedulers *before*
* each of the stages below. (Unless the other schedulers
* are blocked, in which case memory barriers will be issued
* when they are awaken.)
@@ -1650,6 +1650,8 @@ erts_finish_breakpointing(void)
erts_consolidate_bp_data(&finish_bp.f, 1);
erts_bp_free_matched_functions(&finish_bp.e);
erts_bp_free_matched_functions(&finish_bp.f);
+ consolidate_event_tracing(erts_send_tracing);
+ consolidate_event_tracing(erts_receive_tracing);
return 0;
default:
ASSERT(0);
@@ -1664,11 +1666,10 @@ install_exp_breakpoints(BpFunctions* f)
BpFunction* fp = f->matching;
Uint ne = f->matched;
Uint i;
- Uint offset = offsetof(Export, code) + 3*sizeof(BeamInstr);
for (i = 0; i < ne; i++) {
BeamInstr* pc = fp[i].pc;
- Export* ep = (Export *) (((char *)pc)-offset);
+ Export* ep = ErtsContainerStruct(pc, Export, code[3]);
ep->addressv[code_ix] = pc;
}
@@ -1681,11 +1682,10 @@ uninstall_exp_breakpoints(BpFunctions* f)
BpFunction* fp = f->matching;
Uint ne = f->matched;
Uint i;
- Uint offset = offsetof(Export, code) + 3*sizeof(BeamInstr);
for (i = 0; i < ne; i++) {
BeamInstr* pc = fp[i].pc;
- Export* ep = (Export *) (((char *)pc)-offset);
+ Export* ep = ErtsContainerStruct(pc, Export, code[3]);
if (ep->addressv[code_ix] != pc) {
continue;
@@ -1702,11 +1702,10 @@ clean_export_entries(BpFunctions* f)
BpFunction* fp = f->matching;
Uint ne = f->matched;
Uint i;
- Uint offset = offsetof(Export, code) + 3*sizeof(BeamInstr);
for (i = 0; i < ne; i++) {
BeamInstr* pc = fp[i].pc;
- Export* ep = (Export *) (((char *)pc)-offset);
+ Export* ep = ErtsContainerStruct(pc, Export, code[3]);
if (ep->addressv[code_ix] == pc) {
continue;
@@ -2336,50 +2335,86 @@ BIF_RETTYPE system_profile_2(BIF_ALIST_2)
}
/* End: Trace for System Profiling */
-BIF_RETTYPE
-trace_delivered_1(BIF_ALIST_1)
+/* Trace delivered send an aux work message to all schedulers
+ and when all schedulers have acknowledged that they have seen
+ the message the message is sent to the requesting process.
+
+ IMPORTANT: We have to make sure that the all messages sent
+ using enif_send have been delivered before we send the message
+ to the caller.
+
+ There used to be a separate implementation for when only a pid
+ is passed in, but since this is not performance critical code
+ we now use the same approach for both.
+*/
+
+typedef struct {
+ Process *proc;
+ Eterm ref;
+ Eterm ref_heap[REF_THING_SIZE];
+ Eterm target;
+ erts_smp_atomic32_t refc;
+} ErtsTraceDeliveredAll;
+
+static void
+reply_trace_delivered_all(void *vtdarp)
{
- DECL_AM(trace_delivered);
-#ifdef ERTS_SMP
- ErlHeapFragment *bp;
-#else
- ErtsProcLocks locks = 0;
-#endif
- Eterm *hp;
- Eterm msg, ref, msg_ref;
- Process *p;
- if (BIF_ARG_1 == am_all) {
- p = NULL;
- } else if (! (p = erts_pid2proc(BIF_P, ERTS_PROC_LOCK_MAIN,
- BIF_ARG_1, ERTS_PROC_LOCKS_ALL))) {
- if (is_not_internal_pid(BIF_ARG_1)) {
- BIF_ERROR(BIF_P, BADARG);
- }
- }
-
- ref = erts_make_ref(BIF_P);
+ ErtsTraceDeliveredAll *tdarp = (ErtsTraceDeliveredAll *) vtdarp;
+ if (erts_smp_atomic32_dec_read_nob(&tdarp->refc) == 0) {
+ Eterm ref_copy, msg;
+ Process *rp = tdarp->proc;
+ Eterm *hp = NULL;
+ ErlOffHeap *ohp;
#ifdef ERTS_SMP
- bp = new_message_buffer(REF_THING_SIZE + 4);
- hp = &bp->mem[0];
- msg_ref = STORE_NC(&hp, &bp->off_heap, ref);
+ ErlHeapFragment *bp;
+ bp = new_message_buffer(4 + NC_HEAP_SIZE(tdarp->ref));
+ hp = &bp->mem[0];
+ ohp = &bp->off_heap;
#else
- hp = HAlloc(BIF_P, 4);
- msg_ref = ref;
+ ErtsProcLocks rp_locks = 0;
+ ErtsMessage *mp;
+ mp = erts_alloc_message_heap(
+ rp, &rp_locks, 4 + NC_HEAP_SIZE(tdarp->ref), &hp, &ohp);
#endif
- msg = TUPLE3(hp, AM_trace_delivered, BIF_ARG_1, msg_ref);
+ ref_copy = STORE_NC(&hp, ohp, tdarp->ref);
+ msg = TUPLE3(hp, am_trace_delivered, tdarp->target, ref_copy);
#ifdef ERTS_SMP
- erts_send_sys_msg_proc(BIF_P->common.id, BIF_P->common.id, msg, bp);
- if (p)
- erts_smp_proc_unlock(p,
- (BIF_P == p
- ? ERTS_PROC_LOCKS_ALL_MINOR
- : ERTS_PROC_LOCKS_ALL));
+ erts_send_sys_msg_proc(rp->common.id, rp->common.id, msg, bp);
#else
- erts_send_message(BIF_P, BIF_P, &locks, msg, ERTS_SND_FLG_NO_SEQ_TRACE);
+ erts_queue_message(rp, rp_locks, mp, msg, am_system);
#endif
- BIF_RET(ref);
+ erts_free(ERTS_ALC_T_MISC_AUX_WORK, vtdarp);
+ erts_proc_dec_refc(rp);
+ }
+}
+
+BIF_RETTYPE
+trace_delivered_1(BIF_ALIST_1)
+{
+
+ if (BIF_ARG_1 == am_all || is_internal_pid(BIF_ARG_1)) {
+ Eterm *hp, ref;
+ ErtsTraceDeliveredAll *tdarp =
+ erts_alloc(ERTS_ALC_T_MISC_AUX_WORK, sizeof(ErtsTraceDeliveredAll));
+
+ tdarp->proc = BIF_P;
+ ref = erts_make_ref(BIF_P);
+ hp = &tdarp->ref_heap[0];
+ tdarp->ref = STORE_NC(&hp, NULL, ref);
+ tdarp->target = BIF_ARG_1;
+ erts_smp_atomic32_init_nob(&tdarp->refc,
+ (erts_aint32_t) erts_no_schedulers);
+ erts_proc_add_refc(BIF_P, 1);
+ erts_schedule_multi_misc_aux_work(0,
+ erts_no_schedulers,
+ reply_trace_delivered_all,
+ (void *) tdarp);
+ BIF_RET(ref);
+ } else {
+ BIF_ERROR(BIF_P, BADARG);
+ }
}
diff --git a/erts/emulator/beam/erl_bif_unique.c b/erts/emulator/beam/erl_bif_unique.c
index c4a39b8897..1e57e9fa53 100644
--- a/erts/emulator/beam/erl_bif_unique.c
+++ b/erts/emulator/beam/erl_bif_unique.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2014. All Rights Reserved.
+ * Copyright Ericsson AB 2014-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.
@@ -266,17 +266,19 @@ static ERTS_INLINE Eterm unique_integer_bif(Process *c_p, int positive)
}
Uint
-erts_raw_unique_integer_heap_size(Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES])
+erts_raw_unique_integer_heap_size(Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES],
+ int positive)
{
Uint sz;
- bld_unique_integer_term(NULL, &sz, val[0], val[1], 0);
+ bld_unique_integer_term(NULL, &sz, val[0], val[1], positive);
return sz;
}
Eterm
-erts_raw_make_unique_integer(Eterm **hpp, Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES])
+erts_raw_make_unique_integer(Eterm **hpp, Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES],
+ int positive)
{
- return bld_unique_integer_term(hpp, NULL, val[0], val[1], 0);
+ return bld_unique_integer_term(hpp, NULL, val[0], val[1], positive);
}
void
@@ -426,16 +428,16 @@ erts_raw_get_unique_monotonic_integer(void)
}
Uint
-erts_raw_unique_monotonic_integer_heap_size(Sint64 raw)
+erts_raw_unique_monotonic_integer_heap_size(Sint64 raw, int positive)
{
- return get_unique_monotonic_integer_heap_size(raw, 0);
+ return get_unique_monotonic_integer_heap_size(raw, positive);
}
Eterm
-erts_raw_make_unique_monotonic_integer_value(Eterm **hpp, Sint64 raw)
+erts_raw_make_unique_monotonic_integer_value(Eterm **hpp, Sint64 raw, int positive)
{
- Uint hsz = get_unique_monotonic_integer_heap_size(raw, 0);
- Eterm res = make_unique_monotonic_integer_value(*hpp, hsz, raw, 0);
+ Uint hsz = get_unique_monotonic_integer_heap_size(raw, positive);
+ Eterm res = make_unique_monotonic_integer_value(*hpp, hsz, raw, positive);
*hpp += hsz;
return res;
}
diff --git a/erts/emulator/beam/erl_bif_unique.h b/erts/emulator/beam/erl_bif_unique.h
index 37d5d91c39..c6481864d0 100644
--- a/erts/emulator/beam/erl_bif_unique.h
+++ b/erts/emulator/beam/erl_bif_unique.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2014. All Rights Reserved.
+ * Copyright Ericsson AB 2014-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.
@@ -41,8 +41,9 @@ void erts_make_ref_in_array(Uint32 ref[ERTS_MAX_REF_NUMBERS]);
* not necessarily correspond to the end result.
*/
Sint64 erts_raw_get_unique_monotonic_integer(void);
-Uint erts_raw_unique_monotonic_integer_heap_size(Sint64 raw);
-Eterm erts_raw_make_unique_monotonic_integer_value(Eterm **hpp, Sint64 raw);
+Uint erts_raw_unique_monotonic_integer_heap_size(Sint64 raw, int positive);
+Eterm erts_raw_make_unique_monotonic_integer_value(Eterm **hpp, Sint64 raw,
+ int positive);
Sint64 erts_get_min_unique_monotonic_integer(void);
@@ -53,8 +54,11 @@ Eterm erts_debug_get_unique_monotonic_integer_state(Process *c_p);
#define ERTS_UNIQUE_INT_RAW_VALUES 2
#define ERTS_MAX_UNIQUE_INT_HEAP_SIZE ERTS_UINT64_ARRAY_TO_BIG_MAX_HEAP_SZ(2)
-Uint erts_raw_unique_integer_heap_size(Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES]);
-Eterm erts_raw_make_unique_integer(Eterm **hpp, Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES]);
+Uint erts_raw_unique_integer_heap_size(Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES],
+ int positive);
+Eterm erts_raw_make_unique_integer(Eterm **hpp,
+ Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES],
+ int postive);
void erts_raw_get_unique_integer(Uint64 val[ERTS_UNIQUE_INT_RAW_VALUES]);
Sint64 erts_get_min_unique_integer(void);
diff --git a/erts/emulator/beam/erl_binary.h b/erts/emulator/beam/erl_binary.h
index e181b5555d..fdc5efea98 100644
--- a/erts/emulator/beam/erl_binary.h
+++ b/erts/emulator/beam/erl_binary.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2000-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2000-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.
diff --git a/erts/emulator/beam/erl_bits.c b/erts/emulator/beam/erl_bits.c
index 11d83686a3..6bf52fb303 100644
--- a/erts/emulator/beam/erl_bits.c
+++ b/erts/emulator/beam/erl_bits.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/beam/erl_bits.h b/erts/emulator/beam/erl_bits.h
index 8b7807fbd9..1c2a090f07 100644
--- a/erts/emulator/beam/erl_bits.h
+++ b/erts/emulator/beam/erl_bits.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2011. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/beam/erl_cpu_topology.c b/erts/emulator/beam/erl_cpu_topology.c
index c263eebfcc..28aaeeb479 100644
--- a/erts/emulator/beam/erl_cpu_topology.c
+++ b/erts/emulator/beam/erl_cpu_topology.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2013. All Rights Reserved.
+ * 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.
diff --git a/erts/emulator/beam/erl_cpu_topology.h b/erts/emulator/beam/erl_cpu_topology.h
index f3fbfc6da0..45324ac4a0 100644
--- a/erts/emulator/beam/erl_cpu_topology.h
+++ b/erts/emulator/beam/erl_cpu_topology.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2013. All Rights Reserved.
+ * 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.
diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c
index 441dbdde4f..acaca54e9a 100644
--- a/erts/emulator/beam/erl_db.c
+++ b/erts/emulator/beam/erl_db.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -2833,7 +2833,8 @@ BIF_RETTYPE ets_match_spec_run_r_3(BIF_ALIST_3)
BIF_TRAP3(bif_export[BIF_ets_match_spec_run_r_3],
BIF_P,lst,BIF_ARG_2,ret);
}
- res = db_prog_match(BIF_P, mp, CAR(list_val(lst)), NULL, 0,
+ res = db_prog_match(BIF_P, BIF_P,
+ mp, CAR(list_val(lst)), NULL, 0,
ERTS_PAM_COPY_RESULT, &dummy);
if (is_value(res)) {
hp = HAlloc(BIF_P, 2);
diff --git a/erts/emulator/beam/erl_db.h b/erts/emulator/beam/erl_db.h
index a589af784c..1d26c49652 100644
--- a/erts/emulator/beam/erl_db.h
+++ b/erts/emulator/beam/erl_db.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c
index 240b79fc60..74979f984a 100644
--- a/erts/emulator/beam/erl_db_hash.c
+++ b/erts/emulator/beam/erl_db_hash.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2012. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/emulator/beam/erl_db_hash.h b/erts/emulator/beam/erl_db_hash.h
index 66d8ec71d9..e654363cd5 100644
--- a/erts/emulator/beam/erl_db_hash.h
+++ b/erts/emulator/beam/erl_db_hash.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c
index 0f642f0867..02d211a4bb 100644
--- a/erts/emulator/beam/erl_db_tree.c
+++ b/erts/emulator/beam/erl_db_tree.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/emulator/beam/erl_db_tree.h b/erts/emulator/beam/erl_db_tree.h
index 6098387f5d..72749ead1e 100644
--- a/erts/emulator/beam/erl_db_tree.h
+++ b/erts/emulator/beam/erl_db_tree.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c
index 973be58420..95b1cd0148 100644
--- a/erts/emulator/beam/erl_db_util.c
+++ b/erts/emulator/beam/erl_db_util.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
@@ -123,6 +123,9 @@ do { \
#define TermWords(t) (((t) / (sizeof(UWord)/sizeof(Eterm))) + !!((t) % (sizeof(UWord)/sizeof(Eterm))))
+#define add_dmc_err(EINFO, STR, VAR, TERM, SEV) \
+ vadd_dmc_err(EINFO, SEV, VAR, STR, TERM)
+
static ERTS_INLINE Process *
get_proc(Process *cp, Uint32 cp_locks, Eterm id, Uint32 id_locks)
@@ -135,21 +138,22 @@ get_proc(Process *cp, Uint32 cp_locks, Eterm id, Uint32 id_locks)
static Eterm
-set_tracee_flags(Process *tracee_p, Eterm tracer, Uint d_flags, Uint e_flags) {
+set_tracee_flags(Process *tracee_p, ErtsTracer tracer,
+ Uint d_flags, Uint e_flags) {
Eterm ret;
Uint flags;
- if (tracer == NIL) {
+ if (ERTS_TRACER_IS_NIL(tracer)) {
flags = ERTS_TRACE_FLAGS(tracee_p) & ~TRACEE_FLAGS;
} else {
flags = ((ERTS_TRACE_FLAGS(tracee_p) & ~d_flags) | e_flags);
- if (! flags) tracer = NIL;
+ if (! flags) tracer = erts_tracer_nil;
}
- ret = ((ERTS_TRACER_PROC(tracee_p) != tracer
+ ret = ((!ERTS_TRACER_COMPARE(ERTS_TRACER(tracee_p),tracer)
|| ERTS_TRACE_FLAGS(tracee_p) != flags)
? am_true
: am_false);
- ERTS_TRACER_PROC(tracee_p) = tracer;
+ erts_tracer_replace(&tracee_p->common, tracer);
ERTS_TRACE_FLAGS(tracee_p) = flags;
return ret;
}
@@ -163,40 +167,16 @@ set_tracee_flags(Process *tracee_p, Eterm tracer, Uint d_flags, Uint e_flags) {
** returns fail_term on failure. Fails if tracer pid or port is invalid.
*/
static Eterm
-set_match_trace(Process *tracee_p, Eterm fail_term, Eterm tracer,
+set_match_trace(Process *tracee_p, Eterm fail_term, ErtsTracer tracer,
Uint d_flags, Uint e_flags) {
- Eterm ret = fail_term;
- Process *tracer_p;
-
- ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCKS_ALL ==
- erts_proc_lc_my_proc_locks(tracee_p));
-
- if (is_internal_pid(tracer)
- && (tracer_p =
- erts_pid2proc(tracee_p, ERTS_PROC_LOCKS_ALL,
- tracer, ERTS_PROC_LOCKS_ALL))) {
- if (tracee_p != tracer_p) {
- ret = set_tracee_flags(tracee_p, tracer, d_flags, e_flags);
- ERTS_TRACE_FLAGS(tracer_p) |= (ERTS_TRACE_FLAGS(tracee_p)
- ? F_TRACER
- : 0);
- erts_smp_proc_unlock(tracer_p, ERTS_PROC_LOCKS_ALL);
- }
- } else if (is_internal_port(tracer)) {
- Port *tracer_port =
- erts_id2port_sflgs(tracer,
- tracee_p,
- ERTS_PROC_LOCKS_ALL,
- ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP);
- if (tracer_port) {
- ret = set_tracee_flags(tracee_p, tracer, d_flags, e_flags);
- erts_port_release(tracer_port);
- }
- } else {
- ASSERT(is_nil(tracer));
- ret = set_tracee_flags(tracee_p, tracer, d_flags, e_flags);
- }
- return ret;
+
+ ERTS_SMP_LC_ASSERT(
+ ERTS_PROC_LOCKS_ALL == erts_proc_lc_my_proc_locks(tracee_p)
+ || erts_thr_progress_is_blocking());
+
+ if (ERTS_TRACER_IS_NIL(tracer) || erts_is_tracer_enabled(tracee_p, tracer))
+ return set_tracee_flags(tracee_p, tracer, d_flags, e_flags);
+ return fail_term;
}
/*
@@ -434,17 +414,27 @@ get_match_pseudo_process(Process *c_p, Uint heap_size)
{
ErtsMatchPseudoProcess *mpsp;
#ifdef ERTS_SMP
- mpsp = (ErtsMatchPseudoProcess *) c_p->scheduler_data->match_pseudo_process;
- if (mpsp)
+ ErtsSchedulerData *esdp;
+
+ esdp = c_p ? c_p->scheduler_data : erts_get_scheduler_data();
+
+ mpsp = esdp ? esdp->match_pseudo_process :
+ (ErtsMatchPseudoProcess*) erts_smp_tsd_get(match_pseudo_process_key);
+
+ if (mpsp) {
+ ASSERT(mpsp == erts_smp_tsd_get(match_pseudo_process_key));
+ ASSERT(mpsp->process.scheduler_data == esdp);
cleanup_match_pseudo_process(mpsp, 0);
+ }
else {
ASSERT(erts_smp_tsd_get(match_pseudo_process_key) == NULL);
mpsp = create_match_pseudo_process();
- c_p->scheduler_data->match_pseudo_process = (void *) mpsp;
+ if (esdp) {
+ esdp->match_pseudo_process = (void *) mpsp;
+ }
+ mpsp->process.scheduler_data = esdp;
erts_smp_tsd_set(match_pseudo_process_key, (void *) mpsp);
}
- ASSERT(mpsp == erts_smp_tsd_get(match_pseudo_process_key));
- mpsp->process.scheduler_data = c_p->scheduler_data;
#else
mpsp = match_pseudo_process;
cleanup_match_pseudo_process(mpsp, 0);
@@ -912,11 +902,7 @@ void db_match_dis(Binary *prog);
#define TRACE /* Nothing */
#define FENCE_PATTERN_SIZE 0
#endif
-static void add_dmc_err(DMCErrInfo *err_info,
- char *str,
- int variable,
- Eterm term,
- DMCErrorSeverity severity);
+static void vadd_dmc_err(DMCErrInfo*, DMCErrorSeverity, int var, const char *str, ...);
static Eterm dpm_array_to_list(Process *psp, Eterm *arr, int arity);
@@ -1012,12 +998,20 @@ Eterm erts_match_set_get_source(Binary *mpsp)
}
/* This one is for the tracing */
-Binary *erts_match_set_compile(Process *p, Eterm matchexpr) {
+Binary *erts_match_set_compile(Process *p, Eterm matchexpr, Eterm MFA) {
Binary *bin;
Uint sz;
Eterm *hp;
+ Uint flags;
+
+ switch (MFA) {
+ case am_receive: flags = DCOMP_TRACE; break;
+ case am_send: flags = DCOMP_TRACE | DCOMP_ALLOW_TRACE_OPS; break;
+ default:
+ flags = DCOMP_TRACE | DCOMP_CALL_TRACE | DCOMP_ALLOW_TRACE_OPS;
+ }
- bin = db_match_set_compile(p, matchexpr, DCOMP_TRACE);
+ bin = db_match_set_compile(p, matchexpr, flags);
if (bin != NULL) {
MatchProg *prog = Binary2MatchProg(bin);
sz = size_object(matchexpr);
@@ -1147,8 +1141,8 @@ Eterm db_match_set_lint(Process *p, Eterm matchexpr, Uint flags)
int i;
if (!is_list(matchexpr)) {
- add_dmc_err(err_info, "Match programs are not in a list.",
- -1, 0UL, dmcError);
+ add_dmc_err(err_info, "Match programs are not in a list.",
+ -1, 0UL, dmcError);
goto done;
}
num_heads = 0;
@@ -1156,9 +1150,8 @@ Eterm db_match_set_lint(Process *p, Eterm matchexpr, Uint flags)
++num_heads;
if (l != NIL) { /* proper list... */
- add_dmc_err(err_info, "Match programs are not in a proper "
- "list.",
- -1, 0UL, dmcError);
+ add_dmc_err(err_info, "Match programs are not in a proper list.",
+ -1, 0UL, dmcError);
goto done;
}
@@ -1225,30 +1218,37 @@ done:
return ret;
}
-Eterm erts_match_set_run(Process *p, Binary *mpsp,
- Eterm *args, int num_args,
- enum erts_pam_run_flags in_flags,
- Uint32 *return_flags)
+/* Returns
+ * am_false if no match or
+ * if {message,false} has been called,
+ * am_true if {message,_} has NOT been called or
+ * if {message,true} has been called,
+ * Msg if {message,Msg} has been called.
+ *
+ * If return value is_not_immed
+ * then erts_match_set_release_result_trace() must be called to release it.
+ */
+Eterm erts_match_set_run_trace(Process *c_p,
+ Process *self,
+ Binary *mpsp,
+ Eterm *args, int num_args,
+ enum erts_pam_run_flags in_flags,
+ Uint32 *return_flags)
{
Eterm ret;
- ret = db_prog_match(p, mpsp, NIL, args, num_args,
+ ret = db_prog_match(c_p, self, mpsp, NIL, args, num_args,
in_flags, return_flags);
-#if defined(HARDDEBUG)
- if (is_non_value(ret)) {
- erts_fprintf(stderr, "Failed\n");
- } else {
- erts_fprintf(stderr, "Returning : %T\n", ret);
+
+ ASSERT(!(is_non_value(ret) && *return_flags));
+
+ if (is_non_value(ret) || ret == am_false) {
+ erts_match_set_release_result(c_p);
+ return am_false;
}
-#endif
+ if (is_immed(ret))
+ erts_match_set_release_result(c_p);
return ret;
- /* Returns
- * THE_NON_VALUE if no match
- * am_false if {message,false} has been called,
- * am_true if {message,_} has not been called or
- * if {message,true} has been called,
- * Msg if {message,Msg} has been called.
- */
}
static Eterm erts_match_set_run_ets(Process *p, Binary *mpsp,
@@ -1257,7 +1257,8 @@ static Eterm erts_match_set_run_ets(Process *p, Binary *mpsp,
{
Eterm ret;
- ret = db_prog_match(p, mpsp, args, NULL, num_args,
+ ret = db_prog_match(p, p,
+ mpsp, args, NULL, num_args,
ERTS_PAM_COPY_RESULT,
return_flags);
#if defined(HARDDEBUG)
@@ -1753,7 +1754,9 @@ static Eterm dpm_array_to_list(Process *psp, Eterm *arr, int arity)
** the parameter 'arity' is only used if 'term' is actually an array,
** i.e. 'DCOMP_TRACE' was specified
*/
-Eterm db_prog_match(Process *c_p, Binary *bprog,
+Eterm db_prog_match(Process *c_p,
+ Process *self,
+ Binary *bprog,
Eterm term,
Eterm *termp,
int arity,
@@ -1766,10 +1769,10 @@ Eterm db_prog_match(Process *c_p, Binary *bprog,
Eterm *esp;
MatchVariable* variables;
BeamInstr *cp;
- UWord *pc = prog->text;
+ const UWord *pc = prog->text;
Eterm *ehp;
Eterm ret;
- Uint n = 0; /* To avoid warning. */
+ Uint n;
int i;
unsigned do_catch;
ErtsMatchPseudoProcess *mpsp;
@@ -1781,46 +1784,28 @@ Eterm db_prog_match(Process *c_p, Binary *bprog,
Eterm (*bif)(Process*, ...);
Eterm bif_args[3];
int fail_label;
- int atomic_trace;
#ifdef DMC_DEBUG
Uint *heap_fence;
Uint *stack_fence;
Uint save_op;
#endif /* DMC_DEBUG */
+ ERTS_UNDEF(n,0);
+ ERTS_UNDEF(current_scheduled,NULL);
+
+ ASSERT(c_p || !(in_flags & ERTS_PAM_COPY_RESULT));
+
mpsp = get_match_pseudo_process(c_p, prog->heap_size);
psp = &mpsp->process;
/* We need to lure the scheduler into believing in the pseudo process,
because of floating point exceptions. Do *after* mpsp is set!!! */
- esdp = ERTS_GET_SCHEDULER_DATA_FROM_PROC(c_p);
- ASSERT(esdp != NULL);
- current_scheduled = esdp->current_process;
+ esdp = ERTS_GET_SCHEDULER_DATA_FROM_PROC(psp);
+ if (esdp)
+ current_scheduled = esdp->current_process;
/* SMP: psp->scheduler_data is set by get_match_pseudo_process */
- atomic_trace = 0;
-#define BEGIN_ATOMIC_TRACE(p) \
- do { \
- if (! atomic_trace) { \
- erts_refc_inc(&bprog->refc, 2); \
- erts_smp_proc_unlock((p), ERTS_PROC_LOCK_MAIN); \
- erts_smp_thr_progress_block(); \
- atomic_trace = !0; \
- } \
- } while (0)
-#define END_ATOMIC_TRACE(p) \
- do { \
- if (atomic_trace) { \
- erts_smp_thr_progress_unblock(); \
- erts_smp_proc_lock((p), ERTS_PROC_LOCK_MAIN); \
- if (erts_refc_dectest(&bprog->refc, 0) == 0) {\
- erts_bin_free(bprog); \
- } \
- atomic_trace = 0; \
- } \
- } while (0)
-
#ifdef DMC_DEBUG
save_op = 0;
heap_fence = (Eterm*)((char*) mpsp->u.heap + prog->stack_offset) - 1;
@@ -2279,7 +2264,7 @@ restart:
pc += n;
break;
case matchSelf:
- *esp++ = c_p->common.id;
+ *esp++ = self->common.id;
break;
case matchWaste:
--esp;
@@ -2289,6 +2274,7 @@ restart:
break;
case matchProcessDump: {
erts_dsprintf_buf_t *dsbufp = erts_create_tmp_dsbuf(0);
+ ASSERT(c_p == self);
print_process_info(ERTS_PRINT_DSBUF, (void *) dsbufp, c_p);
*esp++ = new_binary(build_proc, (byte *)dsbufp->str,
dsbufp->str_len);
@@ -2307,14 +2293,16 @@ restart:
*return_flags |= MATCH_SET_EXCEPTION_TRACE;
*esp++ = am_true;
break;
- case matchIsSeqTrace:
+ case matchIsSeqTrace:
+ ASSERT(c_p == self);
if (have_seqtrace(SEQ_TRACE_TOKEN(c_p)))
*esp++ = am_true;
else
*esp++ = am_false;
break;
case matchSetSeqToken:
- t = erts_seq_trace(c_p, esp[-1], esp[-2], 0);
+ ASSERT(c_p == self);
+ t = erts_seq_trace(c_p, esp[-1], esp[-2], 0);
if (is_non_value(t)) {
esp[-2] = FAIL_TERM;
} else {
@@ -2322,7 +2310,8 @@ restart:
}
--esp;
break;
- case matchSetSeqTokenFake:
+ case matchSetSeqTokenFake:
+ ASSERT(c_p == self);
t = seq_trace_fake(c_p, esp[-1]);
if (is_non_value(t)) {
esp[-2] = FAIL_TERM;
@@ -2331,7 +2320,8 @@ restart:
}
--esp;
break;
- case matchGetSeqToken:
+ case matchGetSeqToken:
+ ASSERT(c_p == self);
if (have_no_seqtrace(SEQ_TRACE_TOKEN(c_p)))
*esp++ = NIL;
else {
@@ -2355,49 +2345,62 @@ restart:
ASSERT(is_immed(ehp[5]));
}
break;
- case matchEnableTrace:
+ case matchEnableTrace:
+ ASSERT(c_p == self);
if ( (n = erts_trace_flag2bit(esp[-1]))) {
- BEGIN_ATOMIC_TRACE(c_p);
- set_tracee_flags(c_p, ERTS_TRACER_PROC(c_p), 0, n);
+ erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
+ set_tracee_flags(c_p, ERTS_TRACER(c_p), 0, n);
+ erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
esp[-1] = am_true;
} else {
esp[-1] = FAIL_TERM;
}
break;
- case matchEnableTrace2:
+ case matchEnableTrace2:
+ ASSERT(c_p == self);
n = erts_trace_flag2bit((--esp)[-1]);
esp[-1] = FAIL_TERM;
if (n) {
- BEGIN_ATOMIC_TRACE(c_p);
- if ( (tmpp = get_proc(c_p, 0, esp[0], 0))) {
+ if ( (tmpp = get_proc(c_p, ERTS_PROC_LOCK_MAIN, esp[0], ERTS_PROC_LOCKS_ALL))) {
/* Always take over the tracer of the current process */
- set_tracee_flags(tmpp, ERTS_TRACER_PROC(c_p), 0, n);
- esp[-1] = am_true;
+ set_tracee_flags(tmpp, ERTS_TRACER(c_p), 0, n);
+ if (tmpp == c_p)
+ erts_smp_proc_unlock(tmpp, ERTS_PROC_LOCKS_ALL_MINOR);
+ else
+ erts_smp_proc_unlock(tmpp, ERTS_PROC_LOCKS_ALL);
+ esp[-1] = am_true;
}
}
break;
- case matchDisableTrace:
+ case matchDisableTrace:
+ ASSERT(c_p == self);
if ( (n = erts_trace_flag2bit(esp[-1]))) {
- BEGIN_ATOMIC_TRACE(c_p);
- set_tracee_flags(c_p, ERTS_TRACER_PROC(c_p), n, 0);
+ erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
+ set_tracee_flags(c_p, ERTS_TRACER(c_p), n, 0);
+ erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
esp[-1] = am_true;
} else {
esp[-1] = FAIL_TERM;
}
break;
- case matchDisableTrace2:
+ case matchDisableTrace2:
+ ASSERT(c_p == self);
n = erts_trace_flag2bit((--esp)[-1]);
esp[-1] = FAIL_TERM;
if (n) {
- BEGIN_ATOMIC_TRACE(c_p);
- if ( (tmpp = get_proc(c_p, 0, esp[0], 0))) {
+ if ( (tmpp = get_proc(c_p, ERTS_PROC_LOCK_MAIN, esp[0], ERTS_PROC_LOCKS_ALL))) {
/* Always take over the tracer of the current process */
- set_tracee_flags(tmpp, ERTS_TRACER_PROC(c_p), n, 0);
- esp[-1] = am_true;
+ set_tracee_flags(tmpp, ERTS_TRACER(c_p), n, 0);
+ if (tmpp == c_p)
+ erts_smp_proc_unlock(tmpp, ERTS_PROC_LOCKS_ALL_MINOR);
+ else
+ erts_smp_proc_unlock(tmpp, ERTS_PROC_LOCKS_ALL);
+ esp[-1] = am_true;
}
}
break;
- case matchCaller:
+ case matchCaller:
+ ASSERT(c_p == self);
if (!(c_p->cp) || !(cp = find_function_from_pc(c_p->cp))) {
*esp++ = am_undefined;
} else {
@@ -2409,7 +2412,8 @@ restart:
ehp[3] = make_small((Uint) cp[2]);
}
break;
- case matchSilent:
+ case matchSilent:
+ ASSERT(c_p == self);
--esp;
if (in_flags & ERTS_PAM_IGNORE_TRACE_SILENT)
break;
@@ -2424,11 +2428,12 @@ restart:
erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
}
break;
- case matchTrace2:
+ case matchTrace2:
+ ASSERT(c_p == self);
{
/* disable enable */
Uint d_flags = 0, e_flags = 0; /* process trace flags */
- Eterm tracer = ERTS_TRACER_PROC(c_p);
+ ErtsTracer tracer = erts_tracer_nil;
/* XXX Atomicity note: Not fully atomic. Default tracer
* is sampled from current process but applied to
* tracee and tracer later after releasing main
@@ -2440,29 +2445,35 @@ restart:
* {trace,[],[{{tracer,Tracer}}]} is much, much older.
*/
int cputs = 0;
+ erts_tracer_update(&tracer, ERTS_TRACER(c_p));
if (! erts_trace_flags(esp[-1], &d_flags, &tracer, &cputs) ||
! erts_trace_flags(esp[-2], &e_flags, &tracer, &cputs) ||
cputs ) {
(--esp)[-1] = FAIL_TERM;
+ ERTS_TRACER_CLEAR(&tracer);
break;
}
erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
(--esp)[-1] = set_match_trace(c_p, FAIL_TERM, tracer,
d_flags, e_flags);
erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
+ ERTS_TRACER_CLEAR(&tracer);
}
break;
- case matchTrace3:
+ case matchTrace3:
+ ASSERT(c_p == self);
{
/* disable enable */
Uint d_flags = 0, e_flags = 0; /* process trace flags */
- Eterm tracer = ERTS_TRACER_PROC(c_p);
+ ErtsTracer tracer = erts_tracer_nil;
/* XXX Atomicity note. Not fully atomic. See above.
* Above it could possibly be solved, but not here.
*/
int cputs = 0;
Eterm tracee = (--esp)[0];
+
+ erts_tracer_update(&tracer, ERTS_TRACER(c_p));
if (! erts_trace_flags(esp[-1], &d_flags, &tracer, &cputs) ||
! erts_trace_flags(esp[-2], &e_flags, &tracer, &cputs) ||
@@ -2470,6 +2481,7 @@ restart:
! (tmpp = get_proc(c_p, ERTS_PROC_LOCK_MAIN,
tracee, ERTS_PROC_LOCKS_ALL))) {
(--esp)[-1] = FAIL_TERM;
+ ERTS_TRACER_CLEAR(&tracer);
break;
}
if (tmpp == c_p) {
@@ -2483,6 +2495,7 @@ restart:
erts_smp_proc_unlock(tmpp, ERTS_PROC_LOCKS_ALL);
erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN);
}
+ ERTS_TRACER_CLEAR(&tracer);
}
break;
case matchCatch: /* Match success, now build result */
@@ -2522,15 +2535,12 @@ success:
}
#endif
- esdp->current_process = current_scheduled;
-
- END_ATOMIC_TRACE(c_p);
+ if (esdp)
+ esdp->current_process = current_scheduled;
return ret;
#undef FAIL
#undef FAIL_TERM
-#undef BEGIN_ATOMIC_TRACE
-#undef END_ATOMIC_TRACE
}
@@ -3275,20 +3285,20 @@ int erts_db_is_compiled_ms(Eterm term)
** Utility to add an error
*/
-static void add_dmc_err(DMCErrInfo *err_info,
- char *str,
- int variable,
- Eterm term,
- DMCErrorSeverity severity)
+static void vadd_dmc_err(DMCErrInfo *err_info,
+ DMCErrorSeverity severity,
+ int variable,
+ const char *str,
+ ...)
{
+ DMCError *e;
+ va_list args;
+ va_start(args, str);
+
+
/* Linked in in reverse order, to ease the formatting */
- DMCError *e = erts_alloc(ERTS_ALC_T_DB_DMC_ERROR, sizeof(DMCError));
- if (term != 0UL) {
- erts_snprintf(e->error_string, DMC_ERR_STR_LEN, str, term);
- } else {
- strncpy(e->error_string, str, DMC_ERR_STR_LEN);
- e->error_string[DMC_ERR_STR_LEN] ='\0';
- }
+ e = erts_alloc(ERTS_ALC_T_DB_DMC_ERROR, sizeof(DMCError));
+ erts_vsnprintf(e->error_string, DMC_ERR_STR_LEN, str, args);
e->variable = variable;
e->severity = severity;
e->next = err_info->first;
@@ -3298,8 +3308,11 @@ static void add_dmc_err(DMCErrInfo *err_info,
err_info->first = e;
if (severity >= dmcError)
err_info->error_added = 1;
+
+ va_end(args);
}
+
/*
** Handle one term in the match expression (not the guard)
*/
@@ -3498,24 +3511,21 @@ static void do_emit_constant(DMCContext *context, DMC_STACK_TYPE(UWord) *text,
context->stack_need = context->stack_used;
}
-#define RETURN_ERROR_X(String, X, Y, ContextP, ConstantF) \
-do { \
-if ((ContextP)->err_info != NULL) { \
- (ConstantF) = 0; \
- add_dmc_err((ContextP)->err_info, String, X, Y, dmcError); \
- return retOk; \
-} else \
- return retFail; \
-} while(0)
+#define RETURN_ERROR_X(VAR, ContextP, ConstantF, String, ARG) \
+ (((ContextP)->err_info != NULL) \
+ ? ((ConstantF) = 0, \
+ vadd_dmc_err((ContextP)->err_info, dmcError, VAR, String, ARG), \
+ retOk) \
+ : retFail)
#define RETURN_ERROR(String, ContextP, ConstantF) \
- RETURN_ERROR_X(String, -1, 0UL, ContextP, ConstantF)
+ return RETURN_ERROR_X(-1, ContextP, ConstantF, String, 0)
#define RETURN_VAR_ERROR(String, N, ContextP, ConstantF) \
- RETURN_ERROR_X(String, N, 0UL, ContextP, ConstantF)
+ return RETURN_ERROR_X(N, ContextP, ConstantF, String, 0)
#define RETURN_TERM_ERROR(String, T, ContextP, ConstantF) \
- RETURN_ERROR_X(String, -1, T, ContextP, ConstantF)
+ return RETURN_ERROR_X(-1, ContextP, ConstantF, String, T)
#define WARNING(String, ContextP) \
add_dmc_err((ContextP)->err_info, String, -1, 0UL, dmcWarning)
@@ -3781,7 +3791,7 @@ static DMCRet dmc_variable(DMCContext *context,
Uint n = db_is_variable(t);
if (n >= heap->vars_used || !heap->vars[n].is_bound) {
- RETURN_VAR_ERROR("Variable $%d is unbound.", n, context, *constant);
+ RETURN_VAR_ERROR("Variable $%%d is unbound.", n, context, *constant);
}
dmc_add_pushv_variant(context, heap, text, n);
@@ -4113,7 +4123,30 @@ static DMCRet dmc_exception_trace(DMCContext *context,
return retOk;
}
-
+static int check_trace(const char* op,
+ DMCContext *context,
+ int *constant,
+ int need_cflags,
+ int allow_in_guard,
+ DMCRet* retp)
+{
+ if (!(context->cflags & DCOMP_TRACE)) {
+ *retp = RETURN_ERROR_X(-1, context, *constant, "Special form '%s' "
+ "used in wrong dialect.", op);
+ return 0;
+ }
+ if ((context->cflags & need_cflags) != need_cflags) {
+ *retp = RETURN_ERROR_X(-1, context, *constant, "Special form '%s' "
+ "not allow for this trace event.", op);
+ return 0;
+ }
+ if (context->is_guard && !allow_in_guard) {
+ *retp = RETURN_ERROR_X(-1, context, *constant, "Special form '%s' "
+ "called in guard context.", op);
+ return 0;
+ }
+ return 1;
+}
static DMCRet dmc_is_seq_trace(DMCContext *context,
DMCHeap *heap,
@@ -4123,12 +4156,11 @@ static DMCRet dmc_is_seq_trace(DMCContext *context,
{
Eterm *p = tuple_val(t);
Uint a = arityval(*p);
+ DMCRet ret;
- if (!(context->cflags & DCOMP_TRACE)) {
- RETURN_ERROR("Special form 'is_seq_trace' used in wrong dialect.",
- context,
- *constant);
- }
+ if (!check_trace("is_seq_trace", context, constant, DCOMP_ALLOW_TRACE_OPS, 1, &ret))
+ return ret;
+
if (a != 1) {
RETURN_TERM_ERROR("Special form 'is_seq_trace' called with "
"arguments in %T.", t, context, *constant);
@@ -4152,16 +4184,8 @@ static DMCRet dmc_set_seq_token(DMCContext *context,
DMCRet ret;
int c;
-
- if (!(context->cflags & DCOMP_TRACE)) {
- RETURN_ERROR("Special form 'set_seq_token' used in wrong dialect.",
- context,
- *constant);
- }
- if (context->is_guard) {
- RETURN_ERROR("Special form 'set_seq_token' called in "
- "guard context.", context, *constant);
- }
+ if (!check_trace("set_seq_trace", context, constant, DCOMP_ALLOW_TRACE_OPS, 0, &ret))
+ return ret;
if (a != 3) {
RETURN_TERM_ERROR("Special form 'set_seq_token' called with wrong "
@@ -4198,16 +4222,11 @@ static DMCRet dmc_get_seq_token(DMCContext *context,
{
Eterm *p = tuple_val(t);
Uint a = arityval(*p);
+ DMCRet ret;
+
+ if (!check_trace("get_seq_token", context, constant, DCOMP_ALLOW_TRACE_OPS, 0, &ret))
+ return ret;
- if (!(context->cflags & DCOMP_TRACE)) {
- RETURN_ERROR("Special form 'get_seq_token' used in wrong dialect.",
- context,
- *constant);
- }
- if (context->is_guard) {
- RETURN_ERROR("Special form 'get_seq_token' called in "
- "guard context.", context, *constant);
- }
if (a != 1) {
RETURN_TERM_ERROR("Special form 'get_seq_token' called with "
"arguments in %T.", t, context,
@@ -4271,16 +4290,10 @@ static DMCRet dmc_process_dump(DMCContext *context,
{
Eterm *p = tuple_val(t);
Uint a = arityval(*p);
-
- if (!(context->cflags & DCOMP_TRACE)) {
- RETURN_ERROR("Special form 'process_dump' used in wrong dialect.",
- context,
- *constant);
- }
- if (context->is_guard) {
- RETURN_ERROR("Special form 'process_dump' called in "
- "guard context.", context, *constant);
- }
+ DMCRet ret;
+
+ if (!check_trace("process_dump", context, constant, DCOMP_ALLOW_TRACE_OPS, 0, &ret))
+ return ret;
if (a != 1) {
RETURN_TERM_ERROR("Special form 'process_dump' called with "
@@ -4304,17 +4317,8 @@ static DMCRet dmc_enable_trace(DMCContext *context,
DMCRet ret;
int c;
-
- if (!(context->cflags & DCOMP_TRACE)) {
- RETURN_ERROR("Special form 'enable_trace' used in wrong dialect.",
- context,
- *constant);
- }
- if (context->is_guard) {
- RETURN_ERROR("Special form 'enable_trace' called in guard context.",
- context,
- *constant);
- }
+ if (!check_trace("enable_trace", context, constant, DCOMP_ALLOW_TRACE_OPS, 0, &ret))
+ return ret;
switch (a) {
case 2:
@@ -4363,18 +4367,9 @@ static DMCRet dmc_disable_trace(DMCContext *context,
Uint a = arityval(*p);
DMCRet ret;
int c;
-
- if (!(context->cflags & DCOMP_TRACE)) {
- RETURN_ERROR("Special form 'disable_trace' used in wrong dialect.",
- context,
- *constant);
- }
- if (context->is_guard) {
- RETURN_ERROR("Special form 'disable_trace' called in guard context.",
- context,
- *constant);
- }
+ if (!check_trace("disable_trace", context, constant, DCOMP_ALLOW_TRACE_OPS, 0, &ret))
+ return ret;
switch (a) {
case 2:
@@ -4424,17 +4419,8 @@ static DMCRet dmc_trace(DMCContext *context,
DMCRet ret;
int c;
-
- if (!(context->cflags & DCOMP_TRACE)) {
- RETURN_ERROR("Special form 'trace' used in wrong dialect.",
- context,
- *constant);
- }
- if (context->is_guard) {
- RETURN_ERROR("Special form 'trace' called in guard context.",
- context,
- *constant);
- }
+ if (!check_trace("trace", context, constant, DCOMP_ALLOW_TRACE_OPS, 0, &ret))
+ return ret;
switch (a) {
case 3:
@@ -4495,16 +4481,11 @@ static DMCRet dmc_caller(DMCContext *context,
{
Eterm *p = tuple_val(t);
Uint a = arityval(*p);
+ DMCRet ret;
- if (!(context->cflags & DCOMP_TRACE)) {
- RETURN_ERROR("Special form 'caller' used in wrong dialect.",
- context,
- *constant);
- }
- if (context->is_guard) {
- RETURN_ERROR("Special form 'caller' called in "
- "guard context.", context, *constant);
- }
+ if (!check_trace("caller", context, constant,
+ (DCOMP_CALL_TRACE|DCOMP_ALLOW_TRACE_OPS), 0, &ret))
+ return ret;
if (a != 1) {
RETURN_TERM_ERROR("Special form 'caller' called with "
@@ -4530,15 +4511,8 @@ static DMCRet dmc_silent(DMCContext *context,
DMCRet ret;
int c;
- if (!(context->cflags & DCOMP_TRACE)) {
- RETURN_ERROR("Special form 'silent' used in wrong dialect.",
- context,
- *constant);
- }
- if (context->is_guard) {
- RETURN_ERROR("Special form 'silent' called in "
- "guard context.", context, *constant);
- }
+ if (!check_trace("silent", context, constant, DCOMP_ALLOW_TRACE_OPS, 0, &ret))
+ return ret;
if (a != 2) {
RETURN_TERM_ERROR("Special form 'silent' called with wrong "
@@ -5078,13 +5052,16 @@ static Eterm match_spec_test(Process *p, Eterm against, Eterm spec, int trace)
return THE_NON_VALUE;
}
if (trace) {
- lint_res = db_match_set_lint(p, spec, DCOMP_TRACE | DCOMP_FAKE_DESTRUCTIVE);
- mps = db_match_set_compile(p, spec, DCOMP_TRACE | DCOMP_FAKE_DESTRUCTIVE);
+ const Uint cflags = (DCOMP_TRACE | DCOMP_FAKE_DESTRUCTIVE |
+ DCOMP_CALL_TRACE | DCOMP_ALLOW_TRACE_OPS);
+ lint_res = db_match_set_lint(p, spec, cflags);
+ mps = db_match_set_compile(p, spec, cflags);
} else {
- lint_res = db_match_set_lint(p, spec, DCOMP_TABLE | DCOMP_FAKE_DESTRUCTIVE);
- mps = db_match_set_compile(p, spec, DCOMP_TABLE | DCOMP_FAKE_DESTRUCTIVE);
+ const Uint cflags = (DCOMP_TABLE | DCOMP_FAKE_DESTRUCTIVE);
+ lint_res = db_match_set_lint(p, spec, cflags);
+ mps = db_match_set_compile(p, spec, cflags);
}
-
+
if (mps == NULL) {
hp = HAlloc(p,3);
ret = TUPLE2(hp, am_error, lint_res);
@@ -5115,7 +5092,8 @@ static Eterm match_spec_test(Process *p, Eterm against, Eterm spec, int trace)
}
save_cp = p->cp;
p->cp = NULL;
- res = erts_match_set_run(p, mps, arr, n,
+ res = erts_match_set_run_trace(p, p,
+ mps, arr, n,
ERTS_PAM_COPY_RESULT|ERTS_PAM_IGNORE_TRACE_SILENT,
&ret_flags);
p->cp = save_cp;
@@ -5198,7 +5176,8 @@ Eterm db_match_dbterm(DbTableCommon* tb, Process* c_p, Binary* bprog,
obj = db_alloc_tmp_uncompressed(tb, obj);
}
- res = db_prog_match(c_p, bprog, make_tuple(obj->tpl), NULL, 0,
+ res = db_prog_match(c_p, c_p,
+ bprog, make_tuple(obj->tpl), NULL, 0,
ERTS_PAM_COPY_RESULT|ERTS_PAM_CONTIGUOUS_TUPLE, &dummy);
if (is_value(res) && hpp!=NULL) {
diff --git a/erts/emulator/beam/erl_db_util.h b/erts/emulator/beam/erl_db_util.h
index 911ed37aef..60f7067d70 100644
--- a/erts/emulator/beam/erl_db_util.h
+++ b/erts/emulator/beam/erl_db_util.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
@@ -425,6 +425,11 @@ typedef struct dmc_err_info {
#define DCOMP_FAKE_DESTRUCTIVE ((Uint) 8) /* When this is active, no setting of
trace control words or seq_trace tokens will be done. */
+/* Allow lock seizing operations on the tracee and 3rd party processes */
+#define DCOMP_ALLOW_TRACE_OPS ((Uint) 0x10)
+
+/* This is call trace */
+#define DCOMP_CALL_TRACE ((Uint) 0x20)
Binary *db_match_compile(Eterm *matchexpr, Eterm *guards,
Eterm *body, int num_matches,
@@ -435,7 +440,8 @@ Binary *db_match_compile(Eterm *matchexpr, Eterm *guards,
Eterm db_match_dbterm(DbTableCommon* tb, Process* c_p, Binary* bprog,
int all, DbTerm* obj, Eterm** hpp, Uint extra);
-Eterm db_prog_match(Process *p, Binary *prog, Eterm term,
+Eterm db_prog_match(Process *p, Process *self,
+ Binary *prog, Eterm term,
Eterm *termp, int arity,
enum erts_pam_run_flags in_flags,
Uint32 *return_flags /* Zeroed on enter */);
diff --git a/erts/emulator/beam/erl_debug.c b/erts/emulator/beam/erl_debug.c
index 2902c98864..3e3bfa03a2 100644
--- a/erts/emulator/beam/erl_debug.c
+++ b/erts/emulator/beam/erl_debug.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/emulator/beam/erl_driver.h b/erts/emulator/beam/erl_driver.h
index 0234b9b0e4..97a69140c3 100644
--- a/erts/emulator/beam/erl_driver.h
+++ b/erts/emulator/beam/erl_driver.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/beam/erl_drv_nif.h b/erts/emulator/beam/erl_drv_nif.h
index f6b946ae82..2700b62854 100644
--- a/erts/emulator/beam/erl_drv_nif.h
+++ b/erts/emulator/beam/erl_drv_nif.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010. All Rights Reserved.
+ * 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.
diff --git a/erts/emulator/beam/erl_drv_thread.c b/erts/emulator/beam/erl_drv_thread.c
index 184f8e8931..92edce5176 100644
--- a/erts/emulator/beam/erl_drv_thread.c
+++ b/erts/emulator/beam/erl_drv_thread.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2007-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2007-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.
diff --git a/erts/emulator/beam/erl_fun.c b/erts/emulator/beam/erl_fun.c
index ed555aa92f..6ce1376c81 100644
--- a/erts/emulator/beam/erl_fun.c
+++ b/erts/emulator/beam/erl_fun.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2000-2010. All Rights Reserved.
+ * Copyright Ericsson AB 2000-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.
diff --git a/erts/emulator/beam/erl_fun.h b/erts/emulator/beam/erl_fun.h
index 0024b1ff71..8c4deea7a0 100644
--- a/erts/emulator/beam/erl_fun.h
+++ b/erts/emulator/beam/erl_fun.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2000-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2000-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.
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index 0d125c5598..bed7e668d7 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2002-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.
@@ -116,7 +116,7 @@ static Eterm *full_sweep_heaps(Process *p,
char *oh, Uint oh_size,
Eterm *objv, int nobj);
static int garbage_collect(Process* p, ErlHeapFragment *live_hf_end,
- int need, Eterm* objv, int nobj);
+ int need, Eterm* objv, int nobj, int fcalls);
static int major_collection(Process* p, ErlHeapFragment *live_hf_end,
int need, Eterm* objv, int nobj, Uint *recl);
static int minor_collection(Process* p, ErlHeapFragment *live_hf_end,
@@ -392,15 +392,15 @@ erts_gc_after_bif_call_lhf(Process* p, ErlHeapFragment *live_hf_end,
regs = ERTS_PROC_GET_SCHDATA(p)->x_reg_array;
}
#endif
- cost = garbage_collect(p, live_hf_end, 0, regs, p->arity);
+ cost = garbage_collect(p, live_hf_end, 0, regs, p->arity, p->fcalls);
} else {
- cost = garbage_collect(p, live_hf_end, 0, regs, arity);
+ cost = garbage_collect(p, live_hf_end, 0, regs, arity, p->fcalls);
}
} else {
Eterm val[1];
val[0] = result;
- cost = garbage_collect(p, live_hf_end, 0, val, 1);
+ cost = garbage_collect(p, live_hf_end, 0, val, 1, p->fcalls);
result = val[0];
}
BUMP_REDS(p, cost);
@@ -431,7 +431,7 @@ static ERTS_INLINE void reset_active_writer(Process *p)
#define ERTS_ABANDON_HEAP_COST 10
static int
-delay_garbage_collection(Process *p, ErlHeapFragment *live_hf_end, int need)
+delay_garbage_collection(Process *p, ErlHeapFragment *live_hf_end, int need, int fcalls)
{
ErlHeapFragment *hfrag;
Eterm *orig_heap, *orig_hend, *orig_htop, *orig_stop;
@@ -506,12 +506,16 @@ delay_garbage_collection(Process *p, ErlHeapFragment *live_hf_end, int need)
/* Make sure that we do a proper GC as soon as possible... */
p->flags |= F_FORCE_GC;
- reds_left = ERTS_BIF_REDS_LEFT(p);
+ reds_left = ERTS_REDS_LEFT(p, fcalls);
+ ASSERT(CONTEXT_REDS - reds_left >= ERTS_PROC_GET_SCHDATA(p)->virtual_reds);
+
if (reds_left > ERTS_ABANDON_HEAP_COST) {
int vreds = reds_left - ERTS_ABANDON_HEAP_COST;
- ERTS_VBUMP_REDS(p, vreds);
+ ERTS_PROC_GET_SCHDATA((p))->virtual_reds += vreds;
}
- return ERTS_ABANDON_HEAP_COST;
+
+ ASSERT(CONTEXT_REDS >= ERTS_PROC_GET_SCHDATA(p)->virtual_reds);
+ return reds_left;
}
static ERTS_FORCE_INLINE Uint
@@ -570,7 +574,7 @@ young_gen_usage(Process *p)
*/
static int
garbage_collect(Process* p, ErlHeapFragment *live_hf_end,
- int need, Eterm* objv, int nobj)
+ int need, Eterm* objv, int nobj, int fcalls)
{
Uint reclaimed_now = 0;
int reds;
@@ -581,8 +585,11 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end,
DTRACE_CHARBUF(pidbuf, DTRACE_TERM_BUF_SIZE);
#endif
+ ASSERT(CONTEXT_REDS - ERTS_REDS_LEFT(p, fcalls)
+ >= ERTS_PROC_GET_SCHDATA(p)->virtual_reds);
+
if (p->flags & (F_DISABLE_GC|F_DELAY_GC))
- return delay_garbage_collection(p, live_hf_end, need);
+ return delay_garbage_collection(p, live_hf_end, need, fcalls);
if (p->abandoned_heap)
live_hf_end = ERTS_INVALID_HFRAG_PTR;
@@ -593,10 +600,6 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end,
esdp = erts_get_scheduler_data();
- if (IS_TRACED_FL(p, F_TRACE_GC)) {
- trace_gc(p, am_gc_start);
- }
-
erts_smp_atomic32_read_bor_nob(&p->state, ERTS_PSFLG_GC);
if (erts_system_monitor_long_gc != 0)
start_time = erts_get_monotonic_time(esdp);
@@ -619,18 +622,29 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end,
*/
if (GEN_GCS(p) < MAX_GEN_GCS(p) && !(FLAGS(p) & F_NEED_FULLSWEEP)) {
- DTRACE2(gc_minor_start, pidbuf, need);
- reds = minor_collection(p, live_hf_end, need, objv, nobj, &reclaimed_now);
- DTRACE2(gc_minor_end, pidbuf, reclaimed_now);
- if (reds < 0)
- goto do_major_collection;
- }
- else {
- do_major_collection:
+ if (IS_TRACED_FL(p, F_TRACE_GC)) {
+ trace_gc(p, am_gc_minor_start, need);
+ }
+ DTRACE2(gc_minor_start, pidbuf, need);
+ reds = minor_collection(p, live_hf_end, need, objv, nobj, &reclaimed_now);
+ DTRACE2(gc_minor_end, pidbuf, reclaimed_now);
+ if (IS_TRACED_FL(p, F_TRACE_GC)) {
+ trace_gc(p, am_gc_minor_end, reclaimed_now);
+ }
+ if (reds < 0)
+ goto do_major_collection;
+ } else {
+do_major_collection:
ERTS_MSACC_SET_STATE_CACHED_M_X(ERTS_MSACC_STATE_GC_FULL);
- DTRACE2(gc_major_start, pidbuf, need);
- reds = major_collection(p, live_hf_end, need, objv, nobj, &reclaimed_now);
- DTRACE2(gc_major_end, pidbuf, reclaimed_now);
+ if (IS_TRACED_FL(p, F_TRACE_GC)) {
+ trace_gc(p, am_gc_major_start, need);
+ }
+ DTRACE2(gc_major_start, pidbuf, need);
+ reds = major_collection(p, live_hf_end, need, objv, nobj, &reclaimed_now);
+ DTRACE2(gc_major_end, pidbuf, reclaimed_now);
+ if (IS_TRACED_FL(p, F_TRACE_GC)) {
+ trace_gc(p, am_gc_major_end, reclaimed_now);
+ }
ERTS_MSACC_SET_STATE_CACHED_M_X(ERTS_MSACC_STATE_GC);
}
@@ -646,10 +660,6 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end,
erts_smp_atomic32_read_band_nob(&p->state, ~ERTS_PSFLG_GC);
- if (IS_TRACED_FL(p, F_TRACE_GC)) {
- trace_gc(p, am_gc_end);
- }
-
if (erts_system_monitor_long_gc != 0) {
ErtsMonotonicTime end_time;
Uint gc_time;
@@ -700,16 +710,23 @@ garbage_collect(Process* p, ErlHeapFragment *live_hf_end,
}
int
-erts_garbage_collect_nobump(Process* p, int need, Eterm* objv, int nobj)
+erts_garbage_collect_nobump(Process* p, int need, Eterm* objv, int nobj, int fcalls)
{
- return garbage_collect(p, ERTS_INVALID_HFRAG_PTR, need, objv, nobj);
+ int reds = garbage_collect(p, ERTS_INVALID_HFRAG_PTR, need, objv, nobj, fcalls);
+ int reds_left = ERTS_REDS_LEFT(p, fcalls);
+ if (reds > reds_left)
+ reds = reds_left;
+ ASSERT(CONTEXT_REDS - (reds_left - reds) >= ERTS_PROC_GET_SCHDATA(p)->virtual_reds);
+ return reds;
}
void
erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj)
{
- int reds = garbage_collect(p, ERTS_INVALID_HFRAG_PTR, need, objv, nobj);
+ int reds = garbage_collect(p, ERTS_INVALID_HFRAG_PTR, need, objv, nobj, p->fcalls);
BUMP_REDS(p, reds);
+ ASSERT(CONTEXT_REDS - ERTS_BIF_REDS_LEFT(p)
+ >= ERTS_PROC_GET_SCHDATA(p)->virtual_reds);
}
/*
@@ -2053,8 +2070,26 @@ copy_one_frag(Eterm** hpp, ErlOffHeap* off_heap,
*hp++ = val;
break;
case TAG_PRIMARY_LIST:
+#ifdef SHCOPY_SEND
+ if (erts_is_literal(val,list_val(val))) {
+ *hp++ = val;
+ } else {
+ *hp++ = offset_ptr(val, offs);
+ }
+#else
+ *hp++ = offset_ptr(val, offs);
+#endif
+ break;
case TAG_PRIMARY_BOXED:
- *hp++ = offset_ptr(val, offs);
+#ifdef SHCOPY_SEND
+ if (erts_is_literal(val,boxed_val(val))) {
+ *hp++ = val;
+ } else {
+ *hp++ = offset_ptr(val, offs);
+ }
+#else
+ *hp++ = offset_ptr(val, offs);
+#endif
break;
case TAG_PRIMARY_HEADER:
*hp++ = val;
@@ -2233,9 +2268,7 @@ setup_rootset(Process *p, Eterm *objv, int nobj, Rootset *rootset)
n++;
}
#endif
- ASSERT(is_nil(ERTS_TRACER_PROC(p)) ||
- is_internal_pid(ERTS_TRACER_PROC(p)) ||
- is_internal_port(ERTS_TRACER_PROC(p)));
+ ASSERT(IS_TRACER_VALID(ERTS_TRACER(p)));
ASSERT(is_pid(follow_moved(p->group_leader, (Eterm) 0)));
if (is_not_immed(p->group_leader)) {
@@ -2905,7 +2938,7 @@ reply_gc_info(void *vgcirp)
hpp = &hp;
}
- erts_queue_message(rp, &rp_locks, mp, msg, NIL);
+ erts_queue_message(rp, rp_locks, mp, msg, am_system);
if (gcirp->req_sched == esdp->no)
rp_locks &= ~ERTS_PROC_LOCK_MAIN;
@@ -2990,10 +3023,30 @@ erts_process_gc_info(Process *p, Uint *sizep, Eterm **hpp)
};
Eterm res = THE_NON_VALUE;
+ ErtsMessage *mp;
ERTS_CT_ASSERT(sizeof(values)/sizeof(*values) == sizeof(tags)/sizeof(*tags));
ERTS_CT_ASSERT(sizeof(values)/sizeof(*values) == ERTS_PROCESS_GC_INFO_MAX_TERMS);
+ if (p->abandoned_heap) {
+ Eterm *htop, *heap;
+ ERTS_GET_ORIG_HEAP(p, heap, htop);
+ values[3] = HIGH_WATER(p) - heap;
+ values[6] = htop - heap;
+ }
+
+ if (p->flags & F_ON_HEAP_MSGQ) {
+ /* If on heap messages in the internal queue are counted
+ as being part of the heap, so we have to add them to the
+ am_mbuf_size value. process_info(total_heap_size) should
+ be the same as adding old_heap_block_size + heap_block_size
+ + mbuf_size.
+ */
+ for (mp = p->msg.first; mp; mp = mp->next)
+ if (mp->data.attached)
+ values[2] += erts_msg_attached_data_size(mp);
+ }
+
res = erts_bld_atom_uword_2tup_list(hpp,
sizep,
sizeof(values)/sizeof(*values),
diff --git a/erts/emulator/beam/erl_gc.h b/erts/emulator/beam/erl_gc.h
index 2cedd9361f..8a6ff99990 100644
--- a/erts/emulator/beam/erl_gc.h
+++ b/erts/emulator/beam/erl_gc.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2007-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2007-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.
@@ -139,7 +139,7 @@ Eterm erts_process_gc_info(struct process*, Uint *, Eterm **);
void erts_gc_info(ErtsGCInfo *gcip);
void erts_init_gc(void);
-int erts_garbage_collect_nobump(struct process*, int, Eterm*, int);
+int erts_garbage_collect_nobump(struct process*, int, Eterm*, int, int);
void erts_garbage_collect(struct process*, int, Eterm*, int);
void erts_garbage_collect_hibernate(struct process* p);
Eterm erts_gc_after_bif_call_lhf(struct process* p, ErlHeapFragment *live_hf_end,
diff --git a/erts/emulator/beam/erl_goodfit_alloc.c b/erts/emulator/beam/erl_goodfit_alloc.c
index 9b4aad9d91..223ba193da 100644
--- a/erts/emulator/beam/erl_goodfit_alloc.c
+++ b/erts/emulator/beam/erl_goodfit_alloc.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/beam/erl_goodfit_alloc.h b/erts/emulator/beam/erl_goodfit_alloc.h
index ababdbd0a1..76dd558234 100644
--- a/erts/emulator/beam/erl_goodfit_alloc.h
+++ b/erts/emulator/beam/erl_goodfit_alloc.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/beam/erl_hl_timer.c b/erts/emulator/beam/erl_hl_timer.c
index 491d2f8c84..c418762578 100644
--- a/erts/emulator/beam/erl_hl_timer.c
+++ b/erts/emulator/beam/erl_hl_timer.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2015. All Rights Reserved.
+ * Copyright Ericsson AB 2015-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.
@@ -1247,8 +1247,8 @@ hlt_bif_timer_timeout(ErtsHLTimer *tmr, Uint32 roflgs)
if (!ERTS_PROC_IS_EXITING(proc)) {
ErtsMessage *mp = erts_alloc_message(0, NULL);
mp->data.heap_frag = tmr->btm.bp;
- erts_queue_message(proc, &proc_locks, mp,
- tmr->btm.message, NIL);
+ erts_queue_message(proc, proc_locks, mp,
+ tmr->btm.message, am_clock_service);
erts_smp_proc_unlock(proc, ERTS_PROC_LOCKS_MSG_SEND);
queued_message = 1;
proc_locks &= ~ERTS_PROC_LOCKS_MSG_SEND;
@@ -1980,7 +1980,7 @@ access_sched_local_btm(Process *c_p, Eterm pid,
ERTS_HLT_ASSERT(hp + (async ? 4 : 3) == hp_end);
- erts_queue_message(proc, &proc_locks, mp, msg, NIL);
+ erts_queue_message(proc, proc_locks, mp, msg, am_clock_service);
if (c_p)
proc_locks &= ~ERTS_PROC_LOCK_MAIN;
@@ -2111,7 +2111,7 @@ try_access_sched_remote_btm(ErtsSchedulerData *esdp,
msg = TUPLE3(hp, tag, tref, res);
- erts_queue_message(c_p, &proc_locks, mp, msg, NIL);
+ erts_queue_message(c_p, proc_locks, mp, msg, am_clock_service);
proc_locks &= ~ERTS_PROC_LOCK_MAIN;
if (proc_locks)
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index 86c4eeb484..fcd2739ac3 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
@@ -206,15 +206,15 @@ int erts_no_line_info = 0; /* -L: Don't load line information */
ErtsModifiedTimings erts_modified_timings[] = {
/* 0 */ {make_small(0), CONTEXT_REDS, INPUT_REDUCTIONS},
- /* 1 */ {make_small(0), 2*CONTEXT_REDS, 2*INPUT_REDUCTIONS},
+ /* 1 */ {make_small(0), (3*CONTEXT_REDS)/4, 2*INPUT_REDUCTIONS},
/* 2 */ {make_small(0), CONTEXT_REDS/2, INPUT_REDUCTIONS/2},
- /* 3 */ {make_small(0), 3*CONTEXT_REDS, 3*INPUT_REDUCTIONS},
+ /* 3 */ {make_small(0), (7*CONTEXT_REDS)/8, 3*INPUT_REDUCTIONS},
/* 4 */ {make_small(0), CONTEXT_REDS/3, 3*INPUT_REDUCTIONS},
- /* 5 */ {make_small(0), 4*CONTEXT_REDS, INPUT_REDUCTIONS/2},
+ /* 5 */ {make_small(0), (10*CONTEXT_REDS)/11, INPUT_REDUCTIONS/2},
/* 6 */ {make_small(1), CONTEXT_REDS/4, 2*INPUT_REDUCTIONS},
- /* 7 */ {make_small(1), 5*CONTEXT_REDS, INPUT_REDUCTIONS/3},
+ /* 7 */ {make_small(1), (5*CONTEXT_REDS)/7, INPUT_REDUCTIONS/3},
/* 8 */ {make_small(10), CONTEXT_REDS/5, 3*INPUT_REDUCTIONS},
- /* 9 */ {make_small(10), 6*CONTEXT_REDS, INPUT_REDUCTIONS/4}
+ /* 9 */ {make_small(10), (6*CONTEXT_REDS)/7, INPUT_REDUCTIONS/4}
};
#define ERTS_MODIFIED_TIMING_LEVELS \
@@ -578,6 +578,8 @@ void erts_usage(void)
VH_DEFAULT_SIZE);
erts_fprintf(stderr, "-hpds size initial process dictionary size (default %d)\n",
erts_pd_initial_size);
+ erts_fprintf(stderr, "-hmqd val set default message queue data flag for processes,\n");
+ erts_fprintf(stderr, " valid values are: off_heap | on_heap | mixed\n");
/* erts_fprintf(stderr, "-i module set the boot module (default init)\n"); */
@@ -655,8 +657,6 @@ void erts_usage(void)
erts_fprintf(stderr, "-W<i|w|e> set error logger warnings mapping,\n");
erts_fprintf(stderr, " see error_logger documentation for details\n");
- erts_fprintf(stderr, "-xmqd val set default message queue data flag for processes,\n");
- erts_fprintf(stderr, " valid values are: off_heap | on_heap | mixed\n");
erts_fprintf(stderr, "-zdbbl size set the distribution buffer busy limit in kilobytes\n");
erts_fprintf(stderr, " valid range is [1-%d]\n", INT_MAX/1024);
erts_fprintf(stderr, "-zdntgc time set delayed node table gc in seconds\n");
@@ -1487,6 +1487,7 @@ erl_start(int argc, char **argv)
* h|ms - min_heap_size
* h|mbs - min_bin_vheap_size
* h|pds - erts_pd_initial_size
+ * h|mqd - message_queue_data
*
*/
if (has_prefix("mbs", sub_param)) {
@@ -1512,6 +1513,23 @@ erl_start(int argc, char **argv)
}
VERBOSE(DEBUG_SYSTEM, ("using initial process dictionary size %d\n",
erts_pd_initial_size));
+ } else if (has_prefix("mqd", sub_param)) {
+ arg = get_arg(sub_param+3, argv[i+1], &i);
+ if (sys_strcmp(arg, "mixed") == 0)
+ erts_default_spo_flags &= ~(SPO_ON_HEAP_MSGQ|SPO_OFF_HEAP_MSGQ);
+ else if (sys_strcmp(arg, "on_heap") == 0) {
+ erts_default_spo_flags &= ~SPO_OFF_HEAP_MSGQ;
+ erts_default_spo_flags |= SPO_ON_HEAP_MSGQ;
+ }
+ else if (sys_strcmp(arg, "off_heap") == 0) {
+ erts_default_spo_flags &= ~SPO_ON_HEAP_MSGQ;
+ erts_default_spo_flags |= SPO_OFF_HEAP_MSGQ;
+ }
+ else {
+ erts_fprintf(stderr,
+ "Invalid message_queue_data flag: %s\n", arg);
+ erts_usage();
+ }
} else {
/* backward compatibility */
arg = get_arg(argv[i]+2, argv[i+1], &i);
@@ -2047,32 +2065,6 @@ erl_start(int argc, char **argv)
}
break;
- case 'x': {
- char *sub_param = argv[i]+2;
- if (has_prefix("mqd", sub_param)) {
- arg = get_arg(sub_param+3, argv[i+1], &i);
- if (sys_strcmp(arg, "mixed") == 0)
- erts_default_spo_flags &= ~(SPO_ON_HEAP_MSGQ|SPO_OFF_HEAP_MSGQ);
- else if (sys_strcmp(arg, "on_heap") == 0) {
- erts_default_spo_flags &= ~SPO_OFF_HEAP_MSGQ;
- erts_default_spo_flags |= SPO_ON_HEAP_MSGQ;
- }
- else if (sys_strcmp(arg, "off_heap") == 0) {
- erts_default_spo_flags &= ~SPO_ON_HEAP_MSGQ;
- erts_default_spo_flags |= SPO_OFF_HEAP_MSGQ;
- }
- else {
- erts_fprintf(stderr,
- "Invalid message_queue_data flag: %s\n", arg);
- erts_usage();
- }
- } else {
- erts_fprintf(stderr, "bad -x option %s\n", argv[i]);
- erts_usage();
- }
- break;
- }
-
case 'z': {
char *sub_param = argv[i]+2;
@@ -2188,6 +2180,7 @@ erl_start(int argc, char **argv)
init_break_handler();
if (replace_intr)
erts_replace_intr();
+ sys_init_suspend_handler();
#endif
boot_argc = argc - i; /* Number of arguments to init */
diff --git a/erts/emulator/beam/erl_instrument.c b/erts/emulator/beam/erl_instrument.c
index 12a72ad839..f84c63e7a4 100644
--- a/erts/emulator/beam/erl_instrument.c
+++ b/erts/emulator/beam/erl_instrument.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/beam/erl_instrument.h b/erts/emulator/beam/erl_instrument.h
index cb3b1920d3..1f04c91d5e 100644
--- a/erts/emulator/beam/erl_instrument.h
+++ b/erts/emulator/beam/erl_instrument.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c
index 598bf84c0b..39c0617143 100644
--- a/erts/emulator/beam/erl_lock_check.c
+++ b/erts/emulator/beam/erl_lock_check.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
@@ -97,6 +97,7 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "dist_entry_links", "address" },
{ "code_write_permission", NULL },
{ "proc_status", "pid" },
+ { "proc_trace", "pid" },
{ "ports_snapshot", NULL },
{ "meta_name_tab", "address" },
{ "meta_main_tab_slot", "address" },
@@ -148,6 +149,7 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "dist_entry_out_queue", "address" },
{ "port_sched_lock", "port_id" },
{ "sys_msg_q", NULL },
+ { "tracer_mtx", NULL },
{ "port_table", NULL },
#endif
{ "mtrace_op", NULL },
@@ -160,9 +162,6 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "proclist_pre_alloc_lock", "address" },
{ "xports_list_pre_alloc_lock", "address" },
{ "inet_buffer_stack_lock", NULL },
- { "gc_info", NULL },
- { "io_wake", NULL },
- { "timer_wheel", NULL },
{ "system_block", NULL },
{ "timeofday", NULL },
{ "get_time", NULL },
diff --git a/erts/emulator/beam/erl_lock_check.h b/erts/emulator/beam/erl_lock_check.h
index 66251ef4e8..18296d1fec 100644
--- a/erts/emulator/beam/erl_lock_check.h
+++ b/erts/emulator/beam/erl_lock_check.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/beam/erl_lock_count.c b/erts/emulator/beam/erl_lock_count.c
index bd00480ba2..a00e0f0fff 100644
--- a/erts/emulator/beam/erl_lock_count.c
+++ b/erts/emulator/beam/erl_lock_count.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/emulator/beam/erl_lock_count.h b/erts/emulator/beam/erl_lock_count.h
index 4cc6a5c695..3e8dcefe69 100644
--- a/erts/emulator/beam/erl_lock_count.h
+++ b/erts/emulator/beam/erl_lock_count.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c
index 4b6931f848..8efc983f04 100644
--- a/erts/emulator/beam/erl_map.c
+++ b/erts/emulator/beam/erl_map.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2014. All Rights Reserved.
+ * Copyright Ericsson AB 2014-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.
@@ -54,6 +54,7 @@
* - maps:new/0
* - maps:put/3
* - maps:remove/2
+ * - maps:take/2
* - maps:to_list/1
* - maps:update/3
* - maps:values/1
@@ -93,7 +94,7 @@ static Uint hashmap_subtree_size(Eterm node);
static Eterm hashmap_to_list(Process *p, Eterm map);
static Eterm hashmap_keys(Process *p, Eterm map);
static Eterm hashmap_values(Process *p, Eterm map);
-static Eterm hashmap_delete(Process *p, Uint32 hx, Eterm key, Eterm node);
+static Eterm hashmap_delete(Process *p, Uint32 hx, Eterm key, Eterm node, Eterm *value);
static Eterm flatmap_from_validated_list(Process *p, Eterm list, Uint size);
static Eterm hashmap_from_validated_list(Process *p, Eterm list, Uint size);
static Eterm hashmap_from_unsorted_array(ErtsHeapFactory*, hxnode_t *hxns, Uint n, int reject_dupkeys);
@@ -196,13 +197,13 @@ erts_maps_get(Eterm key, Eterm map)
return &vs[i];
}
}
- }
-
- for (i = 0; i < n; i++) {
- if (EQ(ks[i], key)) {
- return &vs[i];
- }
- }
+ } else {
+ for (i = 0; i < n; i++) {
+ if (EQ(ks[i], key)) {
+ return &vs[i];
+ }
+ }
+ }
return NULL;
}
ASSERT(is_hashmap(map));
@@ -1521,10 +1522,45 @@ BIF_RETTYPE maps_put_3(BIF_ALIST_3) {
BIF_ERROR(BIF_P, BADMAP);
}
-/* maps:remove/3 */
+/* maps:take/2 */
-int erts_maps_remove(Process *p, Eterm key, Eterm map, Eterm *res) {
+BIF_RETTYPE maps_take_2(BIF_ALIST_2) {
+ if (is_map(BIF_ARG_2)) {
+ Eterm res, map, val;
+ if (erts_maps_take(BIF_P, BIF_ARG_1, BIF_ARG_2, &map, &val)) {
+ Eterm *hp = HAlloc(BIF_P, 3);
+ res = make_tuple(hp);
+ *hp++ = make_arityval(2);
+ *hp++ = val;
+ *hp++ = map;
+ BIF_RET(res);
+ }
+ BIF_RET(am_error);
+ }
+ BIF_P->fvalue = BIF_ARG_2;
+ BIF_ERROR(BIF_P, BADMAP);
+}
+
+/* maps:remove/2 */
+
+BIF_RETTYPE maps_remove_2(BIF_ALIST_2) {
+ if (is_map(BIF_ARG_2)) {
+ Eterm res;
+ (void) erts_maps_take(BIF_P, BIF_ARG_1, BIF_ARG_2, &res, NULL);
+ BIF_RET(res);
+ }
+ BIF_P->fvalue = BIF_ARG_2;
+ BIF_ERROR(BIF_P, BADMAP);
+}
+
+/* erts_maps_take
+ * return 1 if key is found, otherwise 0
+ * If the key is not found res (output map) will be map (input map)
+ */
+int erts_maps_take(Process *p, Eterm key, Eterm map,
+ Eterm *res, Eterm *value) {
Uint32 hx;
+ Eterm ret;
if (is_flatmap(map)) {
Sint n;
Uint need;
@@ -1537,7 +1573,7 @@ int erts_maps_remove(Process *p, Eterm key, Eterm map, Eterm *res) {
if (n == 0) {
*res = map;
- return 1;
+ return 0;
}
ks = flatmap_get_keys(mp);
@@ -1564,6 +1600,7 @@ int erts_maps_remove(Process *p, Eterm key, Eterm map, Eterm *res) {
if (is_immed(key)) {
while (1) {
if (*ks == key) {
+ if (value) *value = *vs;
goto found_key;
} else if (--n) {
*mhp++ = *vs++;
@@ -1574,6 +1611,7 @@ int erts_maps_remove(Process *p, Eterm key, Eterm map, Eterm *res) {
} else {
while(1) {
if (EQ(*ks, key)) {
+ if (value) *value = *vs;
goto found_key;
} else if (--n) {
*mhp++ = *vs++;
@@ -1589,7 +1627,7 @@ int erts_maps_remove(Process *p, Eterm key, Eterm map, Eterm *res) {
HRelease(p, hp_start + need, hp_start);
*res = map;
- return 1;
+ return 0;
found_key:
/* Copy rest of keys and values */
@@ -1601,19 +1639,13 @@ found_key:
}
ASSERT(is_hashmap(map));
hx = hashmap_make_hash(key);
- *res = hashmap_delete(p, hx, key, map);
- return 1;
-}
-
-BIF_RETTYPE maps_remove_2(BIF_ALIST_2) {
- if (is_map(BIF_ARG_2)) {
- Eterm res;
- if (erts_maps_remove(BIF_P, BIF_ARG_1, BIF_ARG_2, &res)) {
- BIF_RET(res);
- }
+ ret = hashmap_delete(p, hx, key, map, value);
+ if (is_value(ret)) {
+ *res = ret;
+ return 1;
}
- BIF_P->fvalue = BIF_ARG_2;
- BIF_ERROR(BIF_P, BADMAP);
+ *res = map;
+ return 0;
}
int erts_maps_update(Process *p, Eterm key, Eterm value, Eterm map, Eterm *res) {
@@ -2322,7 +2354,8 @@ static Eterm hashmap_values(Process* p, Eterm node) {
return res;
}
-static Eterm hashmap_delete(Process *p, Uint32 hx, Eterm key, Eterm map) {
+static Eterm hashmap_delete(Process *p, Uint32 hx, Eterm key,
+ Eterm map, Eterm *value) {
Eterm *hp = NULL, *nhp = NULL, *hp_end = NULL;
Eterm *ptr;
Eterm hdr, res = map, node = map;
@@ -2337,8 +2370,12 @@ static Eterm hashmap_delete(Process *p, Uint32 hx, Eterm key, Eterm map) {
switch(primary_tag(node)) {
case TAG_PRIMARY_LIST:
if (EQ(CAR(list_val(node)), key)) {
+ if (value) {
+ *value = CDR(list_val(node));
+ }
goto unroll;
}
+ res = THE_NON_VALUE;
goto not_found;
case TAG_PRIMARY_BOXED:
ptr = boxed_val(node);
@@ -2365,6 +2402,7 @@ static Eterm hashmap_delete(Process *p, Uint32 hx, Eterm key, Eterm map) {
n = hashmap_bitcount(hval);
} else {
/* not occupied */
+ res = THE_NON_VALUE;
goto not_found;
}
@@ -2394,6 +2432,7 @@ static Eterm hashmap_delete(Process *p, Uint32 hx, Eterm key, Eterm map) {
break;
}
/* not occupied */
+ res = THE_NON_VALUE;
goto not_found;
default:
erts_exit(ERTS_ERROR_EXIT, "bad header tag %ld\r\n", hdr & _HEADER_MAP_SUBTAG_MASK);
diff --git a/erts/emulator/beam/erl_map.h b/erts/emulator/beam/erl_map.h
index 052fa99f03..8b5c9582ba 100644
--- a/erts/emulator/beam/erl_map.h
+++ b/erts/emulator/beam/erl_map.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2014. All Rights Reserved.
+ * Copyright Ericsson AB 2014-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.
@@ -66,7 +66,7 @@ typedef struct flatmap_s {
/* erl_term.h stuff */
-#define flatmap_get_values(x) (((Eterm *)(x)) + 3)
+#define flatmap_get_values(x) (((Eterm *)(x)) + sizeof(flatmap_t)/sizeof(Eterm))
#define flatmap_get_keys(x) (((Eterm *)tuple_val(((flatmap_t *)(x))->keys)) + 1)
#define flatmap_get_size(x) (((flatmap_t*)(x))->size)
@@ -82,6 +82,7 @@ struct ErtsEStack_;
Eterm erts_maps_put(Process *p, Eterm key, Eterm value, Eterm map);
int erts_maps_update(Process *p, Eterm key, Eterm value, Eterm map, Eterm *res);
int erts_maps_remove(Process *p, Eterm key, Eterm map, Eterm *res);
+int erts_maps_take(Process *p, Eterm key, Eterm map, Eterm *res, Eterm *value);
Eterm erts_hashmap_insert(Process *p, Uint32 hx, Eterm key, Eterm value,
Eterm node, int is_update);
diff --git a/erts/emulator/beam/erl_math.c b/erts/emulator/beam/erl_math.c
index b46cc37495..fc0aaed18a 100644
--- a/erts/emulator/beam/erl_math.c
+++ b/erts/emulator/beam/erl_math.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c
index 88efb2c59f..9bb6e40a11 100644
--- a/erts/emulator/beam/erl_message.c
+++ b/erts/emulator/beam/erl_message.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2012. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
@@ -32,6 +32,7 @@
#include "erl_process.h"
#include "erl_binary.h"
#include "dtrace-wrapper.h"
+#include "beam_bp.h"
ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(message_ref,
ErtsMessageRef,
@@ -251,9 +252,10 @@ erts_realloc_shrink_message(ErtsMessage *mp, Uint sz, Eterm *brefs, Uint brefs_s
void
erts_queue_dist_message(Process *rcvr,
- ErtsProcLocks *rcvr_locks,
+ ErtsProcLocks rcvr_locks,
ErtsDistExternal *dist_ext,
- Eterm token)
+ Eterm token,
+ Eterm from)
{
ErtsMessage* mp;
#ifdef USE_VM_PROBES
@@ -265,7 +267,7 @@ erts_queue_dist_message(Process *rcvr,
erts_aint_t state;
#endif
- ERTS_SMP_LC_ASSERT(*rcvr_locks == erts_proc_lc_my_proc_locks(rcvr));
+ ERTS_SMP_LC_ASSERT(rcvr_locks == erts_proc_lc_my_proc_locks(rcvr));
mp = erts_alloc_message(0, NULL);
mp->data.dist_ext = dist_ext;
@@ -280,10 +282,10 @@ erts_queue_dist_message(Process *rcvr,
ERL_MESSAGE_TOKEN(mp) = token;
#ifdef ERTS_SMP
- if (!(*rcvr_locks & ERTS_PROC_LOCK_MSGQ)) {
+ if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ)) {
if (erts_smp_proc_trylock(rcvr, ERTS_PROC_LOCK_MSGQ) == EBUSY) {
ErtsProcLocks need_locks = ERTS_PROC_LOCK_MSGQ;
- if (*rcvr_locks & ERTS_PROC_LOCK_STATUS) {
+ if (rcvr_locks & ERTS_PROC_LOCK_STATUS) {
erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_STATUS);
need_locks |= ERTS_PROC_LOCK_STATUS;
}
@@ -293,7 +295,7 @@ erts_queue_dist_message(Process *rcvr,
state = erts_smp_atomic32_read_acqb(&rcvr->state);
if (state & (ERTS_PSFLG_PENDING_EXIT|ERTS_PSFLG_EXITING)) {
- if (!(*rcvr_locks & ERTS_PROC_LOCK_MSGQ))
+ if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ))
erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ);
/* Drop message if receiver is exiting or has a pending exit ... */
erts_cleanup_messages(mp);
@@ -301,10 +303,13 @@ erts_queue_dist_message(Process *rcvr,
else
#endif
if (IS_TRACED_FL(rcvr, F_TRACE_RECEIVE)) {
+ if (from == am_Empty)
+ from = dist_ext->dep->sysname;
+
/* Ahh... need to decode it in order to trace it... */
- if (!(*rcvr_locks & ERTS_PROC_LOCK_MSGQ))
+ if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ))
erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ);
- if (!erts_decode_dist_message(rcvr, *rcvr_locks, mp, 0))
+ if (!erts_decode_dist_message(rcvr, rcvr_locks, mp, 0))
erts_free_message(mp);
else {
Eterm msg = ERL_MESSAGE_TERM(mp);
@@ -324,7 +329,7 @@ erts_queue_dist_message(Process *rcvr,
tok_label, tok_lastcnt, tok_serial);
}
#endif
- erts_queue_message(rcvr, rcvr_locks, mp, msg, token);
+ erts_queue_message(rcvr, rcvr_locks, mp, msg, from);
}
}
else {
@@ -349,14 +354,14 @@ erts_queue_dist_message(Process *rcvr,
}
#endif
- LINK_MESSAGE(rcvr, mp);
+ LINK_MESSAGE(rcvr, mp, &mp->next, 1);
- if (!(*rcvr_locks & ERTS_PROC_LOCK_MSGQ))
+ if (!(rcvr_locks & ERTS_PROC_LOCK_MSGQ))
erts_smp_proc_unlock(rcvr, ERTS_PROC_LOCK_MSGQ);
erts_proc_notify_new_message(rcvr,
#ifdef ERTS_SMP
- *rcvr_locks
+ rcvr_locks
#else
0
#endif
@@ -364,31 +369,35 @@ erts_queue_dist_message(Process *rcvr,
}
}
-/* Add a message last in message queue */
+/* Add messages last in message queue */
static Sint
-queue_message(Process *c_p,
- Process* receiver,
- erts_aint32_t *receiver_state,
- ErtsProcLocks *receiver_locks,
- ErtsMessage* mp,
- Eterm message,
- Eterm seq_trace_token
-#ifdef USE_VM_PROBES
- , Eterm dt_utag
-#endif
- )
+queue_messages(Process* receiver,
+ erts_aint32_t *receiver_state,
+ ErtsProcLocks receiver_locks,
+ ErtsMessage* first,
+ ErtsMessage** last,
+ Uint len,
+ Eterm from)
{
+ ErtsTracingEvent* te;
Sint res;
int locked_msgq = 0;
erts_aint32_t state;
- ERTS_SMP_LC_ASSERT(*receiver_locks == erts_proc_lc_my_proc_locks(receiver));
+ ASSERT(is_value(ERL_MESSAGE_TERM(first)));
+ ASSERT(ERL_MESSAGE_TOKEN(first) == am_undefined ||
+ ERL_MESSAGE_TOKEN(first) == NIL ||
+ is_tuple(ERL_MESSAGE_TOKEN(first)));
#ifdef ERTS_SMP
+#ifdef ERTS_ENABLE_LOCK_CHECK
+ ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks(receiver) < ERTS_PROC_LOCK_MSGQ ||
+ receiver_locks == erts_proc_lc_my_proc_locks(receiver));
+#endif
- if (!(*receiver_locks & ERTS_PROC_LOCK_MSGQ)) {
+ if (!(receiver_locks & ERTS_PROC_LOCK_MSGQ)) {
if (erts_smp_proc_trylock(receiver, ERTS_PROC_LOCK_MSGQ) == EBUSY) {
- ErtsProcLocks need_locks = ERTS_PROC_LOCK_MSGQ;
+ ErtsProcLocks need_locks;
if (receiver_state)
state = *receiver_state;
@@ -397,10 +406,11 @@ queue_message(Process *c_p,
if (state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_PENDING_EXIT))
goto exiting;
- if (*receiver_locks & ERTS_PROC_LOCK_STATUS) {
- erts_smp_proc_unlock(receiver, ERTS_PROC_LOCK_STATUS);
- need_locks |= ERTS_PROC_LOCK_STATUS;
+ need_locks = receiver_locks & (ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_TRACE);
+ if (need_locks) {
+ erts_smp_proc_unlock(receiver, need_locks);
}
+ need_locks |= ERTS_PROC_LOCK_MSGQ;
erts_smp_proc_lock(receiver, need_locks);
}
locked_msgq = 1;
@@ -417,19 +427,13 @@ queue_message(Process *c_p,
/* Drop message if receiver is exiting or has a pending exit... */
if (locked_msgq)
erts_smp_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ);
- erts_cleanup_messages(mp);
+ erts_cleanup_messages(first);
return 0;
}
- ERL_MESSAGE_TERM(mp) = message;
- ERL_MESSAGE_TOKEN(mp) = seq_trace_token;
-#ifdef USE_VM_PROBES
- ERL_MESSAGE_DT_UTAG(mp) = dt_utag;
-#endif
-
res = receiver->msg.len;
#ifdef ERTS_SMP
- if (*receiver_locks & ERTS_PROC_LOCK_MAIN) {
+ 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
@@ -440,75 +444,85 @@ queue_message(Process *c_p,
*/
res += receiver->msg_inq.len;
ERTS_SMP_MSGQ_MV_INQ2PRIVQ(receiver);
- LINK_MESSAGE_PRIVQ(receiver, mp);
+ LINK_MESSAGE_PRIVQ(receiver, first, last, len);
}
else
#endif
{
- LINK_MESSAGE(receiver, mp);
+ LINK_MESSAGE(receiver, first, last, len);
}
+ if (IS_TRACED_FL(receiver, F_TRACE_RECEIVE)
+ && (te = &erts_receive_tracing[erts_active_bp_ix()],
+ te->on)) {
+
+ ErtsMessage *msg = first;
+
#ifdef USE_VM_PROBES
- if (DTRACE_ENABLED(message_queued)) {
- DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE);
- Sint tok_label = 0;
- Sint tok_lastcnt = 0;
- Sint tok_serial = 0;
-
- dtrace_proc_str(receiver, receiver_name);
- if (seq_trace_token != NIL && is_tuple(seq_trace_token)) {
- tok_label = signed_val(SEQ_TRACE_T_LABEL(seq_trace_token));
- tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(seq_trace_token));
- tok_serial = signed_val(SEQ_TRACE_T_SERIAL(seq_trace_token));
+ if (DTRACE_ENABLED(message_queued)) {
+ DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE);
+ Sint tok_label = 0;
+ Sint tok_lastcnt = 0;
+ Sint tok_serial = 0;
+ Eterm seq_trace_token = ERL_MESSAGE_TOKEN(msg);
+
+ dtrace_proc_str(receiver, receiver_name);
+ if (seq_trace_token != NIL && is_tuple(seq_trace_token)) {
+ tok_label = signed_val(SEQ_TRACE_T_LABEL(seq_trace_token));
+ tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(seq_trace_token));
+ tok_serial = signed_val(SEQ_TRACE_T_SERIAL(seq_trace_token));
+ }
+ DTRACE6(message_queued,
+ receiver_name, size_object(ERL_MESSAGE_TERM(msg)),
+ receiver->msg.len,
+ tok_label, tok_lastcnt, tok_serial);
}
- DTRACE6(message_queued,
- receiver_name, size_object(message), receiver->msg.len,
- tok_label, tok_lastcnt, tok_serial);
- }
#endif
+ while (msg) {
+ trace_receive(receiver, from, ERL_MESSAGE_TERM(msg), te);
+ msg = msg->next;
+ }
- if (IS_TRACED_FL(receiver, F_TRACE_RECEIVE))
- trace_receive(receiver, message);
-
- if (locked_msgq)
+ }
+ if (locked_msgq) {
erts_smp_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ);
+ }
- erts_proc_notify_new_message(receiver,
#ifdef ERTS_SMP
- *receiver_locks
+ erts_proc_notify_new_message(receiver, receiver_locks);
#else
- 0
-#endif
- );
-
-#ifndef ERTS_SMP
+ erts_proc_notify_new_message(receiver, 0);
ERTS_HOLE_CHECK(receiver);
#endif
return res;
}
-void
-#ifdef USE_VM_PROBES
-erts_queue_message_probe(Process* receiver, ErtsProcLocks *receiver_locks,
- ErtsMessage* mp,
- Eterm message, Eterm seq_trace_token, Eterm dt_utag)
-#else
-erts_queue_message(Process* receiver, ErtsProcLocks *receiver_locks,
- ErtsMessage* mp,
- Eterm message, Eterm seq_trace_token)
-#endif
+static Sint
+queue_message(Process* receiver,
+ erts_aint32_t *receiver_state,
+ ErtsProcLocks receiver_locks,
+ ErtsMessage* mp, Eterm msg, Eterm from)
{
- queue_message(NULL,
- receiver,
- NULL,
- receiver_locks,
- mp,
- message,
- seq_trace_token
-#ifdef USE_VM_PROBES
- , dt_utag
-#endif
- );
+ ERL_MESSAGE_TERM(mp) = msg;
+ return queue_messages(receiver, receiver_state, receiver_locks,
+ mp, &mp->next, 1, from);
+}
+
+Sint
+erts_queue_message(Process* receiver, ErtsProcLocks receiver_locks,
+ ErtsMessage* mp, Eterm msg, Eterm from)
+{
+ return queue_message(receiver, NULL, receiver_locks, mp, msg, from);
+}
+
+
+Sint
+erts_queue_messages(Process* receiver, ErtsProcLocks receiver_locks,
+ ErtsMessage* first, ErtsMessage** last, Uint len,
+ Eterm from)
+{
+ return queue_messages(receiver, NULL, receiver_locks,
+ first, last, len, from);
}
void
@@ -591,7 +605,7 @@ erts_try_alloc_message_on_heap(Process *pp,
#if defined(ERTS_SMP)
*plp & ERTS_PROC_LOCK_MAIN
#else
- 1
+ pp
#endif
) {
#ifdef ERTS_SMP
@@ -621,7 +635,7 @@ erts_try_alloc_message_on_heap(Process *pp,
*on_heap_p = !0;
}
#ifdef ERTS_SMP
- else if (erts_smp_proc_trylock(pp, ERTS_PROC_LOCK_MAIN) == 0) {
+ else if (pp && erts_smp_proc_trylock(pp, ERTS_PROC_LOCK_MAIN) == 0) {
locked_main = 1;
*psp = erts_smp_atomic32_read_nob(&pp->state);
*plp |= ERTS_PROC_LOCK_MAIN;
@@ -766,17 +780,7 @@ erts_send_message(Process* sender,
utag = DT_UTAG(sender);
else
utag = copy_struct(DT_UTAG(sender), dt_utag_size, &hp, ohp);
-#ifdef DTRACE_TAG_HARDDEBUG
- erts_fprintf(stderr,
- "Dtrace -> (%T) Spreading tag (%T) with "
- "message %T!\r\n",sender->common.id, utag, message);
-#endif
}
-#endif
- BM_MESSAGE_COPIED(msize);
- BM_SWAP_TIMER(copy,send);
-
-#ifdef USE_VM_PROBES
if (DTRACE_ENABLED(message_send)) {
if (have_seqtrace(stoken)) {
tok_label = signed_val(SEQ_TRACE_T_LABEL(stoken));
@@ -787,6 +791,9 @@ erts_send_message(Process* sender,
msize, tok_label, tok_lastcnt, tok_serial);
}
#endif
+ BM_MESSAGE_COPIED(msize);
+ BM_SWAP_TIMER(copy,send);
+
} else {
Eterm *hp;
@@ -822,21 +829,21 @@ erts_send_message(Process* sender,
BM_MESSAGE_COPIED(msz);
BM_SWAP_TIMER(copy,send);
}
+#ifdef USE_VM_PROBES
DTRACE6(message_send, sender_name, receiver_name,
msize, tok_label, tok_lastcnt, tok_serial);
+#endif
}
- res = queue_message(sender,
- receiver,
- &receiver_state,
- receiver_locks,
- mp,
- message,
- token
+ ERL_MESSAGE_TOKEN(mp) = token;
#ifdef USE_VM_PROBES
- , utag
+ ERL_MESSAGE_DT_UTAG(mp) = utag;
#endif
- );
+ res = queue_message(receiver,
+ &receiver_state,
+ *receiver_locks,
+ mp, message,
+ sender->common.id);
BM_SWAP_TIMER(send,system);
@@ -892,7 +899,8 @@ erts_deliver_exit_message(Eterm from, Process *to, ErtsProcLocks *to_locksp,
/* the trace token must in this case be updated by the caller */
seq_trace_output(token, save, SEQ_TRACE_SEND, to->common.id, NULL);
temptoken = copy_struct(token, sz_token, &hp, ohp);
- erts_queue_message(to, to_locksp, mp, save, temptoken);
+ ERL_MESSAGE_TOKEN(mp) = temptoken;
+ erts_queue_message(to, *to_locksp, mp, save, am_system);
} else {
sz_from = IS_CONST(from) ? 0 : size_object(from);
#ifdef SHCOPY_SEND
@@ -914,7 +922,7 @@ erts_deliver_exit_message(Eterm from, Process *to, ErtsProcLocks *to_locksp,
? from
: copy_struct(from, sz_from, &hp, ohp));
save = TUPLE3(hp, am_EXIT, from_copy, mess);
- erts_queue_message(to, to_locksp, mp, save, NIL);
+ erts_queue_message(to, *to_locksp, mp, save, am_system);
}
}
@@ -1489,7 +1497,7 @@ erts_factory_message_create(ErtsHeapFactory* factory,
int on_heap;
erts_aint32_t state;
- state = erts_smp_atomic32_read_nob(&proc->state);
+ state = proc ? erts_smp_atomic32_read_nob(&proc->state) : 0;
if (state & ERTS_PSFLG_OFF_HEAP_MSGQ) {
msgp = erts_alloc_message(sz, &hp);
diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h
index 60035d15ae..851ac37fda 100644
--- a/erts/emulator/beam/erl_message.h
+++ b/erts/emulator/beam/erl_message.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2012. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
@@ -182,48 +182,64 @@ typedef struct {
Sint len; /* queue length */
} ErlMessageInQueue;
+typedef struct erl_trace_message_queue__ {
+ struct erl_trace_message_queue__ *next; /* point to the next receiver */
+ Eterm receiver;
+ ErtsMessage* first;
+ ErtsMessage** last; /* point to the last next pointer */
+ Sint len; /* queue length */
+} ErlTraceMessageQueue;
+
#endif
/* Get "current" message */
#define PEEK_MESSAGE(p) (*(p)->msg.save)
+#ifdef USE_VM_PROBES
+#define LINK_MESSAGE_DTAG(mp, dt) ERL_MESSAGE_DT_UTAG(mp) = dt
+#else
+#define LINK_MESSAGE_DTAG(mp, dt)
+#endif
-/* Add message last in private message queue */
-#define LINK_MESSAGE_PRIVQ(p, mp) do { \
- *(p)->msg.last = (mp); \
- (p)->msg.last = &(mp)->next; \
- (p)->msg.len++; \
-} while (0)
-
+#define LINK_MESSAGE_IMPL(p, first_msg, last_msg, num_msgs, where) do { \
+ *(p)->where.last = (first_msg); \
+ (p)->where.last = (last_msg); \
+ (p)->where.len += (num_msgs); \
+ } while(0)
#ifdef ERTS_SMP
-/* Move in message queue to end of private message queue */
-#define ERTS_SMP_MSGQ_MV_INQ2PRIVQ(P) \
-do { \
- if ((P)->msg_inq.first) { \
- *(P)->msg.last = (P)->msg_inq.first; \
- (P)->msg.last = (P)->msg_inq.last; \
- (P)->msg.len += (P)->msg_inq.len; \
- (P)->msg_inq.first = NULL; \
- (P)->msg_inq.last = &(P)->msg_inq.first; \
- (P)->msg_inq.len = 0; \
- } \
-} while (0)
-
-/* Add message last in message queue */
-#define LINK_MESSAGE(p, mp) do { \
- *(p)->msg_inq.last = (mp); \
- (p)->msg_inq.last = &(mp)->next; \
- (p)->msg_inq.len++; \
-} while(0)
+/* Add message last in private message queue */
+#define LINK_MESSAGE_PRIVQ(p, first_msg, last_msg, len) \
+ do { \
+ LINK_MESSAGE_IMPL(p, first_msg, last_msg, len, msg); \
+ } while (0)
+
+/* Add message last_msg in message queue */
+#define LINK_MESSAGE(p, first_msg, last_msg, len) \
+ LINK_MESSAGE_IMPL(p, first_msg, last_msg, len, msg_inq)
+
+#define ERTS_SMP_MSGQ_MV_INQ2PRIVQ(p) \
+ do { \
+ if (p->msg_inq.first) { \
+ *p->msg.last = p->msg_inq.first; \
+ p->msg.last = p->msg_inq.last; \
+ p->msg.len += p->msg_inq.len; \
+ p->msg_inq.first = NULL; \
+ p->msg_inq.last = &p->msg_inq.first; \
+ p->msg_inq.len = 0; \
+ } \
+ } while (0)
#else
-#define ERTS_SMP_MSGQ_MV_INQ2PRIVQ(P)
+#define ERTS_SMP_MSGQ_MV_INQ2PRIVQ(p)
-/* Add message last in message queue */
-#define LINK_MESSAGE(p, mp) LINK_MESSAGE_PRIVQ((p), (mp))
+/* Add message last_msg in message queue */
+#define LINK_MESSAGE(p, first_msg, last_msg, len) \
+ do { \
+ LINK_MESSAGE_IMPL(p, first_msg, last_msg, len, msg); \
+ } while(0)
#endif
@@ -259,23 +275,30 @@ do { \
(HEAP_FRAG_P)->off_heap.overhead = 0; \
} while (0)
+#ifdef USE_VM_PROBES
+#define ERL_MESSAGE_DT_UTAG_INIT(MP) ERL_MESSAGE_DT_UTAG(MP) = NIL
+#else
+#define ERL_MESSAGE_DT_UTAG_INIT(MP) do{ } while (0)
+#endif
+
+#define ERTS_INIT_MESSAGE(MP) \
+ do { \
+ (MP)->next = NULL; \
+ ERL_MESSAGE_TERM(MP) = THE_NON_VALUE; \
+ ERL_MESSAGE_TOKEN(MP) = NIL; \
+ ERL_MESSAGE_DT_UTAG_INIT(MP); \
+ MP->data.attached = NULL; \
+ } while (0)
+
void init_message(void);
ErlHeapFragment* new_message_buffer(Uint);
ErlHeapFragment* erts_resize_message_buffer(ErlHeapFragment *, Uint,
Eterm *, Uint);
void free_message_buffer(ErlHeapFragment *);
-void erts_queue_dist_message(Process*, ErtsProcLocks*, ErtsDistExternal *, Eterm);
-#ifdef USE_VM_PROBES
-void erts_queue_message_probe(Process*, ErtsProcLocks*, ErtsMessage*,
- Eterm message, Eterm seq_trace_token, Eterm dt_utag);
-#define erts_queue_message(RP,RL,BP,Msg,SEQ) \
- erts_queue_message_probe((RP),(RL),(BP),(Msg),(SEQ),NIL)
-#else
-void erts_queue_message(Process*, ErtsProcLocks*, ErtsMessage*,
- Eterm message, Eterm seq_trace_token);
-#define erts_queue_message_probe(RP,RL,BP,Msg,SEQ,TAG) \
- erts_queue_message((RP),(RL),(BP),(Msg),(SEQ))
-#endif
+void erts_queue_dist_message(Process*, ErtsProcLocks, ErtsDistExternal *, Eterm, Eterm);
+Sint erts_queue_message(Process*, ErtsProcLocks,ErtsMessage*, Eterm, Eterm);
+Sint erts_queue_messages(Process*, ErtsProcLocks,
+ ErtsMessage*, ErtsMessage**, Uint, Eterm);
void erts_deliver_exit_message(Eterm, Process*, ErtsProcLocks *, Eterm, Eterm);
Sint erts_send_message(Process*, Process*, ErtsProcLocks*, Eterm, unsigned);
void erts_link_mbuf_to_proc(Process *proc, ErlHeapFragment *bp);
@@ -354,9 +377,7 @@ ERTS_GLB_FORCE_INLINE ErtsMessage *erts_alloc_message(Uint sz, Eterm **hpp)
if (sz == 0) {
mp = erts_alloc_message_ref();
- mp->next = NULL;
- ERL_MESSAGE_TERM(mp) = NIL;
- mp->data.attached = NULL;
+ ERTS_INIT_MESSAGE(mp);
if (hpp)
*hpp = NULL;
return mp;
@@ -365,8 +386,7 @@ ERTS_GLB_FORCE_INLINE ErtsMessage *erts_alloc_message(Uint sz, Eterm **hpp)
mp = erts_alloc(ERTS_ALC_T_MSG,
sizeof(ErtsMessage) + (sz - 1)*sizeof(Eterm));
- mp->next = NULL;
- ERL_MESSAGE_TERM(mp) = NIL;
+ ERTS_INIT_MESSAGE(mp);
mp->data.attached = ERTS_MSG_COMBINED_HFRAG;
ERTS_INIT_HEAP_FRAG(&mp->hfrag, sz, sz);
diff --git a/erts/emulator/beam/erl_monitors.c b/erts/emulator/beam/erl_monitors.c
index bd899fa2f9..910598690d 100644
--- a/erts/emulator/beam/erl_monitors.c
+++ b/erts/emulator/beam/erl_monitors.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/beam/erl_monitors.h b/erts/emulator/beam/erl_monitors.h
index 901ed8940b..9e2beedea3 100644
--- a/erts/emulator/beam/erl_monitors.h
+++ b/erts/emulator/beam/erl_monitors.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/beam/erl_msacc.c b/erts/emulator/beam/erl_msacc.c
index 71e3fd8b6e..0e625f213b 100644
--- a/erts/emulator/beam/erl_msacc.c
+++ b/erts/emulator/beam/erl_msacc.c
@@ -257,7 +257,7 @@ static void send_reply(ErtsMsAcc *msacc, ErtsMSAccReq *msaccrp) {
if (msacc->unmanaged) erts_mtx_unlock(&msacc->mtx);
- erts_queue_message(rp, &rp_locks, msgp, msg, NIL);
+ erts_queue_message(rp, rp_locks, msgp, msg, am_system);
if (esdp && msaccrp->req_sched == esdp->no)
rp_locks &= ~ERTS_PROC_LOCK_MAIN;
diff --git a/erts/emulator/beam/erl_mtrace.c b/erts/emulator/beam/erl_mtrace.c
index fdaf02f37a..e275867928 100644
--- a/erts/emulator/beam/erl_mtrace.c
+++ b/erts/emulator/beam/erl_mtrace.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/beam/erl_mtrace.h b/erts/emulator/beam/erl_mtrace.h
index b34eab3c4a..776c70a819 100644
--- a/erts/emulator/beam/erl_mtrace.h
+++ b/erts/emulator/beam/erl_mtrace.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index 8580bc2689..a695a028ba 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2009-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.
@@ -92,11 +92,12 @@ static ERTS_INLINE Eterm* alloc_heap(ErlNifEnv* env, unsigned need)
}
static Eterm* alloc_heap_heavy(ErlNifEnv* env, unsigned need, Eterm* hp)
-{
+{
env->hp = hp;
- if (env->heap_frag == NULL) {
+ if (env->heap_frag == NULL) {
ASSERT(HEAP_LIMIT(env->proc) == env->hp_end);
- HEAP_TOP(env->proc) = env->hp;
+ ASSERT(env->hp + need > env->hp_end);
+ HEAP_TOP(env->proc) = env->hp;
}
else {
env->heap_frag->used_size = hp - env->heap_frag->mem;
@@ -120,7 +121,8 @@ static ERTS_INLINE void ensure_heap(ErlNifEnv* env, unsigned may_need)
}
#endif
-void erts_pre_nif(ErlNifEnv* env, Process* p, struct erl_module_nif* mod_nif)
+void erts_pre_nif(ErlNifEnv* env, Process* p, struct erl_module_nif* mod_nif,
+ Process* tracee)
{
env->mod_nif = mod_nif;
env->proc = p;
@@ -130,17 +132,7 @@ void erts_pre_nif(ErlNifEnv* env, Process* p, struct erl_module_nif* mod_nif)
env->fpe_was_unmasked = erts_block_fpe();
env->tmp_obj_list = NULL;
env->exception_thrown = 0;
-}
-
-static void pre_nif_noproc(ErlNifEnv* env, struct erl_module_nif* mod_nif)
-{
- env->mod_nif = mod_nif;
- env->proc = NULL;
- env->hp = NULL;
- env->hp_end = NULL;
- env->heap_frag = NULL;
- env->fpe_was_unmasked = erts_block_fpe();
- env->tmp_obj_list = NULL;
+ env->tracee = tracee;
}
/* Temporary object header, auto-deallocated when NIF returns
@@ -180,13 +172,6 @@ void erts_post_nif(ErlNifEnv* env)
free_tmp_objs(env);
}
-static void post_nif_noproc(ErlNifEnv* env)
-{
- erts_unblock_fpe(env->fpe_was_unmasked);
- free_tmp_objs(env);
-}
-
-
/* Flush out our cached heap pointers to allow an ordinary HAlloc
*/
static void flush_env(ErlNifEnv* env)
@@ -209,6 +194,7 @@ static void flush_env(ErlNifEnv* env)
*/
static void cache_env(ErlNifEnv* env)
{
+ env->heap_frag = MBUF(env->proc);
if (env->heap_frag == NULL) {
ASSERT(env->hp_end == HEAP_LIMIT(env->proc));
ASSERT(env->hp <= HEAP_TOP(env->proc));
@@ -216,10 +202,6 @@ static void cache_env(ErlNifEnv* env)
env->hp = HEAP_TOP(env->proc);
}
else {
- ASSERT(env->hp_end != HEAP_LIMIT(env->proc));
- ASSERT(env->hp_end - env->hp <= env->heap_frag->alloc_size);
- env->heap_frag = MBUF(env->proc);
- ASSERT(env->heap_frag != NULL);
env->hp = env->heap_frag->mem + env->heap_frag->used_size;
env->hp_end = env->heap_frag->mem + env->heap_frag->alloc_size;
}
@@ -250,18 +232,20 @@ struct enif_msg_environment_t
Process phony_proc;
};
-ErlNifEnv* enif_alloc_env(void)
+static ERTS_INLINE void
+setup_nif_env(struct enif_msg_environment_t* msg_env,
+ struct erl_module_nif* mod,
+ Process* tracee)
{
- struct enif_msg_environment_t* msg_env =
- erts_alloc_fnf(ERTS_ALC_T_NIF, sizeof(struct enif_msg_environment_t));
Eterm* phony_heap = (Eterm*) msg_env; /* dummy non-NULL ptr */
-
- msg_env->env.hp = phony_heap;
+
+ msg_env->env.hp = phony_heap;
msg_env->env.hp_end = phony_heap;
msg_env->env.heap_frag = NULL;
- msg_env->env.mod_nif = NULL;
+ msg_env->env.mod_nif = mod;
msg_env->env.tmp_obj_list = NULL;
msg_env->env.proc = &msg_env->phony_proc;
+ msg_env->env.exception_thrown = 0;
memset(&msg_env->phony_proc, 0, sizeof(Process));
HEAP_START(&msg_env->phony_proc) = phony_heap;
HEAP_TOP(&msg_env->phony_proc) = phony_heap;
@@ -273,6 +257,14 @@ ErlNifEnv* enif_alloc_env(void)
msg_env->phony_proc.space_verified = 0;
msg_env->phony_proc.space_verified_from = NULL;
#endif
+ msg_env->env.tracee = tracee;
+}
+
+ErlNifEnv* enif_alloc_env(void)
+{
+ struct enif_msg_environment_t* msg_env =
+ erts_alloc_fnf(ERTS_ALC_T_NIF, sizeof(struct enif_msg_environment_t));
+ setup_nif_env(msg_env, NULL, NULL);
return &msg_env->env;
}
void enif_free_env(ErlNifEnv* env)
@@ -281,6 +273,20 @@ void enif_free_env(ErlNifEnv* env)
erts_free(ERTS_ALC_T_NIF, env);
}
+static ERTS_INLINE void pre_nif_noproc(struct enif_msg_environment_t* msg_env,
+ struct erl_module_nif* mod,
+ Process* tracee)
+{
+ setup_nif_env(msg_env, mod, tracee);
+ msg_env->env.fpe_was_unmasked = erts_block_fpe();
+}
+
+static ERTS_INLINE void post_nif_noproc(struct enif_msg_environment_t* msg_env)
+{
+ erts_unblock_fpe(msg_env->env.fpe_was_unmasked);
+ enif_clear_env(&msg_env->env);
+}
+
static ERTS_INLINE void clear_offheap(ErlOffHeap* oh)
{
oh->first = NULL;
@@ -307,18 +313,109 @@ void enif_clear_env(ErlNifEnv* env)
ASSERT(!is_offheap(&MSO(p)));
free_tmp_objs(env);
}
-int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid,
- ErlNifEnv* msg_env, ERL_NIF_TERM msg)
+
+#ifdef ERTS_SMP
+#ifdef DEBUG
+static int enif_send_delay = 0;
+#define ERTS_FORCE_ENIF_SEND_DELAY() (enif_send_delay++ % 2 == 0)
+#else
+#ifdef ERTS_PROC_LOCK_OWN_IMPL
+#define ERTS_FORCE_ENIF_SEND_DELAY() 0
+#else
+/*
+ * We always schedule messages if we do not use our own
+ * process lock implementation, as if we try to do a trylock on
+ * a lock that might already be locked by the same thread.
+ * And what happens then with different mutex implementations
+ * is not always guaranteed.
+ */
+#define ERTS_FORCE_ENIF_SEND_DELAY() 1
+#endif
+#endif
+
+int erts_flush_trace_messages(Process *c_p, ErtsProcLocks c_p_locks)
+{
+ ErlTraceMessageQueue *msgq, **last_msgq;
+ int reds = 0;
+
+ erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_TRACE);
+
+ msgq = c_p->trace_msg_q;
+
+ if (!msgq)
+ goto error;
+
+ do {
+ Process* rp;
+ ErtsProcLocks rp_locks;
+ ErtsMessage *first, **last;
+ Uint len;
+
+ first = msgq->first;
+ last = msgq->last;
+ len = msgq->len;
+ msgq->first = NULL;
+ msgq->last = &msgq->first;
+ msgq->len = 0;
+ erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_TRACE);
+
+ ASSERT(len != 0);
+
+ rp = erts_proc_lookup(msgq->receiver);
+ if (rp) {
+ rp_locks = 0;
+ if (rp->common.id == c_p->common.id)
+ rp_locks = c_p_locks;
+ erts_queue_messages(rp, rp_locks, first, last, len, c_p->common.id);
+ if (rp->common.id == c_p->common.id)
+ rp_locks &= ~c_p_locks;
+ if (rp_locks)
+ erts_smp_proc_unlock(rp, rp_locks);
+ reds += len;
+ } else {
+ erts_cleanup_messages(first);
+ }
+ reds += 1;
+ erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_TRACE);
+ msgq = msgq->next;
+ } while (msgq);
+
+ last_msgq = &c_p->trace_msg_q;
+
+ while (*last_msgq) {
+ msgq = *last_msgq;
+ if (msgq->len == 0) {
+ *last_msgq = msgq->next;
+ erts_free(ERTS_ALC_T_TRACE_MSG_QUEUE, msgq);
+ } else {
+ last_msgq = &msgq->next;
+ }
+ }
+
+error:
+ erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_TRACE);
+
+ return reds;
+}
+
+#endif
+
+int
+enif_send(ErlNifEnv* env, const ErlNifPid* to_pid,
+ ErlNifEnv* msg_env, ERL_NIF_TERM msg)
{
struct enif_msg_environment_t* menv = (struct enif_msg_environment_t*)msg_env;
ErtsProcLocks rp_locks = 0;
+#ifdef ERTS_SMP
+ ErtsProcLocks lc_locks = 0;
+#endif
Process* rp;
Process* c_p;
ErtsMessage *mp;
- ErlHeapFragment* frags;
Eterm receiver = to_pid->pid;
int flush_me = 0;
- int scheduler = erts_get_scheduler_id() != 0;
+ ErtsSchedulerData *esdp = erts_get_scheduler_data();
+ int scheduler = esdp ? esdp->no : 0;
if (env != NULL) {
c_p = env->proc;
@@ -333,40 +430,122 @@ int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid,
#else
erts_exit(ERTS_ABORT_EXIT,"enif_send: env==NULL on non-SMP VM");
#endif
- }
+ }
rp = (scheduler
? erts_proc_lookup(receiver)
: erts_pid2proc_opt(c_p, ERTS_PROC_LOCK_MAIN,
receiver, rp_locks, ERTS_P2P_FLG_INC_REFC));
+
if (rp == NULL) {
ASSERT(env == NULL || receiver != c_p->common.id);
return 0;
}
- flush_env(msg_env);
- frags = menv->env.heap_frag;
- ASSERT(frags == MBUF(&menv->phony_proc));
- if (frags != NULL) {
- /* Move all offheap's from phony proc to the first fragment.
- Quick and dirty... */
- ASSERT(!is_offheap(&frags->off_heap));
- frags->off_heap = MSO(&menv->phony_proc);
- clear_offheap(&MSO(&menv->phony_proc));
- menv->env.heap_frag = NULL;
- MBUF(&menv->phony_proc) = NULL;
- }
- ASSERT(!is_offheap(&MSO(&menv->phony_proc)));
-
- if (flush_me) {
- flush_env(env); /* Needed for ERTS_HOLE_CHECK */
- }
- mp = erts_alloc_message(0, NULL);
- mp->data.heap_frag = frags;
- erts_queue_message(rp, &rp_locks, mp, msg, am_undefined);
+ if (menv) {
+ flush_env(msg_env);
+ mp = erts_alloc_message(0, NULL);
+ mp->data.heap_frag = menv->env.heap_frag;
+ ASSERT(mp->data.heap_frag == MBUF(&menv->phony_proc));
+ if (mp->data.heap_frag != NULL) {
+ /* Move all offheap's from phony proc to the first fragment.
+ Quick and dirty... */
+ ASSERT(!is_offheap(&mp->data.heap_frag->off_heap));
+ mp->data.heap_frag->off_heap = MSO(&menv->phony_proc);
+ clear_offheap(&MSO(&menv->phony_proc));
+ menv->env.heap_frag = NULL;
+ MBUF(&menv->phony_proc) = NULL;
+ }
+ } else {
+ Uint sz = size_object(msg);
+ Eterm *hp;
+ mp = erts_alloc_message(sz, &hp);
+ msg = copy_struct(msg, sz, &hp, &mp->hfrag.off_heap);
+ ASSERT(hp == mp->hfrag.mem+mp->hfrag.used_size);
+ }
+
+ ERL_MESSAGE_TERM(mp) = msg;
+
+ if (flush_me) {
+ flush_env(env); /* Needed for ERTS_HOLE_CHECK */
+ }
+
+ if (!env || !env->tracee) {
+
+ if (c_p && IS_TRACED_FL(c_p, F_TRACE_SEND))
+ trace_send(c_p, receiver, msg);
+ }
+#ifdef ERTS_SMP
+ else {
+ /* This clause is taken when the nif is called in the context
+ of a traced process. We do not know which locks we have
+ so we have to do a try lock and if that fails we enqueue
+ the message in a special trace message output queue of the
+ tracee */
+ ErlTraceMessageQueue *msgq;
+ Process *t_p = env->tracee;
+
+
+ erts_smp_proc_lock(t_p, ERTS_PROC_LOCK_TRACE);
+
+ msgq = t_p->trace_msg_q;
+
+ while (msgq != NULL) {
+ if (msgq->receiver == receiver) {
+ break;
+ }
+ msgq = msgq->next;
+ }
+
+#ifdef ERTS_ENABLE_LOCK_CHECK
+ lc_locks = erts_proc_lc_my_proc_locks(rp);
+ rp_locks |= lc_locks;
+#endif
+ if (ERTS_FORCE_ENIF_SEND_DELAY() || msgq ||
+ rp_locks & ERTS_PROC_LOCK_MSGQ ||
+ erts_smp_proc_trylock(rp, ERTS_PROC_LOCK_MSGQ) == EBUSY) {
+
+ if (!msgq) {
+
+ msgq = erts_alloc(ERTS_ALC_T_TRACE_MSG_QUEUE,
+ sizeof(ErlTraceMessageQueue));
+ msgq->receiver = receiver;
+ msgq->first = mp;
+ msgq->last = &mp->next;
+ msgq->len = 1;
+
+ /* Insert in linked list */
+ msgq->next = t_p->trace_msg_q;
+ t_p->trace_msg_q = msgq;
+
+ erts_smp_proc_unlock(t_p, ERTS_PROC_LOCK_TRACE);
+
+ erts_schedule_flush_trace_messages(t_p->common.id);
+
+ } else {
+ msgq->len++;
+ *msgq->last = mp;
+ msgq->last = &mp->next;
+ erts_smp_proc_unlock(t_p, ERTS_PROC_LOCK_TRACE);
+ }
+ goto done;
+ } else {
+ erts_smp_proc_unlock(t_p, ERTS_PROC_LOCK_TRACE);
+ rp_locks &= ~ERTS_PROC_LOCK_TRACE;
+ rp_locks |= ERTS_PROC_LOCK_MSGQ;
+ }
+ }
+#endif /* ERTS_SMP */
+
+ erts_queue_message(rp, rp_locks, mp, msg,
+ c_p ? c_p->common.id : am_undefined);
+
+#ifdef ERTS_SMP
+done:
if (c_p == rp)
rp_locks &= ~ERTS_PROC_LOCK_MAIN;
- if (rp_locks)
- erts_smp_proc_unlock(rp, rp_locks);
+ if (rp_locks & ~lc_locks)
+ erts_smp_proc_unlock(rp, rp_locks & ~lc_locks);
+#endif
if (!scheduler)
erts_proc_dec_refc(rp);
if (flush_me) {
@@ -375,6 +554,32 @@ int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid,
return 1;
}
+int
+enif_port_command(ErlNifEnv *env, const ErlNifPort* to_port,
+ ErlNifEnv *msg_env, ERL_NIF_TERM msg)
+{
+
+ ErtsSchedulerData *esdp = erts_get_scheduler_data();
+ int scheduler = esdp ? esdp->no : 0;
+ Port *prt;
+
+ if (scheduler == 0 || !env)
+ return 0;
+
+ prt = erts_port_lookup(to_port->port_id,
+ (erts_port_synchronous_ops
+ ? ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP
+ : ERTS_PORT_SFLGS_INVALID_LOOKUP));
+
+ if (!prt)
+ return 0;
+
+ if (IS_TRACED_FL(prt, F_TRACE_RECEIVE))
+ trace_port_receive(prt, env->proc->common.id, am_command, msg);
+
+ return erts_port_output_async(prt, env->proc->common.id, msg);
+}
+
ERL_NIF_TERM enif_make_copy(ErlNifEnv* dst_env, ERL_NIF_TERM src_term)
{
Uint sz;
@@ -404,12 +609,28 @@ static int is_offheap(const ErlOffHeap* oh)
ErlNifPid* enif_self(ErlNifEnv* caller_env, ErlNifPid* pid)
{
+ if (caller_env->proc->common.id == ERTS_INVALID_PID)
+ return NULL;
pid->pid = caller_env->proc->common.id;
return pid;
}
+
int enif_get_local_pid(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifPid* pid)
{
- return is_internal_pid(term) ? (pid->pid=term, 1) : 0;
+ if (is_internal_pid(term)) {
+ pid->pid=term;
+ return 1;
+ }
+ return 0;
+}
+
+int enif_get_local_port(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifPort* port)
+{
+ if (is_internal_port(term)) {
+ port->port_id=term;
+ return 1;
+ }
+ return 0;
}
int enif_is_atom(ErlNifEnv* env, ERL_NIF_TERM term)
@@ -622,6 +843,68 @@ unsigned char* enif_make_new_binary(ErlNifEnv* env, size_t size,
return binary_bytes(*termp);
}
+int enif_term_to_binary(ErlNifEnv *dst_env, ERL_NIF_TERM term,
+ ErlNifBinary *bin)
+{
+ Sint size;
+ byte *bp;
+ Binary* refbin;
+
+ size = erts_encode_ext_size(term);
+ if (!enif_alloc_binary(size, bin))
+ return 0;
+
+ refbin = bin->ref_bin;
+
+ bp = bin->data;
+
+ erts_encode_ext(term, &bp);
+
+ bin->size = bp - bin->data;
+ refbin->orig_size = bin->size;
+
+ ASSERT(bin->data + bin->size == bp);
+
+ return 1;
+}
+
+size_t enif_binary_to_term(ErlNifEnv *dst_env,
+ const unsigned char* data,
+ size_t data_sz,
+ ERL_NIF_TERM *term,
+ ErlNifBinaryToTerm opts)
+{
+ Sint size;
+ ErtsHeapFactory factory;
+ byte *bp = (byte*) data;
+
+ ERTS_CT_ASSERT(ERL_NIF_BIN2TERM_SAFE == ERTS_DIST_EXT_BTT_SAFE);
+
+ if (opts & ~ERL_NIF_BIN2TERM_SAFE) {
+ return 0;
+ }
+ if ((size = erts_decode_ext_size(bp, data_sz)) < 0)
+ return 0;
+
+ if (size > 0) {
+ flush_env(dst_env);
+ erts_factory_proc_prealloc_init(&factory, dst_env->proc, size);
+ } else {
+ erts_factory_dummy_init(&factory);
+ }
+
+ *term = erts_decode_ext(&factory, &bp, (Uint32)opts);
+
+ if (is_non_value(*term)) {
+ return 0;
+ }
+ erts_factory_close(&factory);
+ cache_env(dst_env);
+
+ ASSERT(bp > data);
+ return bp - data;
+}
+
int enif_is_identical(Eterm lhs, Eterm rhs)
{
return EQ(lhs,rhs);
@@ -1158,6 +1441,103 @@ int enif_make_reverse_list(ErlNifEnv* env, ERL_NIF_TERM term, ERL_NIF_TERM *list
return 1;
}
+int enif_is_process_alive(ErlNifEnv* env, ErlNifPid *proc)
+{
+ ErtsProcLocks rp_locks = 0; /* We don't need any locks,
+ just to check if it is alive */
+ Eterm target = proc->pid;
+ Process* rp;
+ Process* c_p;
+ int scheduler = erts_get_scheduler_id() != 0;
+
+ if (env != NULL) {
+ c_p = env->proc;
+ if (target == c_p->common.id) {
+ /* We are alive! */
+ return 1;
+ }
+ }
+ else {
+#ifdef ERTS_SMP
+ c_p = NULL;
+#else
+ erts_exit(ERTS_ABORT_EXIT,"enif_is_process_alive: "
+ "env==NULL on non-SMP VM");
+#endif
+ }
+
+ rp = (scheduler
+ ? erts_proc_lookup(target)
+ : erts_pid2proc_opt(c_p, ERTS_PROC_LOCK_MAIN,
+ target, rp_locks, ERTS_P2P_FLG_INC_REFC));
+ if (rp == NULL) {
+ ASSERT(env == NULL || target != c_p->common.id);
+ return 0;
+ } else {
+ if (!scheduler)
+ erts_proc_dec_refc(rp);
+ return 1;
+ }
+}
+
+int enif_is_port_alive(ErlNifEnv *env, ErlNifPort *port)
+{
+ /* only allowed if called from scheduler */
+ if (erts_get_scheduler_id() == 0)
+ erts_exit(ERTS_ABORT_EXIT,"enif_is_port_alive: called from non-scheduler");
+
+ return erts_port_lookup(
+ port->port_id,
+ (erts_port_synchronous_ops
+ ? ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP
+ : ERTS_PORT_SFLGS_INVALID_LOOKUP)) != NULL;
+}
+
+ERL_NIF_TERM
+enif_now_time(ErlNifEnv *env)
+{
+ Uint mega, sec, micro;
+ Eterm *hp;
+ get_now(&mega, &sec, &micro);
+ hp = alloc_heap(env, 4);
+ return TUPLE3(hp, make_small(mega), make_small(sec), make_small(micro));
+}
+
+ERL_NIF_TERM
+enif_cpu_time(ErlNifEnv *env)
+{
+#ifdef HAVE_ERTS_NOW_CPU
+ Uint mega, sec, micro;
+ Eterm *hp;
+ erts_get_now_cpu(&mega, &sec, &micro);
+ hp = alloc_heap(env, 4);
+ return TUPLE3(hp, make_small(mega), make_small(sec), make_small(micro));
+#else
+ return enif_make_badarg(env);
+#endif
+}
+
+ERL_NIF_TERM
+enif_make_unique_integer(ErlNifEnv *env, ErlNifUniqueInteger properties)
+{
+ int monotonic = properties & ERL_NIF_UNIQUE_MONOTONIC;
+ int positive = properties & ERL_NIF_UNIQUE_POSITIVE;
+ Eterm *hp;
+ Uint hsz;
+
+ if (monotonic) {
+ Sint64 raw_unique = erts_raw_get_unique_monotonic_integer();
+ hsz = erts_raw_unique_monotonic_integer_heap_size(raw_unique, positive);
+ hp = alloc_heap(env, hsz);
+ return erts_raw_make_unique_monotonic_integer_value(&hp, raw_unique, positive);
+ } else {
+ Uint64 raw_unique[ERTS_UNIQUE_INT_RAW_VALUES];
+ erts_raw_get_unique_integer(raw_unique);
+ hsz = erts_raw_unique_integer_heap_size(raw_unique, positive);
+ hp = alloc_heap(env, hsz);
+ return erts_raw_make_unique_integer(&hp, raw_unique, positive);
+ }
+}
ErlNifMutex* enif_mutex_create(char *name) { return erl_drv_mutex_create(name); }
void enif_mutex_destroy(ErlNifMutex *mtx) { erl_drv_mutex_destroy(mtx); }
@@ -1284,10 +1664,10 @@ static void close_lib(struct erl_module_nif* lib)
ASSERT(erts_refc_read(&lib->rt_dtor_cnt,0) == 0);
if (lib->entry != NULL && lib->entry->unload != NULL) {
- ErlNifEnv env;
- pre_nif_noproc(&env, lib);
- lib->entry->unload(&env, lib->priv_data);
- post_nif_noproc(&env);
+ struct enif_msg_environment_t msg_env;
+ pre_nif_noproc(&msg_env, lib, NULL);
+ lib->entry->unload(&msg_env.env, lib->priv_data);
+ post_nif_noproc(&msg_env);
}
if (!erts_is_static_nif(lib->handle))
erts_sys_ddll_close(lib->handle);
@@ -1433,10 +1813,10 @@ static void nif_resource_dtor(Binary* bin)
ASSERT(ERTS_MAGIC_BIN_DESTRUCTOR(bin) == &nif_resource_dtor);
if (type->dtor != NULL) {
- ErlNifEnv env;
- pre_nif_noproc(&env, type->owner);
- type->dtor(&env,resource->data);
- post_nif_noproc(&env);
+ struct enif_msg_environment_t msg_env;
+ pre_nif_noproc(&msg_env, type->owner, NULL);
+ type->dtor(&msg_env.env, resource->data);
+ post_nif_noproc(&msg_env);
}
if (erts_refc_dectest(&type->refc, 0) == 0) {
ASSERT(type->next == NULL);
@@ -1653,7 +2033,7 @@ allocate_nif_sched_data(Process* proc, int argc)
ep->exp.addressv[i] = &ep->exp.code[3];
}
ep->exp.code[3] = (BeamInstr) em_call_nif;
- (void) ERTS_PROC_SET_NIF_TRAP_EXPORT(proc, ERTS_PROC_LOCK_MAIN, ep);
+ (void) ERTS_PROC_SET_NIF_TRAP_EXPORT(proc, ep);
return ep;
}
@@ -2064,14 +2444,13 @@ int enif_make_map_remove(ErlNifEnv* env,
Eterm key,
Eterm *map_out)
{
- int res;
if (!is_map(map_in)) {
return 0;
}
flush_env(env);
- res = erts_maps_remove(env->proc, key, map_in, map_out);
+ (void) erts_maps_take(env->proc, key, map_in, map_out, NULL);
cache_env(env);
- return res;
+ return 1;
}
int enif_map_iterator_create(ErlNifEnv *env,
@@ -2402,7 +2781,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
ErlNifEntry* entry = NULL;
ErlNifEnv env;
int i, err, encoding;
- Module* mod;
+ Module* module_p;
Eterm mod_atom;
const Atom* mod_atomp;
Eterm f_atom;
@@ -2412,6 +2791,8 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
int veto;
struct erl_module_nif* lib = NULL;
int reload_warning = 0;
+ struct erl_module_instance* this_mi;
+ struct erl_module_instance* prev_mi;
encoding = erts_get_native_filename_encoding();
if (encoding == ERL_FILENAME_WIN_WCHAR) {
@@ -2445,21 +2826,29 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
ASSERT(caller != NULL);
mod_atom = caller[0];
ASSERT(is_atom(mod_atom));
- mod=erts_get_module(mod_atom, erts_active_code_ix());
- ASSERT(mod != NULL);
+ module_p = erts_get_module(mod_atom, erts_active_code_ix());
+ ASSERT(module_p != NULL);
mod_atomp = atom_tab(atom_val(mod_atom));
init_func = erts_static_nif_get_nif_init((char*)mod_atomp->name, mod_atomp->len);
if (init_func != NULL)
handle = init_func;
- if (!in_area(caller, mod->curr.code_hdr, mod->curr.code_length)) {
- ASSERT(in_area(caller, mod->old.code_hdr, mod->old.code_length));
+ if (in_area(caller, module_p->old.code_hdr, module_p->old.code_length)) {
+ if (module_p->old.code_hdr->on_load_function_ptr) {
+ this_mi = &module_p->old;
+ prev_mi = &module_p->curr;
+ } else {
+ ret = load_nif_error(BIF_P, "old_code", "Calling load_nif from old "
+ "module '%T' not allowed", mod_atom);
+ goto error;
+ }
+ } else {
+ this_mi = &module_p->curr;
+ prev_mi = &module_p->old;
+ }
- ret = load_nif_error(BIF_P, "old_code", "Calling load_nif from old "
- "module '%T' not allowed", mod_atom);
- }
- else if (init_func == NULL &&
+ if (init_func == NULL &&
(err=erts_sys_ddll_open(lib_name, &handle, &errdesc)) != ERL_DE_NO_ERROR) {
const char slogan[] = "Failed to load NIF library";
if (strstr(errdesc.str, lib_name) != NULL) {
@@ -2508,7 +2897,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
for (i=0; i < entry->num_of_funcs && ret==am_ok; i++) {
BeamInstr** code_pp;
if (!erts_atom_get(f->name, sys_strlen(f->name), &f_atom, ERTS_ATOM_ENC_LATIN1)
- || (code_pp = get_func_pp(mod->curr.code_hdr, f_atom, f->arity))==NULL) {
+ || (code_pp = get_func_pp(this_mi->code_hdr, f_atom, f->arity))==NULL) {
ret = load_nif_error(BIF_P,bad_lib,"Function not found %T:%s/%u",
mod_atom, f->name, f->arity);
}
@@ -2559,9 +2948,9 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
erts_refc_init(&lib->rt_cnt, 0);
erts_refc_init(&lib->rt_dtor_cnt, 0);
ASSERT(opened_rt_list == NULL);
- lib->mod = mod;
+ lib->mod = module_p;
env.mod_nif = lib;
- if (mod->curr.nif != NULL) { /*************** Reload ******************/
+ if (this_mi->nif != NULL) { /*************** Reload ******************/
/*
* Repeated load_nif calls from same Erlang module instance ("reload")
* is deprecated and was only ment as a development feature not to
@@ -2569,16 +2958,16 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
*/
int k, old_incr = 0;
ErlNifFunc* old_func;
- lib->priv_data = mod->curr.nif->priv_data;
+ lib->priv_data = this_mi->nif->priv_data;
- ASSERT(mod->curr.nif->entry != NULL);
+ ASSERT(this_mi->nif->entry != NULL);
if (entry->reload == NULL) {
ret = load_nif_error(BIF_P,reload,"Reload not supported by this NIF library.");
goto error;
}
/* Check that no NIF is removed */
- old_func = mod->curr.nif->entry->funcs;
- for (k=0; k < mod->curr.nif->entry->num_of_funcs; k++) {
+ old_func = this_mi->nif->entry->funcs;
+ for (k=0; k < this_mi->nif->entry->num_of_funcs; k++) {
int incr = 0;
ErlNifFunc* f = entry->funcs;
for (i=0; i < entry->num_of_funcs; i++) {
@@ -2594,9 +2983,9 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
old_func->name, old_func->arity);
goto error;
}
- old_func = next_func(mod->curr.nif->entry, &old_incr, old_func);
+ old_func = next_func(this_mi->nif->entry, &old_incr, old_func);
}
- erts_pre_nif(&env, BIF_P, lib);
+ erts_pre_nif(&env, BIF_P, lib, NULL);
veto = entry->reload(&env, &lib->priv_data, BIF_ARG_2);
erts_post_nif(&env);
if (veto) {
@@ -2604,31 +2993,31 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
}
else {
commit_opened_resource_types(lib);
- mod->curr.nif->entry = NULL; /* to prevent 'unload' callback */
- erts_unload_nif(mod->curr.nif);
+ this_mi->nif->entry = NULL; /* to prevent 'unload' callback */
+ erts_unload_nif(this_mi->nif);
reload_warning = 1;
}
}
else {
lib->priv_data = NULL;
- if (mod->old.nif != NULL) { /**************** Upgrade ***************/
- void* prev_old_data = mod->old.nif->priv_data;
+ if (prev_mi->nif != NULL) { /**************** Upgrade ***************/
+ void* prev_old_data = prev_mi->nif->priv_data;
if (entry->upgrade == NULL) {
ret = load_nif_error(BIF_P, upgrade, "Upgrade not supported by this NIF library.");
goto error;
}
- erts_pre_nif(&env, BIF_P, lib);
- veto = entry->upgrade(&env, &lib->priv_data, &mod->old.nif->priv_data, BIF_ARG_2);
+ erts_pre_nif(&env, BIF_P, lib, NULL);
+ veto = entry->upgrade(&env, &lib->priv_data, &prev_mi->nif->priv_data, BIF_ARG_2);
erts_post_nif(&env);
if (veto) {
- mod->old.nif->priv_data = prev_old_data;
+ prev_mi->nif->priv_data = prev_old_data;
ret = load_nif_error(BIF_P, upgrade, "Library upgrade-call unsuccessful.");
}
else
commit_opened_resource_types(lib);
}
else if (entry->load != NULL) { /********* Initial load ***********/
- erts_pre_nif(&env, BIF_P, lib);
+ erts_pre_nif(&env, BIF_P, lib, NULL);
veto = entry->load(&env, &lib->priv_data, BIF_ARG_2);
erts_post_nif(&env);
if (veto) {
@@ -2646,12 +3035,12 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
int incr = 0;
ErlNifFunc* f = entry->funcs;
- mod->curr.nif = lib;
+ this_mi->nif = lib;
for (i=0; i < entry->num_of_funcs; i++)
{
BeamInstr* code_ptr;
erts_atom_get(f->name, sys_strlen(f->name), &f_atom, ERTS_ATOM_ENC_LATIN1);
- code_ptr = *get_func_pp(mod->curr.code_hdr, f_atom, f->arity);
+ code_ptr = *get_func_pp(this_mi->code_hdr, f_atom, f->arity);
if (code_ptr[1] == 0) {
code_ptr[5+0] = (BeamInstr) BeamOp(op_call_nif);
@@ -2715,6 +3104,9 @@ erts_unload_nif(struct erl_module_nif* lib)
ASSERT(erts_smp_thr_progress_is_blocking());
ASSERT(lib != NULL);
ASSERT(lib->mod != NULL);
+
+ erts_tracer_nif_clear();
+
for (rt = resource_type_list.next;
rt != &resource_type_list;
rt = next) {
@@ -2757,6 +3149,76 @@ void erl_nif_init()
resource_type_list.owner = NULL;
resource_type_list.module = THE_NON_VALUE;
resource_type_list.name = THE_NON_VALUE;
+
+}
+
+int erts_nif_get_funcs(struct erl_module_nif* mod,
+ ErlNifFunc **funcs)
+{
+ *funcs = mod->entry->funcs;
+ return mod->entry->num_of_funcs;
+}
+
+Eterm erts_nif_call_function(Process *p, Process *tracee,
+ struct erl_module_nif* mod,
+ ErlNifFunc *fun, int argc, Eterm *argv)
+{
+ Eterm nif_result;
+#ifdef DEBUG
+ /* Verify that function is part of this module */
+ int i;
+ for (i = 0; i < mod->entry->num_of_funcs; i++)
+ if (fun == &(mod->entry->funcs[i]))
+ break;
+ ASSERT(i < mod->entry->num_of_funcs);
+ if (p)
+ ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks(p) & ERTS_PROC_LOCK_MAIN
+ || erts_smp_thr_progress_is_blocking());
+#endif
+ if (p) {
+ /* This is almost a normal nif call like in beam_emu,
+ except that any heap fragment created in the nif will be
+ discarded without checking if anything in it is live.
+ This is because we cannot do a GC here as we don't know
+ the number of live registers that have to be preserved.
+ This means that any heap part of the returned term may
+ not be used outside this function. */
+ struct enif_environment_t env;
+ ErlHeapFragment *orig_hf = MBUF(p);
+ ErlOffHeap orig_oh = MSO(p);
+ ASSERT(is_internal_pid(p->common.id));
+ MBUF(p) = NULL;
+ clear_offheap(&MSO(p));
+
+ erts_pre_nif(&env, p, mod, tracee);
+ nif_result = (*fun->fptr)(&env, argc, argv);
+ if (env.exception_thrown)
+ nif_result = THE_NON_VALUE;
+ erts_post_nif(&env);
+
+ /* Free any offheap and heap fragments created in nif */
+ if (MSO(p).first) {
+ erts_cleanup_offheap(&MSO(p));
+ clear_offheap(&MSO(p));
+ }
+ if (MBUF(p))
+ free_message_buffer(MBUF(p));
+
+ /* restore original heap fragment list */
+ MBUF(p) = orig_hf;
+ MSO(p) = orig_oh;
+ } else {
+ /* Nif call was done without a process context,
+ so we create a phony one. */
+ struct enif_msg_environment_t msg_env;
+ pre_nif_noproc(&msg_env, mod, tracee);
+ nif_result = (*fun->fptr)(&msg_env.env, argc, argv);
+ if (msg_env.env.exception_thrown)
+ nif_result = THE_NON_VALUE;
+ post_nif_noproc(&msg_env);
+ }
+
+ return nif_result;
}
#ifdef USE_VM_PROBES
diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h
index c9c8b1d0af..3964f7f679 100644
--- a/erts/emulator/beam/erl_nif.h
+++ b/erts/emulator/beam/erl_nif.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2009-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.
@@ -87,16 +87,16 @@ typedef ErlNifSInt64 ErlNifTime;
#define ERL_NIF_TIME_ERROR ((ErlNifSInt64) ERTS_NAPI_TIME_ERROR__)
typedef enum {
- ERL_NIF_SEC = ERTS_NAPI_SEC__,
- ERL_NIF_MSEC = ERTS_NAPI_MSEC__,
- ERL_NIF_USEC = ERTS_NAPI_USEC__,
- ERL_NIF_NSEC = ERTS_NAPI_NSEC__
+ ERL_NIF_SEC = ERTS_NAPI_SEC__,
+ ERL_NIF_MSEC = ERTS_NAPI_MSEC__,
+ ERL_NIF_USEC = ERTS_NAPI_USEC__,
+ ERL_NIF_NSEC = ERTS_NAPI_NSEC__
} ErlNifTimeUnit;
struct enif_environment_t;
typedef struct enif_environment_t ErlNifEnv;
-typedef struct
+typedef struct enif_func_t
{
const char* name;
unsigned arity;
@@ -150,7 +150,12 @@ typedef enum
typedef struct
{
ERL_NIF_TERM pid; /* internal, may change */
-}ErlNifPid;
+} ErlNifPid;
+
+typedef struct
+{
+ ERL_NIF_TERM port_id; /* internal, may change */
+}ErlNifPort;
typedef ErlDrvSysInfo ErlNifSysInfo;
@@ -197,6 +202,15 @@ typedef enum {
ERL_NIF_MAP_ITERATOR_TAIL = ERL_NIF_MAP_ITERATOR_LAST
} ErlNifMapIteratorEntry;
+typedef enum {
+ ERL_NIF_UNIQUE_POSITIVE = (1 << 0),
+ ERL_NIF_UNIQUE_MONOTONIC = (1 << 1)
+} ErlNifUniqueInteger;
+
+typedef enum {
+ ERL_NIF_BIN2TERM_SAFE = 0x20000000
+} ErlNifBinaryToTerm;
+
#if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_))
# define ERL_NIF_API_FUNC_DECL(RET_TYPE, NAME, ARGS) RET_TYPE (*NAME) ARGS
typedef struct {
diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h
index 1448a508a2..a5acd86551 100644
--- a/erts/emulator/beam/erl_nif_api_funcs.h
+++ b/erts/emulator/beam/erl_nif_api_funcs.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2009-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.
@@ -163,6 +163,15 @@ ERL_NIF_API_FUNC_DECL(int,enif_getenv,(const char* key, char* value, size_t* val
ERL_NIF_API_FUNC_DECL(ErlNifTime, enif_monotonic_time, (ErlNifTimeUnit));
ERL_NIF_API_FUNC_DECL(ErlNifTime, enif_time_offset, (ErlNifTimeUnit));
ERL_NIF_API_FUNC_DECL(ErlNifTime, enif_convert_time_unit, (ErlNifTime, ErlNifTimeUnit, ErlNifTimeUnit));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM, enif_now_time, (ErlNifEnv *env));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM, enif_cpu_time, (ErlNifEnv *env));
+ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM, enif_make_unique_integer, (ErlNifEnv *env, ErlNifUniqueInteger properties));
+ERL_NIF_API_FUNC_DECL(int, enif_is_process_alive, (ErlNifEnv *env, ErlNifPid *pid));
+ERL_NIF_API_FUNC_DECL(int, enif_is_port_alive, (ErlNifEnv *env, ErlNifPort *port_id));
+ERL_NIF_API_FUNC_DECL(int, enif_get_local_port, (ErlNifEnv* env, ERL_NIF_TERM, ErlNifPort* port_id));
+ERL_NIF_API_FUNC_DECL(int, enif_term_to_binary, (ErlNifEnv *env, ERL_NIF_TERM term, ErlNifBinary *bin));
+ERL_NIF_API_FUNC_DECL(size_t, enif_binary_to_term, (ErlNifEnv *env, const unsigned char* data, size_t sz, ERL_NIF_TERM *term, unsigned int opts));
+ERL_NIF_API_FUNC_DECL(int, enif_port_command, (ErlNifEnv *env, const ErlNifPort* to_port, ErlNifEnv *msg_env, ERL_NIF_TERM msg));
/*
** ADD NEW ENTRIES HERE (before this comment) !!!
@@ -318,6 +327,15 @@ ERL_NIF_API_FUNC_DECL(int,enif_is_on_dirty_scheduler,(ErlNifEnv*));
# define enif_monotonic_time ERL_NIF_API_FUNC_MACRO(enif_monotonic_time)
# define enif_time_offset ERL_NIF_API_FUNC_MACRO(enif_time_offset)
# define enif_convert_time_unit ERL_NIF_API_FUNC_MACRO(enif_convert_time_unit)
+# define enif_now_time ERL_NIF_API_FUNC_MACRO(enif_now_time)
+# define enif_cpu_time ERL_NIF_API_FUNC_MACRO(enif_cpu_time)
+# define enif_make_unique_integer ERL_NIF_API_FUNC_MACRO(enif_make_unique_integer)
+# define enif_is_process_alive ERL_NIF_API_FUNC_MACRO(enif_is_process_alive)
+# define enif_is_port_alive ERL_NIF_API_FUNC_MACRO(enif_is_port_alive)
+# define enif_get_local_port ERL_NIF_API_FUNC_MACRO(enif_get_local_port)
+# define enif_term_to_binary ERL_NIF_API_FUNC_MACRO(enif_term_to_binary)
+# define enif_binary_to_term ERL_NIF_API_FUNC_MACRO(enif_binary_to_term)
+# define enif_port_command ERL_NIF_API_FUNC_MACRO(enif_port_command)
/*
** ADD NEW ENTRIES HERE (before this comment)
diff --git a/erts/emulator/beam/erl_node_container_utils.h b/erts/emulator/beam/erl_node_container_utils.h
index b6a3531e28..0c76c6fe7d 100644
--- a/erts/emulator/beam/erl_node_container_utils.h
+++ b/erts/emulator/beam/erl_node_container_utils.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c
index 8617f42d7b..646f786651 100644
--- a/erts/emulator/beam/erl_node_tables.c
+++ b/erts/emulator/beam/erl_node_tables.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
@@ -497,31 +497,7 @@ node_table_hash(void *venp)
Uint32 cre = ((ErlNode *) venp)->creation;
HashValue h = atom_tab(atom_val(((ErlNode *) venp)->sysname))->slot.bucket.hvalue;
- h *= PRIME0;
- h += cre & 0xff;
-
-#if MAX_CREATION >= (1 << 8)
- h *= PRIME1;
- h += (cre >> 8) & 0xff;
-#endif
-
-#if MAX_CREATION >= (1 << 16)
- h *= PRIME2;
- h += (cre >> 16) & 0xff;
-#endif
-
-#if MAX_CREATION >= (1 << 24)
- h *= PRIME3;
- h += (cre >> 24) & 0xff;
-#endif
-
-#if 0
-/* XXX Problems in older versions of GCC */
- #if MAX_CREATION >= (1UL << 32)
- #error "MAX_CREATION larger than size of expected creation storage (Uint32)"
- #endif
-#endif
- return h;
+ return (h + cre) * PRIME0;
}
static int
@@ -599,7 +575,7 @@ erts_node_table_info(int to, void *to_arg)
}
-ErlNode *erts_find_or_insert_node(Eterm sysname, Uint creation)
+ErlNode *erts_find_or_insert_node(Eterm sysname, Uint32 creation)
{
ErlNode *res;
ErlNode ne;
diff --git a/erts/emulator/beam/erl_node_tables.h b/erts/emulator/beam/erl_node_tables.h
index fb2f2a5407..7a4434acbf 100644
--- a/erts/emulator/beam/erl_node_tables.h
+++ b/erts/emulator/beam/erl_node_tables.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
@@ -182,7 +182,7 @@ Uint erts_dist_table_size(void);
void erts_dist_table_info(int, void *);
void erts_set_dist_entry_not_connected(DistEntry *);
void erts_set_dist_entry_connected(DistEntry *, Eterm, Uint);
-ErlNode *erts_find_or_insert_node(Eterm, Uint);
+ErlNode *erts_find_or_insert_node(Eterm, Uint32);
void erts_schedule_delete_node(ErlNode *);
void erts_set_this_node(Eterm, Uint);
Uint erts_node_table_size(void);
diff --git a/erts/emulator/beam/erl_port.h b/erts/emulator/beam/erl_port.h
index fa97707a87..c2588e718d 100644
--- a/erts/emulator/beam/erl_port.h
+++ b/erts/emulator/beam/erl_port.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2012-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2012-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.
@@ -185,7 +185,7 @@ struct _erl_drv_port {
int control_flags; /* Flags for port_control() */
ErlDrvPDL port_data_lock;
- ErtsPrtSD *psd; /* Port specific data */
+ erts_smp_atomic_t psd; /* Port specific data */
int reds; /* Only used while executing driver callbacks */
struct {
@@ -252,22 +252,51 @@ ERTS_GLB_INLINE void *erts_prtsd_set(Port *p, int ix, void *new);
ERTS_GLB_INLINE void *
erts_prtsd_get(Port *prt, int ix)
{
- return prt->psd ? prt->psd->data[ix] : NULL;
+ ErtsPrtSD *psd = (ErtsPrtSD *) erts_smp_atomic_read_nob(&prt->psd);
+ if (!psd)
+ return NULL;
+ ERTS_SMP_DATA_DEPENDENCY_READ_MEMORY_BARRIER;
+ return psd->data[ix];
}
ERTS_GLB_INLINE void *
erts_prtsd_set(Port *prt, int ix, void *data)
{
- if (prt->psd) {
- void *old = prt->psd->data[ix];
- prt->psd->data[ix] = data;
+ ErtsPrtSD *psd, *new_psd;
+ void *old;
+ int i;
+
+ psd = (ErtsPrtSD *) erts_smp_atomic_read_nob(&prt->psd);
+
+ if (psd) {
+#ifdef ERTS_SMP
+#ifdef ETHR_ORDERED_READ_DEPEND
+ ETHR_MEMBAR(ETHR_LoadStore|ETHR_StoreStore);
+#else
+ ETHR_MEMBAR(ETHR_LoadLoad|ETHR_LoadStore|ETHR_StoreStore);
+#endif
+#endif
+ old = psd->data[ix];
+ psd->data[ix] = data;
return old;
}
- else {
- prt->psd = erts_alloc(ERTS_ALC_T_PRTSD, sizeof(ErtsPrtSD));
- prt->psd->data[ix] = data;
+
+ if (!data)
return NULL;
- }
+
+ new_psd = erts_alloc(ERTS_ALC_T_PRTSD, sizeof(ErtsPrtSD));
+ for (i = 0; i < ERTS_PRTSD_SIZE; i++)
+ new_psd->data[i] = NULL;
+ psd = (ErtsPrtSD *) erts_smp_atomic_cmpxchg_mb(&prt->psd,
+ (erts_aint_t) new_psd,
+ (erts_aint_t) NULL);
+ if (psd)
+ erts_free(ERTS_ALC_T_PRTSD, new_psd);
+ else
+ psd = new_psd;
+ old = psd->data[ix];
+ psd->data[ix] = data;
+ return old;
}
#endif
@@ -915,7 +944,7 @@ erts_schedule_proc2port_signal(Process *,
ErtsPortTaskHandle *,
ErtsProc2PortSigCallback);
-int erts_deliver_port_exit(Port *, Eterm, Eterm, int);
+int erts_deliver_port_exit(Port *, Eterm, Eterm, int, int);
/*
* Port signal flags
@@ -949,6 +978,8 @@ ErtsPortOpResult erts_port_control(Process *, Port *, unsigned int, Eterm, Eterm
ErtsPortOpResult erts_port_call(Process *, Port *, unsigned int, Eterm, Eterm *);
ErtsPortOpResult erts_port_info(Process *, Port *, Eterm, Eterm *);
+int erts_port_output_async(Port *, Eterm, Eterm);
+
/*
* Signals from ports to ports. Used by sys drivers.
*/
diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c
index e85395e062..3102e44c11 100644
--- a/erts/emulator/beam/erl_port_task.c
+++ b/erts/emulator/beam/erl_port_task.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
@@ -35,6 +35,7 @@
#include "dist.h"
#include "erl_check_io.h"
#include "dtrace-wrapper.h"
+#include "lttng-wrapper.h"
#include <stdarg.h>
/*
@@ -69,6 +70,18 @@ static void chk_task_queues(Port *pp, ErtsPortTask *execq, int processing_busy_q
#else
#define DTRACE_DRIVER(PROBE_NAME, PP) do {} while(0)
#endif
+#ifdef USE_LTTNG_VM_TRACEPOINTS
+#define LTTNG_DRIVER(TRACEPOINT, PP) \
+ if (LTTNG_ENABLED(TRACEPOINT)) { \
+ lttng_decl_portbuf(port_str); \
+ lttng_decl_procbuf(proc_str); \
+ lttng_pid_to_str(ERTS_PORT_GET_CONNECTED(PP), proc_str); \
+ lttng_port_to_str((PP), port_str); \
+ LTTNG3(TRACEPOINT, proc_str, port_str, (PP)->name); \
+ }
+#else
+#define LTTNG_DRIVER(TRACEPOINT, PP) do {} while(0)
+#endif
#define ERTS_SMP_LC_VERIFY_RQ(RQ, PP) \
do { \
@@ -180,10 +193,9 @@ p2p_sig_data_to_task(ErtsProc2PortSigData *sigdp)
return ptp;
}
-ErtsProc2PortSigData *
-erts_port_task_alloc_p2p_sig_data(void)
+static ERTS_INLINE ErtsProc2PortSigData *
+p2p_sig_data_init(ErtsPortTask *ptp)
{
- ErtsPortTask *ptp = port_task_alloc();
ptp->type = ERTS_PORT_TASK_PROC_SIG;
ptp->u.alive.flags = ERTS_PT_FLG_SIG_DEP;
@@ -194,6 +206,31 @@ erts_port_task_alloc_p2p_sig_data(void)
return &ptp->u.alive.td.psig.data;
}
+ErtsProc2PortSigData *
+erts_port_task_alloc_p2p_sig_data(void)
+{
+ ErtsPortTask *ptp = port_task_alloc();
+
+ return p2p_sig_data_init(ptp);
+}
+
+ErtsProc2PortSigData *
+erts_port_task_alloc_p2p_sig_data_extra(size_t extra, void **extra_ptr)
+{
+ ErtsPortTask *ptp = erts_alloc(ERTS_ALC_T_PORT_TASK,
+ sizeof(ErtsPortTask) + extra);
+
+ *extra_ptr = ptp+1;
+
+ return p2p_sig_data_init(ptp);
+}
+
+void
+erts_port_task_free_p2p_sig_data(ErtsProc2PortSigData *sigdp)
+{
+ schedule_port_task_free(p2p_sig_data_to_task(sigdp));
+}
+
static ERTS_INLINE Eterm
task_caller(ErtsPortTask *ptp)
{
@@ -1728,6 +1765,9 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
reds = ERTS_PORT_REDS_TIMEOUT;
if (!(state & ERTS_PORT_SFLGS_DEAD)) {
DTRACE_DRIVER(driver_timeout, pp);
+ LTTNG_DRIVER(driver_timeout, pp);
+ if (IS_TRACED_FL(pp, F_TRACE_RECEIVE))
+ trace_port(pp, am_receive, am_timeout);
(*pp->drv_ptr->timeout)((ErlDrvData) pp->drv_data);
}
}
@@ -1736,6 +1776,7 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
reds = ERTS_PORT_REDS_INPUT;
ASSERT((state & ERTS_PORT_SFLGS_DEAD) == 0);
DTRACE_DRIVER(driver_ready_input, pp);
+ LTTNG_DRIVER(driver_ready_input, pp);
/* NOTE some windows drivers use ->ready_input
for input and output */
(*pp->drv_ptr->ready_input)((ErlDrvData) pp->drv_data,
@@ -1747,6 +1788,7 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
reds = ERTS_PORT_REDS_OUTPUT;
ASSERT((state & ERTS_PORT_SFLGS_DEAD) == 0);
DTRACE_DRIVER(driver_ready_output, pp);
+ LTTNG_DRIVER(driver_ready_output, pp);
(*pp->drv_ptr->ready_output)((ErlDrvData) pp->drv_data,
ptp->u.alive.td.io.event);
reset_executed_io_task_handle(ptp);
@@ -1756,6 +1798,7 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp)
reds = ERTS_PORT_REDS_EVENT;
ASSERT((state & ERTS_PORT_SFLGS_DEAD) == 0);
DTRACE_DRIVER(driver_event, pp);
+ LTTNG_DRIVER(driver_event, pp);
(*pp->drv_ptr->event)((ErlDrvData) pp->drv_data,
ptp->u.alive.td.io.event,
ptp->u.alive.td.io.event_data);
diff --git a/erts/emulator/beam/erl_port_task.h b/erts/emulator/beam/erl_port_task.h
index 335f7a77d5..2a6bd165a3 100644
--- a/erts/emulator/beam/erl_port_task.h
+++ b/erts/emulator/beam/erl_port_task.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
@@ -269,6 +269,8 @@ int erts_port_task_schedule(Eterm,
void erts_port_task_free_port(Port *);
int erts_port_is_scheduled(Port *);
ErtsProc2PortSigData *erts_port_task_alloc_p2p_sig_data(void);
+ErtsProc2PortSigData *erts_port_task_alloc_p2p_sig_data_extra(size_t extra, void **extra_ptr);
+void erts_port_task_free_p2p_sig_data(ErtsProc2PortSigData *sigdp);
#ifdef ERTS_SMP
void erts_enqueue_port(ErtsRunQueue *rq, Port *pp);
diff --git a/erts/emulator/beam/erl_printf_term.c b/erts/emulator/beam/erl_printf_term.c
index 45ba4371dc..1a579704a8 100644
--- a/erts/emulator/beam/erl_printf_term.c
+++ b/erts/emulator/beam/erl_printf_term.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/beam/erl_printf_term.h b/erts/emulator/beam/erl_printf_term.h
index 4618457f27..8a30286fd8 100644
--- a/erts/emulator/beam/erl_printf_term.h
+++ b/erts/emulator/beam/erl_printf_term.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index a706ebf595..36b0af0c1a 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -43,6 +43,7 @@
#include "erl_thr_queue.h"
#include "erl_async.h"
#include "dtrace-wrapper.h"
+#include "lttng-wrapper.h"
#include "erl_ptab.h"
#include "erl_bif_unique.h"
#define ERTS_WANT_TIMER_WHEEL_API
@@ -443,7 +444,8 @@ int erts_system_profile_ts_type = ERTS_TRACE_FLG_NOW_TIMESTAMP;
typedef enum {
ERTS_PSTT_GC, /* Garbage Collect */
ERTS_PSTT_CPC, /* Check Process Code */
- ERTS_PSTT_COHMQ /* Change off heap message queue */
+ ERTS_PSTT_COHMQ, /* Change off heap message queue */
+ ERTS_PSTT_FTMQ /* Flush trace msg queue */
} ErtsProcSysTaskType;
#define ERTS_MAX_PROC_SYS_TASK_ARGS 2
@@ -687,45 +689,36 @@ erts_pre_init_process(void)
= "DEBUG_WAIT_COMPLETED";
#ifdef ERTS_ENABLE_LOCK_CHECK
- {
- int ix;
- erts_psd_required_locks[ERTS_PSD_ERROR_HANDLER].get_locks
- = ERTS_PSD_ERROR_HANDLER_BUF_GET_LOCKS;
- erts_psd_required_locks[ERTS_PSD_ERROR_HANDLER].set_locks
- = ERTS_PSD_ERROR_HANDLER_BUF_SET_LOCKS;
+ erts_psd_required_locks[ERTS_PSD_ERROR_HANDLER].get_locks
+ = ERTS_PSD_ERROR_HANDLER_BUF_GET_LOCKS;
+ erts_psd_required_locks[ERTS_PSD_ERROR_HANDLER].set_locks
+ = ERTS_PSD_ERROR_HANDLER_BUF_SET_LOCKS;
- erts_psd_required_locks[ERTS_PSD_SAVED_CALLS_BUF].get_locks
- = ERTS_PSD_SAVED_CALLS_BUF_GET_LOCKS;
- erts_psd_required_locks[ERTS_PSD_SAVED_CALLS_BUF].set_locks
- = ERTS_PSD_SAVED_CALLS_BUF_SET_LOCKS;
+ erts_psd_required_locks[ERTS_PSD_SAVED_CALLS_BUF].get_locks
+ = ERTS_PSD_SAVED_CALLS_BUF_GET_LOCKS;
+ erts_psd_required_locks[ERTS_PSD_SAVED_CALLS_BUF].set_locks
+ = ERTS_PSD_SAVED_CALLS_BUF_SET_LOCKS;
- erts_psd_required_locks[ERTS_PSD_SCHED_ID].get_locks
- = ERTS_PSD_SCHED_ID_GET_LOCKS;
- erts_psd_required_locks[ERTS_PSD_SCHED_ID].set_locks
- = ERTS_PSD_SCHED_ID_SET_LOCKS;
+ erts_psd_required_locks[ERTS_PSD_SCHED_ID].get_locks
+ = ERTS_PSD_SCHED_ID_GET_LOCKS;
+ erts_psd_required_locks[ERTS_PSD_SCHED_ID].set_locks
+ = ERTS_PSD_SCHED_ID_SET_LOCKS;
- erts_psd_required_locks[ERTS_PSD_CALL_TIME_BP].get_locks
- = ERTS_PSD_CALL_TIME_BP_GET_LOCKS;
- erts_psd_required_locks[ERTS_PSD_CALL_TIME_BP].set_locks
- = ERTS_PSD_CALL_TIME_BP_SET_LOCKS;
+ erts_psd_required_locks[ERTS_PSD_CALL_TIME_BP].get_locks
+ = ERTS_PSD_CALL_TIME_BP_GET_LOCKS;
+ erts_psd_required_locks[ERTS_PSD_CALL_TIME_BP].set_locks
+ = ERTS_PSD_CALL_TIME_BP_SET_LOCKS;
- erts_psd_required_locks[ERTS_PSD_DELAYED_GC_TASK_QS].get_locks
- = ERTS_PSD_DELAYED_GC_TASK_QS_GET_LOCKS;
- erts_psd_required_locks[ERTS_PSD_DELAYED_GC_TASK_QS].set_locks
- = ERTS_PSD_DELAYED_GC_TASK_QS_SET_LOCKS;
+ erts_psd_required_locks[ERTS_PSD_DELAYED_GC_TASK_QS].get_locks
+ = ERTS_PSD_DELAYED_GC_TASK_QS_GET_LOCKS;
+ erts_psd_required_locks[ERTS_PSD_DELAYED_GC_TASK_QS].set_locks
+ = ERTS_PSD_DELAYED_GC_TASK_QS_SET_LOCKS;
- erts_psd_required_locks[ERTS_PSD_NIF_TRAP_EXPORT].get_locks
- = ERTS_PSD_NIF_TRAP_EXPORT_GET_LOCKS;
- erts_psd_required_locks[ERTS_PSD_NIF_TRAP_EXPORT].set_locks
- = ERTS_PSD_NIF_TRAP_EXPORT_SET_LOCKS;
-
- /* Check that we have locks for all entries */
- for (ix = 0; ix < ERTS_PSD_SIZE; ix++) {
- ERTS_SMP_LC_ASSERT(erts_psd_required_locks[ix].get_locks);
- ERTS_SMP_LC_ASSERT(erts_psd_required_locks[ix].set_locks);
- }
- }
+ erts_psd_required_locks[ERTS_PSD_NIF_TRAP_EXPORT].get_locks
+ = ERTS_PSD_NIF_TRAP_EXPORT_GET_LOCKS;
+ erts_psd_required_locks[ERTS_PSD_NIF_TRAP_EXPORT].set_locks
+ = ERTS_PSD_NIF_TRAP_EXPORT_SET_LOCKS;
#endif
}
@@ -1146,7 +1139,7 @@ reply_sched_wall_time(void *vswtrp)
hpp = &hp;
}
- erts_queue_message(rp, &rp_locks, mp, msg, NIL);
+ erts_queue_message(rp, rp_locks, mp, msg, am_system);
if (swtrp->req_sched == esdp->no)
rp_locks &= ~ERTS_PROC_LOCK_MAIN;
@@ -1225,7 +1218,7 @@ reply_system_check(void *vscrp)
hpp = &hp;
msg = STORE_NC(hpp, ohp, scrp->ref);
- erts_queue_message(rp, &rp_locks, mp, msg, NIL);
+ erts_queue_message(rp, rp_locks, mp, msg, am_system);
if (scrp->req_sched == esdp->no)
rp_locks &= ~ERTS_PROC_LOCK_MAIN;
@@ -1314,46 +1307,25 @@ erts_proclist_destroy(ErtsProcList *plp)
}
void *
-erts_psd_set_init(Process *p, ErtsProcLocks plocks, int ix, void *data)
+erts_psd_set_init(Process *p, int ix, void *data)
{
void *old;
- ErtsProcLocks xplocks;
- int refc = 0;
- ErtsPSD *psd = erts_alloc(ERTS_ALC_T_PSD, sizeof(ErtsPSD));
+ ErtsPSD *psd, *new_psd;
int i;
- for (i = 0; i < ERTS_PSD_SIZE; i++)
- psd->data[i] = NULL;
- ERTS_SMP_LC_ASSERT(plocks);
- ERTS_SMP_LC_ASSERT(plocks == erts_proc_lc_my_proc_locks(p));
+ new_psd = erts_alloc(ERTS_ALC_T_PSD, sizeof(ErtsPSD));
+ for (i = 0; i < ERTS_PSD_SIZE; i++)
+ new_psd->data[i] = NULL;
- xplocks = ERTS_PROC_LOCKS_ALL;
- xplocks &= ~plocks;
- if (xplocks && erts_smp_proc_trylock(p, xplocks) == EBUSY) {
- if (xplocks & ERTS_PROC_LOCK_MAIN) {
- erts_proc_inc_refc(p);
- erts_smp_proc_unlock(p, plocks);
- erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL);
- refc = 1;
- }
- else {
- if (plocks & ERTS_PROC_LOCKS_ALL_MINOR)
- erts_smp_proc_unlock(p, plocks & ERTS_PROC_LOCKS_ALL_MINOR);
- erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL_MINOR);
- }
- }
- if (!p->psd)
- p->psd = psd;
- if (xplocks)
- erts_smp_proc_unlock(p, xplocks);
- if (refc)
- erts_proc_dec_refc(p);
- ASSERT(p->psd);
- if (p->psd != psd)
- erts_free(ERTS_ALC_T_PSD, psd);
- old = p->psd->data[ix];
- p->psd->data[ix] = data;
- ERTS_SMP_LC_ASSERT(plocks == erts_proc_lc_my_proc_locks(p));
+ psd = (ErtsPSD *) erts_smp_atomic_cmpxchg_mb(&p->psd,
+ (erts_aint_t) new_psd,
+ (erts_aint_t) NULL);
+ if (psd)
+ erts_free(ERTS_ALC_T_PSD, new_psd);
+ else
+ psd = new_psd;
+ old = psd->data[ix];
+ psd->data[ix] = data;
return old;
}
@@ -2211,8 +2183,7 @@ setup_thr_debug_wait_completed(void *vproc)
if (debug_wait_completed_flags & ERTS_DEBUG_WAIT_COMPLETED_DEALLOCATIONS) {
erts_alloc_fix_alloc_shrink(awdp->sched_id, 0);
wait_flags |= (ERTS_SSI_AUX_WORK_DD
- | ERTS_SSI_AUX_WORK_DD_THR_PRGR
- | ERTS_SSI_AUX_WORK_THR_PRGR_LATER_OP);
+ | ERTS_SSI_AUX_WORK_DD_THR_PRGR);
#ifdef ERTS_SMP
aux_work_flags |= ERTS_SSI_AUX_WORK_DD;
#endif
@@ -2220,8 +2191,7 @@ setup_thr_debug_wait_completed(void *vproc)
if (debug_wait_completed_flags & ERTS_DEBUG_WAIT_COMPLETED_TIMER_CANCELLATIONS) {
wait_flags |= (ERTS_SSI_AUX_WORK_CNCLD_TMRS
- | ERTS_SSI_AUX_WORK_CNCLD_TMRS_THR_PRGR
- | ERTS_SSI_AUX_WORK_THR_PRGR_LATER_OP);
+ | ERTS_SSI_AUX_WORK_CNCLD_TMRS_THR_PRGR);
#ifdef ERTS_SMP
if (awdp->esdp && !ERTS_SCHEDULER_IS_DIRTY(awdp->esdp))
aux_work_flags |= ERTS_SSI_AUX_WORK_CNCLD_TMRS;
@@ -2235,26 +2205,42 @@ setup_thr_debug_wait_completed(void *vproc)
awdp->debug.wait_completed.arg = vproc;
}
-static void
-prep_setup_thr_debug_wait_completed(void *vproc)
+struct debug_lop {
+ ErtsThrPrgrLaterOp lop;
+ Process *proc;
+};
+
+static void later_thr_debug_wait_completed(void *vlop)
{
+ struct debug_lop *lop = vlop;
erts_aint32_t count = (erts_aint32_t) erts_no_schedulers;
#ifdef ERTS_SMP
count += 1; /* aux thread */
#endif
if (erts_atomic32_dec_read_mb(&debug_wait_completed_count) == count) {
- /* scheduler threads */
- erts_schedule_multi_misc_aux_work(0,
- erts_no_schedulers,
- setup_thr_debug_wait_completed,
- vproc);
+ /* scheduler threads */
+ erts_schedule_multi_misc_aux_work(0,
+ erts_no_schedulers,
+ setup_thr_debug_wait_completed,
+ lop->proc);
#ifdef ERTS_SMP
- /* aux_thread */
- erts_schedule_misc_aux_work(0,
- setup_thr_debug_wait_completed,
- vproc);
+ /* aux_thread */
+ erts_schedule_misc_aux_work(0,
+ setup_thr_debug_wait_completed,
+ lop->proc);
#endif
}
+ erts_free(ERTS_ALC_T_DEBUG, lop);
+}
+
+
+static void
+init_thr_debug_wait_completed(void *vproc)
+{
+ struct debug_lop* lop = erts_alloc(ERTS_ALC_T_DEBUG,
+ sizeof(struct debug_lop));
+ lop->proc = vproc;
+ erts_schedule_thr_prgr_later_op(later_thr_debug_wait_completed, lop, &lop->lop);
}
@@ -2264,7 +2250,7 @@ erts_debug_wait_completed(Process *c_p, int flags)
/* Only one process at a time can do this */
erts_aint32_t count = (erts_aint32_t) (2*erts_no_schedulers);
#ifdef ERTS_SMP
- count += 2; /* aux thread */
+ count += 1; /* aux thread */
#endif
if (0 == erts_atomic32_cmpxchg_mb(&debug_wait_completed_count,
count,
@@ -2272,17 +2258,12 @@ erts_debug_wait_completed(Process *c_p, int flags)
debug_wait_completed_flags = flags;
erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL);
erts_proc_inc_refc(c_p);
- /* scheduler threads */
+
+ /* First flush later-ops on all scheduler threads */
erts_schedule_multi_misc_aux_work(0,
erts_no_schedulers,
- prep_setup_thr_debug_wait_completed,
+ init_thr_debug_wait_completed,
(void *) c_p);
-#ifdef ERTS_SMP
- /* aux_thread */
- erts_schedule_misc_aux_work(0,
- prep_setup_thr_debug_wait_completed,
- (void *) c_p);
-#endif
return 1;
}
return 0;
@@ -2331,7 +2312,7 @@ handle_reap_ports(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting)
ERTS_PORT_SFLG_HALT);
erts_smp_atomic32_inc_nob(&erts_halt_progress);
if (!(state & (ERTS_PORT_SFLG_EXITING|ERTS_PORT_SFLG_CLOSING)))
- erts_deliver_port_exit(prt, prt->common.id, am_killed, 0);
+ erts_deliver_port_exit(prt, prt->common.id, am_killed, 0, 1);
}
erts_port_release(prt);
@@ -3238,6 +3219,7 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
ERTS_MSACC_SET_STATE_CACHED_M(ERTS_MSACC_STATE_CHECK_IO);
ASSERT(!erts_port_task_have_outstanding_io_tasks());
+ LTTNG2(scheduler_poll, esdp->no, 1);
erl_sys_schedule(1); /* Might give us something to do */
ERTS_MSACC_POP_STATE_M();
@@ -3361,6 +3343,7 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
ASSERT(!erts_port_task_have_outstanding_io_tasks());
ERTS_MSACC_SET_STATE_CACHED_M(ERTS_MSACC_STATE_CHECK_IO);
+ LTTNG2(scheduler_poll, esdp->no, 0);
erl_sys_schedule(0);
@@ -6705,10 +6688,8 @@ schedule_process_sys_task(Process *p, erts_aint32_t prio, ErtsProcSysTask *st)
erts_aint32_t e;
n = e = a;
- if (a & ERTS_PSFLG_FREE) {
- res = 0;
+ if (a & ERTS_PSFLG_FREE)
goto cleanup; /* We don't want to schedule free processes... */
- }
enqueue = ERTS_ENQUEUE_NOT;
n |= ERTS_PSFLG_ACTIVE_SYS;
@@ -9257,6 +9238,21 @@ erts_set_process_priority(Process *p, Eterm value)
}
}
+static int
+scheduler_gc_proc(Process *c_p, int reds_left)
+{
+ int fcalls, reds;
+ if (!ERTS_PROC_GET_SAVED_CALLS_BUF(c_p))
+ fcalls = reds_left;
+ else
+ fcalls = reds_left - CONTEXT_REDS;
+ reds = erts_garbage_collect_nobump(c_p, 0, c_p->arg_reg, c_p->arity, fcalls);
+ ASSERT(reds_left >= reds);
+ return reds;
+}
+
+
+
/*
* schedule() is called from BEAM (process_main()) or HiPE
* (hipe_mode_switch()) when the current process is to be
@@ -9324,8 +9320,6 @@ Process *schedule(Process *p, int calls)
} else {
sched_out_proc:
- ASSERT(!(p->flags & F_DELAY_GC));
-
#ifdef ERTS_SMP
ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p);
esdp = p->scheduler_data;
@@ -9335,7 +9329,9 @@ Process *schedule(Process *p, int calls)
esdp = erts_scheduler_data;
ASSERT(esdp->current_process == p);
#endif
+
reds = actual_reds = calls - esdp->virtual_reds;
+ ASSERT(actual_reds >= 0);
if (reds < ERTS_PROC_MIN_CONTEXT_SWITCH_REDS_COST)
reds = ERTS_PROC_MIN_CONTEXT_SWITCH_REDS_COST;
esdp->virtual_reds = 0;
@@ -9347,27 +9343,39 @@ Process *schedule(Process *p, int calls)
p->reds += actual_reds;
- erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS);
+#ifdef ERTS_SMP
+ erts_smp_proc_lock(p, ERTS_PROC_LOCK_TRACE);
+ if (p->trace_msg_q) {
+ erts_smp_proc_unlock(p, ERTS_PROC_LOCK_TRACE);
+ erts_schedule_flush_trace_messages(p->common.id);
+ } else
+ erts_smp_proc_unlock(p, ERTS_PROC_LOCK_TRACE);
+#endif
- state = erts_smp_atomic32_read_acqb(&p->state);
+ state = erts_smp_atomic32_read_nob(&p->state);
if (IS_TRACED(p)) {
if (IS_TRACED_FL(p, F_TRACE_CALLS) && !(state & ERTS_PSFLG_FREE))
erts_schedule_time_break(p, ERTS_BP_CALL_TIME_SCHEDULE_OUT);
- if (state & (ERTS_PSFLG_FREE|ERTS_PSFLG_EXITING)) {
+ if ((state & (ERTS_PSFLG_FREE|ERTS_PSFLG_EXITING)) == ERTS_PSFLG_EXITING) {
if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_EXIT))
- trace_sched(p, ((state & ERTS_PSFLG_FREE)
- ? am_out_exited
- : am_out_exiting));
+ trace_sched(p, ERTS_PROC_LOCK_MAIN,
+ ((state & ERTS_PSFLG_FREE)
+ ? am_out_exited
+ : am_out_exiting));
}
else {
- if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED))
- trace_sched(p, am_out);
- else if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_PROCS))
- trace_virtual_sched(p, am_out);
+ if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED) ||
+ ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_PROCS))
+ trace_sched(p, ERTS_PROC_LOCK_MAIN, am_out);
}
}
+ erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS);
+
+ /* have to re-read state after taking lock */
+ state = erts_smp_atomic32_read_nob(&p->state);
+
#ifdef ERTS_SMP
if (state & ERTS_PSFLG_PENDING_EXIT)
erts_handle_pending_exit(p, (ERTS_PROC_LOCK_MAIN
@@ -9581,7 +9589,10 @@ Process *schedule(Process *p, int calls)
erts_sys_schedule_interrupt(0);
#endif
erts_smp_runq_unlock(rq);
- ERTS_MSACC_SET_STATE_CACHED_M(ERTS_MSACC_STATE_CHECK_IO);
+
+ ERTS_MSACC_SET_STATE_CACHED_M(ERTS_MSACC_STATE_CHECK_IO);
+ LTTNG2(scheduler_poll, esdp->no, 1);
+
erl_sys_schedule(1);
ERTS_MSACC_POP_STATE_M();
@@ -9724,12 +9735,14 @@ Process *schedule(Process *p, int calls)
| ERTS_PSFLG_ACTIVE_SYS
| ERTS_PSFLG_DIRTY_ACTIVE_SYS))
== ERTS_PSFLG_SUSPENDED)) {
- if (state & ERTS_PSFLG_FREE)
- erts_proc_dec_refc(p);
if (proxy_p) {
free_proxy_proc(proxy_p);
proxy_p = NULL;
}
+ else if (state & ERTS_PSFLG_FREE) {
+ /* free and not queued by proxy */
+ erts_proc_dec_refc(p);
+ }
goto pick_next_process;
}
state = new;
@@ -9741,7 +9754,7 @@ Process *schedule(Process *p, int calls)
esdp->current_process = p;
-
+ calls = 0;
reds = context_reds;
#ifdef ERTS_SMP
@@ -9789,10 +9802,7 @@ Process *schedule(Process *p, int calls)
if (erts_sched_stat.enabled) {
int prio;
- UWord old = ERTS_PROC_SCHED_ID(p,
- (ERTS_PROC_LOCK_MAIN
- | ERTS_PROC_LOCK_STATUS),
- (UWord) esdp->no);
+ UWord old = ERTS_PROC_SCHED_ID(p, (UWord) esdp->no);
int migrated = old && old != esdp->no;
#ifdef ERTS_DIRTY_SCHEDULERS
@@ -9823,9 +9833,7 @@ Process *schedule(Process *p, int calls)
/* Migrate to dirty scheduler... */
sunlock_sched_out_proc:
erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
- p->fcalls = reds;
goto sched_out_proc;
-
}
}
else {
@@ -9860,41 +9868,49 @@ Process *schedule(Process *p, int calls)
#endif /* ERTS_SMP */
- p->fcalls = reds;
+ erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
if (IS_TRACED(p)) {
if (state & ERTS_PSFLG_EXITING) {
if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_EXIT))
- trace_sched(p, am_in_exiting);
+ trace_sched(p, ERTS_PROC_LOCK_MAIN, am_in_exiting);
}
else {
- if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED))
- trace_sched(p, am_in);
- else if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_PROCS))
- trace_virtual_sched(p, am_in);
+ if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED) ||
+ ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_PROCS))
+ trace_sched(p, ERTS_PROC_LOCK_MAIN, am_in);
}
if (IS_TRACED_FL(p, F_TRACE_CALLS)) {
erts_schedule_time_break(p, ERTS_BP_CALL_TIME_SCHEDULE_IN);
}
}
- erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
#ifdef ERTS_SMP
- if (is_not_nil(ERTS_TRACER_PROC(p)))
- erts_check_my_tracer_proc(p);
+ /* Clears tracer if it has been removed */
+ (void)ERTS_TRACER_PROC_IS_ENABLED(p);
#endif
if (state & ERTS_PSFLG_RUNNING_SYS) {
- reds -= execute_sys_tasks(p, &state, reds);
- if (reds <= 0
+ /*
+ * GC is normally never delayed when a process
+ * is scheduled out, but might be when executing
+ * hand written beam assembly in
+ * prim_eval:'receive'. If GC is delayed we are
+ * not allowed to execute system tasks.
+ */
+ if (!(p->flags & F_DELAY_GC)) {
+ int cost = execute_sys_tasks(p, &state, reds);
+ calls += cost;
+ reds -= cost;
+ if (reds <= 0
#ifdef ERTS_DIRTY_SCHEDULERS
- || ERTS_SCHEDULER_IS_DIRTY(esdp)
- || (state & ERTS_PSFLGS_DIRTY_WORK)
+ || ERTS_SCHEDULER_IS_DIRTY(esdp)
+ || (state & ERTS_PSFLGS_DIRTY_WORK)
#endif
- ) {
- p->fcalls = reds;
- goto sched_out_proc;
+ ) {
+ goto sched_out_proc;
+ }
}
ASSERT(state & ERTS_PSFLG_RUNNING_SYS);
@@ -9905,8 +9921,9 @@ Process *schedule(Process *p, int calls)
if (((state & (ERTS_PSFLG_SUSPENDED
| ERTS_PSFLG_ACTIVE)) != ERTS_PSFLG_ACTIVE)
- && !(state & ERTS_PSFLG_EXITING))
+ && !(state & ERTS_PSFLG_EXITING)) {
goto sched_out_proc;
+ }
n = e = state;
n &= ~ERTS_PSFLG_RUNNING_SYS;
@@ -9924,12 +9941,12 @@ Process *schedule(Process *p, int calls)
}
if (ERTS_IS_GC_DESIRED(p)) {
- if (!(state & ERTS_PSFLG_EXITING) && !(p->flags & F_DISABLE_GC)) {
- reds -= erts_garbage_collect_nobump(p, 0, p->arg_reg, p->arity);
- if (reds <= 0) {
- p->fcalls = reds;
+ if (!(state & ERTS_PSFLG_EXITING) && !(p->flags & (F_DELAY_GC|F_DISABLE_GC))) {
+ int cost = scheduler_gc_proc(p, reds);
+ calls += cost;
+ reds -= cost;
+ if (reds <= 0)
goto sched_out_proc;
- }
}
}
@@ -9937,6 +9954,8 @@ Process *schedule(Process *p, int calls)
free_proxy_proc(proxy_p);
proxy_p = NULL;
}
+
+ p->fcalls = reds;
ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p);
@@ -10005,7 +10024,7 @@ notify_sys_task_executed(Process *c_p, ErtsProcSysTask *st, Eterm st_result)
ASSERT(hp_start + hsz == hp);
#endif
- erts_queue_message(rp, &rp_locks, mp, msg, NIL);
+ erts_queue_message(rp, rp_locks, mp, msg, c_p->common.id);
if (c_p == rp)
rp_locks &= ~ERTS_PROC_LOCK_MAIN;
@@ -10173,8 +10192,7 @@ execute_sys_tasks(Process *c_p, erts_aint32_t *statep, int in_reds)
{
int garbage_collected = 0;
erts_aint32_t state = *statep;
- int max_reds = in_reds;
- int reds = 0;
+ int reds = in_reds;
int qmask = 0;
ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks(c_p) == ERTS_PROC_LOCK_MAIN);
@@ -10202,35 +10220,47 @@ execute_sys_tasks(Process *c_p, erts_aint32_t *statep, int in_reds)
if (c_p->flags & F_DISABLE_GC) {
save_gc_task(c_p, st, st_prio);
st = NULL;
- reds++;
+ reds--;
}
else {
if (!garbage_collected) {
FLAGS(c_p) |= F_NEED_FULLSWEEP;
- reds += erts_garbage_collect_nobump(c_p,
- 0,
- c_p->arg_reg,
- c_p->arity);
+ reds -= scheduler_gc_proc(c_p, reds);
garbage_collected = 1;
}
st_res = am_true;
}
break;
- case ERTS_PSTT_CPC:
+ case ERTS_PSTT_CPC: {
+ int fcalls;
+ int cpc_reds = 0;
+ if (!ERTS_PROC_GET_SAVED_CALLS_BUF(c_p))
+ fcalls = reds;
+ else
+ fcalls = reds - CONTEXT_REDS;
st_res = erts_check_process_code(c_p,
st->arg[0],
unsigned_val(st->arg[1]),
- &reds);
+ &cpc_reds,
+ fcalls);
+ reds -= cpc_reds;
if (is_non_value(st_res)) {
/* Needed gc, but gc was disabled */
save_gc_task(c_p, st, st_prio);
st = NULL;
}
break;
+ }
case ERTS_PSTT_COHMQ:
- reds += erts_complete_off_heap_message_queue_change(c_p);
+ reds -= erts_complete_off_heap_message_queue_change(c_p);
st_res = am_true;
break;
+#ifdef ERTS_SMP
+ case ERTS_PSTT_FTMQ:
+ reds -= erts_flush_trace_messages(c_p, ERTS_PROC_LOCK_MAIN);
+ st_res = am_true;
+ break;
+#endif
default:
ERTS_INTERNAL_ERROR("Invalid process sys task type");
st_res = am_false;
@@ -10240,11 +10270,14 @@ execute_sys_tasks(Process *c_p, erts_aint32_t *statep, int in_reds)
reds += notify_sys_task_executed(c_p, st, st_res);
state = erts_smp_atomic32_read_acqb(&c_p->state);
- } while (qmask && reds < max_reds);
+ } while (qmask && reds > 0);
*statep = state;
- return reds;
+ if (in_reds < reds)
+ return in_reds;
+
+ return in_reds - reds;
}
static int
@@ -10276,6 +10309,12 @@ cleanup_sys_tasks(Process *c_p, erts_aint32_t in_state, int in_reds)
case ERTS_PSTT_COHMQ:
st_res = am_false;
break;
+#ifdef ERTS_SMP
+ case ERTS_PSTT_FTMQ:
+ reds -= erts_flush_trace_messages(c_p, ERTS_PROC_LOCK_MAIN);
+ st_res = am_true;
+ break;
+#endif
default:
ERTS_INTERNAL_ERROR("Invalid process sys task type");
st_res = am_false;
@@ -10411,8 +10450,8 @@ badarg:
BIF_ERROR(BIF_P, BADARG);
}
-void
-erts_schedule_complete_off_heap_message_queue_change(Eterm pid)
+static void
+erts_schedule_generic_sys_task(Eterm pid, ErtsProcSysTaskType type)
{
Process *rp = erts_proc_lookup(pid);
if (rp) {
@@ -10422,7 +10461,7 @@ erts_schedule_complete_off_heap_message_queue_change(Eterm pid)
st = erts_alloc(ERTS_ALC_T_PROC_SYS_TSK,
ERTS_PROC_SYS_TASK_SIZE(0));
- st->type = ERTS_PSTT_COHMQ;
+ st->type = type;
st->requester = NIL;
st->reply_tag = NIL;
st->req_id = NIL;
@@ -10437,6 +10476,18 @@ erts_schedule_complete_off_heap_message_queue_change(Eterm pid)
}
}
+void
+erts_schedule_complete_off_heap_message_queue_change(Eterm pid)
+{
+ erts_schedule_generic_sys_task(pid, ERTS_PSTT_COHMQ);
+}
+
+void
+erts_schedule_flush_trace_messages(Eterm pid)
+{
+ erts_schedule_generic_sys_task(pid, ERTS_PSTT_FTMQ);
+}
+
static void
save_gc_task(Process *c_p, ErtsProcSysTask *st, int prio)
{
@@ -10456,7 +10507,7 @@ save_gc_task(Process *c_p, ErtsProcSysTask *st, int prio)
qs->q[PRIORITY_NORMAL] = NULL;
qs->q[PRIORITY_LOW] = NULL;
qs->q[prio] = st;
- (void) ERTS_PROC_SET_DELAYED_GC_TASK_QS(c_p, ERTS_PROC_LOCK_MAIN, qs);
+ (void) ERTS_PROC_SET_DELAYED_GC_TASK_QS(c_p, qs);
}
else {
if (!qs->q[prio]) {
@@ -10603,7 +10654,7 @@ erts_set_gc_state(Process *c_p, int enable)
erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_STATUS);
- (void) ERTS_PROC_SET_DELAYED_GC_TASK_QS(c_p, ERTS_PROC_LOCK_MAIN, NULL);
+ (void) ERTS_PROC_SET_DELAYED_GC_TASK_QS(c_p, NULL);
if (dgc_tsk_qs)
proc_sys_task_queues_free(dgc_tsk_qs);
@@ -10895,14 +10946,13 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
Eterm res = THE_NON_VALUE;
erts_aint32_t state = 0;
erts_aint32_t prio = (erts_aint32_t) PRIORITY_NORMAL;
+ ErtsProcLocks locks = ERTS_PROC_LOCKS_ALL;
#ifdef SHCOPY_SPAWN
erts_shcopy_t info;
INITIALIZE_SHCOPY(info);
#endif
-#ifdef ERTS_SMP
erts_smp_proc_lock(parent, ERTS_PROC_LOCKS_ALL_MINOR);
-#endif
/*
* Check for errors.
@@ -11071,7 +11121,7 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
: STORE_NC(&p->htop, &p->off_heap, parent->group_leader);
}
- erts_get_default_tracing(&ERTS_TRACE_FLAGS(p), &ERTS_TRACER_PROC(p));
+ erts_get_default_proc_tracing(&ERTS_TRACE_FLAGS(p), &ERTS_TRACER(p));
p->msg.first = NULL;
p->msg.last = &p->msg.first;
@@ -11089,7 +11139,7 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
p->mbuf = NULL;
p->msg_frag = NULL;
p->mbuf_sz = 0;
- p->psd = NULL;
+ erts_smp_atomic_init_nob(&p->psd, (erts_aint_t) NULL);
p->dictionary = NULL;
p->seq_trace_lastcnt = 0;
p->seq_trace_clock = 0;
@@ -11107,21 +11157,60 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
p->last_old_htop = NULL;
#endif
+#ifdef ERTS_SMP
+ p->trace_msg_q = NULL;
+ p->scheduler_data = NULL;
+ p->suspendee = NIL;
+ p->pending_suspenders = NULL;
+ p->pending_exit.reason = THE_NON_VALUE;
+ p->pending_exit.bp = NULL;
+#endif
+
+#if !defined(NO_FPE_SIGNALS) || defined(HIPE)
+ p->fp_exception = 0;
+#endif
+
if (IS_TRACED(parent)) {
if (ERTS_TRACE_FLAGS(parent) & F_TRACE_SOS) {
ERTS_TRACE_FLAGS(p) |= (ERTS_TRACE_FLAGS(parent) & TRACEE_FLAGS);
- ERTS_TRACER_PROC(p) = ERTS_TRACER_PROC(parent);
- }
- if (ARE_TRACE_FLAGS_ON(parent, F_TRACE_PROCS)) {
- trace_proc_spawn(parent, p->common.id, mod, func, args);
+ erts_tracer_replace(&p->common, ERTS_TRACER(parent));
}
- if (ERTS_TRACE_FLAGS(parent) & F_TRACE_SOS1) {
+ if (ERTS_TRACE_FLAGS(parent) & F_TRACE_SOS1) {
/* Overrides TRACE_CHILDREN */
ERTS_TRACE_FLAGS(p) |= (ERTS_TRACE_FLAGS(parent) & TRACEE_FLAGS);
- ERTS_TRACER_PROC(p) = ERTS_TRACER_PROC(parent);
+ erts_tracer_replace(&p->common, ERTS_TRACER(parent));
ERTS_TRACE_FLAGS(p) &= ~(F_TRACE_SOS1 | F_TRACE_SOS);
ERTS_TRACE_FLAGS(parent) &= ~(F_TRACE_SOS1 | F_TRACE_SOS);
}
+ if (so->flags & SPO_LINK && ERTS_TRACE_FLAGS(parent) & (F_TRACE_SOL|F_TRACE_SOL1)) {
+ ERTS_TRACE_FLAGS(p) |= (ERTS_TRACE_FLAGS(parent)&TRACEE_FLAGS);
+ erts_tracer_replace(&p->common, ERTS_TRACER(parent));
+ if (ERTS_TRACE_FLAGS(parent) & F_TRACE_SOL1) {/*maybe override*/
+ ERTS_TRACE_FLAGS(p) &= ~(F_TRACE_SOL1 | F_TRACE_SOL);
+ ERTS_TRACE_FLAGS(parent) &= ~(F_TRACE_SOL1 | F_TRACE_SOL);
+ }
+ }
+ if (ARE_TRACE_FLAGS_ON(parent, F_TRACE_PROCS)) {
+ locks &= ~(ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_TRACE);
+ erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_TRACE);
+ erts_smp_proc_unlock(parent, ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_TRACE);
+ trace_proc_spawn(parent, am_spawn, p->common.id, mod, func, args);
+ if (so->flags & SPO_LINK)
+ trace_proc(parent, locks, parent, am_link, p->common.id);
+ }
+ }
+
+ if (IS_TRACED_FL(p, F_TRACE_PROCS)) {
+ if ((locks & (ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_TRACE))
+ == (ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_TRACE)) {
+ /* This happens when parent was not traced, but child is */
+ locks &= ~(ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_TRACE);
+ erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_TRACE);
+ erts_smp_proc_unlock(parent, ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_TRACE);
+ }
+ trace_proc_spawn(p, am_spawned, parent->common.id, mod, func, args);
+ if (so->flags & SPO_LINK)
+ trace_proc(p, locks, p, am_getting_linked, parent->common.id);
}
/*
@@ -11132,10 +11221,6 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
#ifdef DEBUG
int ret;
#endif
- if (IS_TRACED_FL(parent, F_TRACE_PROCS)) {
- trace_proc(parent, parent, am_link, p->common.id);
- }
-
#ifdef DEBUG
ret = erts_add_link(&ERTS_P_LINKS(parent), LINK_PID, p->common.id);
ASSERT(ret == 0);
@@ -11146,17 +11231,6 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
erts_add_link(&ERTS_P_LINKS(p), LINK_PID, parent->common.id);
#endif
- if (IS_TRACED(parent)) {
- if (ERTS_TRACE_FLAGS(parent) & (F_TRACE_SOL|F_TRACE_SOL1)) {
- ERTS_TRACE_FLAGS(p) |= (ERTS_TRACE_FLAGS(parent)&TRACEE_FLAGS);
- ERTS_TRACER_PROC(p) = ERTS_TRACER_PROC(parent); /*maybe steal*/
-
- if (ERTS_TRACE_FLAGS(parent) & F_TRACE_SOL1) {/*maybe override*/
- ERTS_TRACE_FLAGS(p) &= ~(F_TRACE_SOL1 | F_TRACE_SOL);
- ERTS_TRACE_FLAGS(parent) &= ~(F_TRACE_SOL1 | F_TRACE_SOL);
- }
- }
- }
}
/*
@@ -11171,19 +11245,7 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
so->mref = mref;
}
-#ifdef ERTS_SMP
- p->scheduler_data = NULL;
- p->suspendee = NIL;
- p->pending_suspenders = NULL;
- p->pending_exit.reason = THE_NON_VALUE;
- p->pending_exit.bp = NULL;
-#endif
-
-#if !defined(NO_FPE_SIGNALS) || defined(HIPE)
- p->fp_exception = 0;
-#endif
-
- erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL);
+ erts_smp_proc_unlock(p, locks);
res = p->common.id;
@@ -11191,6 +11253,8 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
* Schedule process for execution.
*/
+ erts_smp_proc_unlock(parent, locks & ERTS_PROC_LOCKS_ALL_MINOR);
+
schedule_process(p, state, 0);
VERBOSE(DEBUG_PROCESSES, ("Created a new process: %T\n",p->common.id));
@@ -11204,10 +11268,11 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
DTRACE2(process_spawn, process_name, mfa);
}
#endif
+ return res;
error:
- erts_smp_proc_unlock(parent, ERTS_PROC_LOCKS_ALL_MINOR);
+ erts_smp_proc_unlock(parent, locks & ERTS_PROC_LOCKS_ALL_MINOR);
return res;
}
@@ -11232,7 +11297,7 @@ void erts_init_empty_process(Process *p)
p->rcount = 0;
p->common.id = ERTS_INVALID_PID;
p->reds = 0;
- ERTS_TRACER_PROC(p) = NIL;
+ ERTS_TRACER(p) = erts_tracer_nil;
ERTS_TRACE_FLAGS(p) = F_INITIAL_TRACE_FLAGS;
p->group_leader = ERTS_INVALID_PID;
p->flags = 0;
@@ -11258,7 +11323,7 @@ void erts_init_empty_process(Process *p)
p->mbuf = NULL;
p->msg_frag = NULL;
p->mbuf_sz = 0;
- p->psd = NULL;
+ erts_smp_atomic_init_nob(&p->psd, (erts_aint_t) NULL);
ERTS_P_MONITORS(p) = NULL;
ERTS_P_LINKS(p) = NULL; /* List of links */
p->nodes_monitors = NULL;
@@ -11352,7 +11417,7 @@ erts_debug_verify_clean_empty_process(Process* p)
ASSERT(p->live_hf_end == ERTS_INVALID_HFRAG_PTR);
ASSERT(p->heap == NULL);
ASSERT(p->common.id == ERTS_INVALID_PID);
- ASSERT(ERTS_TRACER_PROC(p) == NIL);
+ ASSERT(ERTS_TRACER_IS_NIL(ERTS_TRACER(p)));
ASSERT(ERTS_TRACE_FLAGS(p) == F_INITIAL_TRACE_FLAGS);
ASSERT(p->group_leader == ERTS_INVALID_PID);
ASSERT(p->next == NULL);
@@ -11428,14 +11493,19 @@ static void
delete_process(Process* p)
{
Eterm *heap;
+ ErtsPSD *psd;
VERBOSE(DEBUG_PROCESSES, ("Removing process: %T\n",p->common.id));
VERBOSE(DEBUG_SHCOPY, ("[pid=%T] delete process: %p %p %p %p\n", p->common.id,
HEAP_START(p), HEAP_END(p), OLD_HEAP(p), OLD_HEND(p)));
/* Cleanup psd */
- if (p->psd)
- erts_free(ERTS_ALC_T_PSD, p->psd);
+ psd = (ErtsPSD *) erts_smp_atomic_read_nob(&p->psd);
+
+ if (psd) {
+ erts_smp_atomic_set_nob(&p->psd, (erts_aint_t) NULL); /* Reduction counting depends on this... */
+ erts_free(ERTS_ALC_T_PSD, psd);
+ }
/* Clean binaries and funs */
erts_cleanup_offheap(&p->off_heap);
@@ -11696,7 +11766,7 @@ send_exit_message(Process *to, ErtsProcLocks *to_locksp,
mp = erts_alloc_message_heap(to, to_locksp, term_size, &hp, &ohp);
mess = copy_struct(exit_term, term_size, &hp, ohp);
#endif
- erts_queue_message(to, to_locksp, mp, mess, NIL);
+ erts_queue_message(to, *to_locksp, mp, mess, am_system);
} else {
Eterm temp_token;
Uint sz_token;
@@ -11714,9 +11784,10 @@ send_exit_message(Process *to, ErtsProcLocks *to_locksp,
mess = copy_struct(exit_term, term_size, &hp, ohp);
#endif
/* the trace token must in this case be updated by the caller */
- seq_trace_output(token, mess, SEQ_TRACE_SEND, to->common.id, NULL);
+ seq_trace_output(token, mess, SEQ_TRACE_SEND, to->common.id, to);
temp_token = copy_struct(token, sz_token, &hp, ohp);
- erts_queue_message(to, to_locksp, mp, mess, temp_token);
+ ERL_MESSAGE_TOKEN(mp) = temp_token;
+ erts_queue_message(to, *to_locksp, mp, mess, am_system);
}
}
@@ -11825,6 +11896,9 @@ send_exit_signal(Process *c_p, /* current process if and only
if ((state & ERTS_PSFLG_TRAP_EXIT)
&& (reason != am_kill || (flags & ERTS_XSIG_FLG_IGN_KILL))) {
+ /* have to release the status lock in order to send the exit message */
+ erts_smp_proc_unlock(rp, *rp_locks & ERTS_PROC_LOCKS_XSIG_SEND);
+ *rp_locks &= ~ERTS_PROC_LOCKS_XSIG_SEND;
if (have_seqtrace(token) && token_update)
seq_trace_update_send(token_update);
if (is_value(exit_tuple))
@@ -12122,6 +12196,7 @@ static void doit_exit_link(ErtsLink *lnk, void *vpcontext)
DistEntry *dep;
Process *rp;
+
switch(lnk->type) {
case LINK_PID:
if(is_internal_port(item)) {
@@ -12169,7 +12244,11 @@ static void doit_exit_link(ErtsLink *lnk, void *vpcontext)
if (xres >= 0 && IS_TRACED_FL(rp, F_TRACE_PROCS)) {
/* We didn't exit the process and it is traced */
if (IS_TRACED_FL(rp, F_TRACE_PROCS)) {
- trace_proc(p, rp, am_getting_unlinked, p->common.id);
+ if (rp_locks & ERTS_PROC_LOCKS_XSIG_SEND) {
+ erts_smp_proc_unlock(rp, ERTS_PROC_LOCKS_XSIG_SEND);
+ rp_locks &= ~ERTS_PROC_LOCKS_XSIG_SEND;
+ }
+ trace_proc(NULL, 0, rp, am_getting_unlinked, p->common.id);
}
}
}
@@ -12286,8 +12365,6 @@ erts_do_exit_process(Process* p, Eterm reason)
if (IS_TRACED_FL(p, F_TRACE_CALLS))
erts_schedule_time_break(p, ERTS_BP_CALL_TIME_SCHEDULE_EXITING);
- if (IS_TRACED_FL(p,F_TRACE_PROCS))
- trace_proc(p, p, am_exit, reason);
}
erts_trace_check_exiting(p->common.id);
@@ -12303,6 +12380,10 @@ erts_do_exit_process(Process* p, Eterm reason)
erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL_MINOR);
+ if (IS_TRACED_FL(p,F_TRACE_PROCS))
+ trace_proc(p, ERTS_PROC_LOCK_MAIN, p, am_exit, reason);
+
+
/*
* p->u.initial of this process can *not* be used anymore;
* will be overwritten by misc termination data.
@@ -12442,6 +12523,9 @@ erts_continue_exit_process(Process *p)
ASSERT(!p->common.u.alive.reg);
}
+ if (IS_TRACED_FL(p, F_TRACE_SCHED_EXIT))
+ trace_sched(p, curr_locks, am_out_exited);
+
erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL_MINOR);
curr_locks = ERTS_PROC_LOCKS_ALL;
@@ -12514,9 +12598,11 @@ erts_continue_exit_process(Process *p)
}
dep = (p->flags & F_DISTRIBUTION) ? erts_this_dist_entry : NULL;
- scb = ERTS_PROC_SET_SAVED_CALLS_BUF(p, ERTS_PROC_LOCKS_ALL, NULL);
- pbt = ERTS_PROC_SET_CALL_TIME(p, ERTS_PROC_LOCKS_ALL, NULL);
- nif_export = ERTS_PROC_SET_NIF_TRAP_EXPORT(p, ERTS_PROC_LOCKS_ALL, NULL);
+ scb = ERTS_PROC_SET_SAVED_CALLS_BUF(p, NULL);
+ if (scb)
+ p->fcalls += CONTEXT_REDS; /* Reduction counting depends on this... */
+ pbt = ERTS_PROC_SET_CALL_TIME(p, NULL);
+ nif_export = ERTS_PROC_SET_NIF_TRAP_EXPORT(p, NULL);
erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL);
#ifdef BM_COUNTERS
@@ -12565,6 +12651,12 @@ erts_continue_exit_process(Process *p)
if (nif_export)
erts_destroy_nif_export(nif_export);
+#ifdef ERTS_SMP
+ erts_flush_trace_messages(p, 0);
+#endif
+
+ ERTS_TRACER_CLEAR(&ERTS_TRACER(p));
+
delete_process(p);
#ifdef ERTS_SMP
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index c88bd7056c..59da9c1779 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -805,8 +805,15 @@ erts_smp_reset_max_len(ErtsRunQueue *rq, ErtsRunQueueInfo *rqi)
#define ERTS_PSD_CALL_TIME_BP 3
#define ERTS_PSD_DELAYED_GC_TASK_QS 4
#define ERTS_PSD_NIF_TRAP_EXPORT 5
+#ifdef HIPE
+#define ERTS_PSD_SUSPENDED_SAVED_CALLS_BUF 6
+#endif
+#ifdef HIPE
+#define ERTS_PSD_SIZE 7
+#else
#define ERTS_PSD_SIZE 6
+#endif
typedef struct {
void *data[ERTS_PSD_SIZE];
@@ -818,8 +825,8 @@ typedef struct {
#define ERTS_PSD_ERROR_HANDLER_BUF_GET_LOCKS ERTS_PROC_LOCK_MAIN
#define ERTS_PSD_ERROR_HANDLER_BUF_SET_LOCKS ERTS_PROC_LOCK_MAIN
-#define ERTS_PSD_SAVED_CALLS_BUF_GET_LOCKS ERTS_PROC_LOCK_MAIN
-#define ERTS_PSD_SAVED_CALLS_BUF_SET_LOCKS ERTS_PROC_LOCK_MAIN
+#define ERTS_PSD_SAVED_CALLS_BUF_GET_LOCKS ((ErtsProcLocks) 0)
+#define ERTS_PSD_SAVED_CALLS_BUF_SET_LOCKS ((ErtsProcLocks) 0)
#define ERTS_PSD_SCHED_ID_GET_LOCKS ERTS_PROC_LOCK_STATUS
#define ERTS_PSD_SCHED_ID_SET_LOCKS ERTS_PROC_LOCK_STATUS
@@ -830,8 +837,8 @@ typedef struct {
#define ERTS_PSD_DELAYED_GC_TASK_QS_GET_LOCKS ERTS_PROC_LOCK_MAIN
#define ERTS_PSD_DELAYED_GC_TASK_QS_SET_LOCKS ERTS_PROC_LOCK_MAIN
-#define ERTS_PSD_NIF_TRAP_EXPORT_GET_LOCKS ERTS_PROC_LOCK_MAIN
-#define ERTS_PSD_NIF_TRAP_EXPORT_SET_LOCKS ERTS_PROC_LOCK_MAIN
+#define ERTS_PSD_NIF_TRAP_EXPORT_GET_LOCKS ((ErtsProcLocks) 0)
+#define ERTS_PSD_NIF_TRAP_EXPORT_SET_LOCKS ((ErtsProcLocks) 0)
typedef struct {
ErtsProcLocks get_locks;
@@ -925,7 +932,6 @@ struct process {
Eterm* stop; /* Stack top */
Eterm* heap; /* Heap start */
Eterm* hend; /* Heap end */
- Eterm* abandoned_heap;
Uint heap_sz; /* Size of heap in words */
Uint min_heap_size; /* Minimum size of heap (in words). */
Uint min_vheap_size; /* Minimum size of virtual heap (in words). */
@@ -941,6 +947,16 @@ struct process {
#endif
/*
+ * Moved to after "struct hipe_process_state hipe", as a temporary fix for
+ * LLVM hard-coding offsetof(struct process, hipe.nstack) (sic!)
+ * (see void X86FrameLowering::adjustForHiPEPrologue(...) in
+ * lib/Target/X86/X86FrameLowering.cpp).
+ *
+ * Used to be below "Eterm* hend".
+ */
+ Eterm* abandoned_heap;
+
+ /*
* Saved x registers.
*/
Uint arity; /* Number of live argument registers (only valid
@@ -1026,7 +1042,7 @@ struct process {
ErlHeapFragment* live_hf_end;
ErtsMessage *msg_frag; /* Pointer to message fragment list */
Uint mbuf_sz; /* Total size of heap fragments and message fragments */
- ErtsPSD *psd; /* Rarely used process specific data */
+ erts_smp_atomic_t psd; /* Rarely used process specific data */
Uint64 bin_vheap_sz; /* Virtual heap block size for binaries */
Uint64 bin_old_vheap_sz; /* Virtual old heap block size for binaries */
@@ -1041,6 +1057,7 @@ struct process {
#ifdef ERTS_SMP
ErlMessageInQueue msg_inq;
+ ErlTraceMessageQueue *trace_msg_q;
ErtsPendExit pending_exit;
erts_proc_lock_t lock;
ErtsSchedulerData *scheduler_data;
@@ -1070,6 +1087,10 @@ struct process {
Uint space_verified; /* Avoid HAlloc forcing heap fragments when */
Eterm* space_verified_from; /* we rely on available heap space (TestHeap) */
#endif
+
+#ifdef DEBUG
+ Uint debug_reds_in;
+#endif
};
extern const Process erts_invalid_process;
@@ -1341,6 +1362,7 @@ extern int erts_system_profile_ts_type;
#define F_DELAY_GC (1 << 16) /* Similar to disable GC (see below) */
#define F_SCHDLR_ONLN_WAITQ (1 << 17) /* Process enqueued waiting to change schedulers online */
#define F_HAVE_BLCKD_NMSCHED (1 << 18) /* Process has blocked normal multi-scheduling */
+#define F_HIPE_MODE (1 << 19)
/*
* F_DISABLE_GC and F_DELAY_GC are similar. Both will prevent
@@ -1358,7 +1380,6 @@ extern int erts_system_profile_ts_type;
#define F_TRACE_FLAG(N) (1 << (ERTS_TRACE_TS_TYPE_BITS + (N)))
/* process trace_flags */
-
#define F_NOW_TS (ERTS_TRACE_FLG_NOW_TIMESTAMP \
<< ERTS_TRACE_FLAGS_TS_TYPE_SHIFT)
#define F_STRICT_MON_TS (ERTS_TRACE_FLG_STRICT_MONOTONIC_TIMESTAMP \
@@ -1380,8 +1401,7 @@ extern int erts_system_profile_ts_type;
#define F_TRACE_ARITY_ONLY F_TRACE_FLAG(12)
#define F_TRACE_RETURN_TO F_TRACE_FLAG(13) /* Return_to trace when breakpoint tracing */
#define F_TRACE_SILENT F_TRACE_FLAG(14) /* No call trace msg suppress */
-#define F_TRACER F_TRACE_FLAG(15) /* May be (has been) tracer */
-#define F_EXCEPTION_TRACE F_TRACE_FLAG(16) /* May have exception trace on stack */
+#define F_EXCEPTION_TRACE F_TRACE_FLAG(15) /* May have exception trace on stack */
/* port trace flags, currently the same as process trace flags */
#define F_TRACE_SCHED_PORTS F_TRACE_FLAG(17) /* Trace of port scheduling */
@@ -1410,12 +1430,14 @@ extern int erts_system_profile_ts_type;
| F_TRACE_SCHED_PORTS | F_TRACE_SCHED_NO \
| F_TRACE_SCHED_EXIT)
+
#define ERTS_TRACEE_MODIFIER_FLAGS \
- (F_TRACE_SILENT | F_TIMESTAMP_MASK | F_TRACE_SCHED_NO)
-#define ERTS_PORT_TRACEE_FLAGS \
- (ERTS_TRACEE_MODIFIER_FLAGS | F_TRACE_PORTS | F_TRACE_SCHED_PORTS)
+ (F_TRACE_SILENT | F_TIMESTAMP_MASK | F_TRACE_SCHED_NO \
+ | F_TRACE_RECEIVE | F_TRACE_SEND)
+#define ERTS_PORT_TRACEE_FLAGS \
+ (ERTS_TRACEE_MODIFIER_FLAGS | F_TRACE_PORTS | F_TRACE_SCHED_PORTS)
#define ERTS_PROC_TRACEE_FLAGS \
- ((TRACEE_FLAGS & ~ERTS_PORT_TRACEE_FLAGS) | ERTS_TRACEE_MODIFIER_FLAGS)
+ ((TRACEE_FLAGS & ~ERTS_PORT_TRACEE_FLAGS) | ERTS_TRACEE_MODIFIER_FLAGS)
#define SEQ_TRACE_FLAG(N) (1 << (ERTS_TRACE_TS_TYPE_BITS + (N)))
@@ -1717,6 +1739,8 @@ void erts_schedule_thr_prgr_later_cleanup_op(void (*)(void *),
ErtsThrPrgrLaterOp *,
UWord);
void erts_schedule_complete_off_heap_message_queue_change(Eterm pid);
+void erts_schedule_flush_trace_messages(Eterm pid);
+int erts_flush_trace_messages(Process *c_p, ErtsProcLocks locks);
#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)
int erts_dbg_check_halloc_lock(Process *p);
@@ -1903,18 +1927,19 @@ do { \
#define ERTS_SMP_LC_CHK_RUNQ_LOCK(RQ, L)
#endif
-void *erts_psd_set_init(Process *p, ErtsProcLocks plocks, int ix, void *data);
+void *erts_psd_set_init(Process *p, int ix, void *data);
ERTS_GLB_INLINE void *
erts_psd_get(Process *p, int ix);
ERTS_GLB_INLINE void *
-erts_psd_set(Process *p, ErtsProcLocks plocks, int ix, void *new);
+erts_psd_set(Process *p, int ix, void *new);
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
ERTS_GLB_INLINE void *
erts_psd_get(Process *p, int ix)
{
+ ErtsPSD *psd;
#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)
ErtsProcLocks locks = erts_proc_lc_my_proc_locks(p);
if (ERTS_LC_PSD_ANY_LOCK == erts_psd_required_locks[ix].get_locks)
@@ -1925,17 +1950,19 @@ erts_psd_get(Process *p, int ix)
|| erts_thr_progress_is_blocking());
}
#endif
+
+ psd = (ErtsPSD *) erts_smp_atomic_read_nob(&p->psd);
ASSERT(0 <= ix && ix < ERTS_PSD_SIZE);
- return p->psd ? p->psd->data[ix] : NULL;
+ if (!psd)
+ return NULL;
+ ERTS_SMP_DATA_DEPENDENCY_READ_MEMORY_BARRIER;
+ return psd->data[ix];
}
-
-/*
- * NOTE: erts_psd_set() might release and reacquire locks on 'p'.
- */
ERTS_GLB_INLINE void *
-erts_psd_set(Process *p, ErtsProcLocks plocks, int ix, void *data)
+erts_psd_set(Process *p, int ix, void *data)
{
+ ErtsPSD *psd;
#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)
ErtsProcLocks locks = erts_proc_lc_my_proc_locks(p);
if (ERTS_LC_PSD_ANY_LOCK == erts_psd_required_locks[ix].set_locks)
@@ -1946,50 +1973,62 @@ erts_psd_set(Process *p, ErtsProcLocks plocks, int ix, void *data)
|| erts_thr_progress_is_blocking());
}
#endif
+ psd = (ErtsPSD *) erts_smp_atomic_read_nob(&p->psd);
ASSERT(0 <= ix && ix < ERTS_PSD_SIZE);
- if (p->psd) {
- void *old = p->psd->data[ix];
- p->psd->data[ix] = data;
+ if (psd) {
+ void *old;
+#ifdef ERTS_SMP
+#ifdef ETHR_ORDERED_READ_DEPEND
+ ETHR_MEMBAR(ETHR_LoadStore|ETHR_StoreStore);
+#else
+ ETHR_MEMBAR(ETHR_LoadLoad|ETHR_LoadStore|ETHR_StoreStore);
+#endif
+#endif
+ old = psd->data[ix];
+ psd->data[ix] = data;
return old;
}
- else {
- if (!data)
- return NULL;
- else
- return erts_psd_set_init(p, plocks, ix, data);
- }
+
+ if (!data)
+ return NULL;
+
+ return erts_psd_set_init(p, ix, data);
}
#endif
-#define ERTS_PROC_SCHED_ID(P, L, ID) \
- ((UWord) erts_psd_set((P), (L), ERTS_PSD_SCHED_ID, (void *) (ID)))
+#define ERTS_PROC_SCHED_ID(P, ID) \
+ ((UWord) erts_psd_set((P), ERTS_PSD_SCHED_ID, (void *) (ID)))
#define ERTS_PROC_GET_SAVED_CALLS_BUF(P) \
((struct saved_calls *) erts_psd_get((P), ERTS_PSD_SAVED_CALLS_BUF))
-#define ERTS_PROC_SET_SAVED_CALLS_BUF(P, L, SCB) \
- ((struct saved_calls *) erts_psd_set((P), (L), ERTS_PSD_SAVED_CALLS_BUF, (void *) (SCB)))
+#define ERTS_PROC_SET_SAVED_CALLS_BUF(P, SCB) \
+ ((struct saved_calls *) erts_psd_set((P), ERTS_PSD_SAVED_CALLS_BUF, (void *) (SCB)))
#define ERTS_PROC_GET_CALL_TIME(P) \
((process_breakpoint_time_t *) erts_psd_get((P), ERTS_PSD_CALL_TIME_BP))
-#define ERTS_PROC_SET_CALL_TIME(P, L, PBT) \
- ((process_breakpoint_time_t *) erts_psd_set((P), (L), ERTS_PSD_CALL_TIME_BP, (void *) (PBT)))
+#define ERTS_PROC_SET_CALL_TIME(P, PBT) \
+ ((process_breakpoint_time_t *) erts_psd_set((P), ERTS_PSD_CALL_TIME_BP, (void *) (PBT)))
#define ERTS_PROC_GET_DELAYED_GC_TASK_QS(P) \
((ErtsProcSysTaskQs *) erts_psd_get((P), ERTS_PSD_DELAYED_GC_TASK_QS))
-#define ERTS_PROC_SET_DELAYED_GC_TASK_QS(P, L, PBT) \
- ((ErtsProcSysTaskQs *) erts_psd_set((P), (L), ERTS_PSD_DELAYED_GC_TASK_QS, (void *) (PBT)))
+#define ERTS_PROC_SET_DELAYED_GC_TASK_QS(P, PBT) \
+ ((ErtsProcSysTaskQs *) erts_psd_set((P), ERTS_PSD_DELAYED_GC_TASK_QS, (void *) (PBT)))
#define ERTS_PROC_GET_NIF_TRAP_EXPORT(P) \
erts_psd_get((P), ERTS_PSD_NIF_TRAP_EXPORT)
-#define ERTS_PROC_SET_NIF_TRAP_EXPORT(P, L, NTE) \
- erts_psd_set((P), (L), ERTS_PSD_NIF_TRAP_EXPORT, (void *) (NTE))
+#define ERTS_PROC_SET_NIF_TRAP_EXPORT(P, NTE) \
+ erts_psd_set((P), ERTS_PSD_NIF_TRAP_EXPORT, (void *) (NTE))
+#ifdef HIPE
+#define ERTS_PROC_GET_SUSPENDED_SAVED_CALLS_BUF(P) \
+ ((struct saved_calls *) erts_psd_get((P), ERTS_PSD_SUSPENDED_SAVED_CALLS_BUF))
+#define ERTS_PROC_SET_SUSPENDED_SAVED_CALLS_BUF(P, SCB) \
+ ((struct saved_calls *) erts_psd_set((P), ERTS_PSD_SUSPENDED_SAVED_CALLS_BUF, (void *) (SCB)))
+#endif
ERTS_GLB_INLINE Eterm erts_proc_get_error_handler(Process *p);
-ERTS_GLB_INLINE Eterm erts_proc_set_error_handler(Process *p,
- ErtsProcLocks plocks,
- Eterm handler);
+ERTS_GLB_INLINE Eterm erts_proc_set_error_handler(Process *p, Eterm handler);
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
ERTS_GLB_INLINE Eterm
@@ -2005,13 +2044,13 @@ erts_proc_get_error_handler(Process *p)
}
ERTS_GLB_INLINE Eterm
-erts_proc_set_error_handler(Process *p, ErtsProcLocks plocks, Eterm handler)
+erts_proc_set_error_handler(Process *p, Eterm handler)
{
void *old_val;
void *new_val;
ASSERT(is_atom(handler));
new_val = (handler == am_error_handler) ? NULL : (void *) (UWord) handler;
- old_val = erts_psd_set(p, plocks, ERTS_PSD_ERROR_HANDLER, new_val);
+ old_val = erts_psd_set(p, ERTS_PSD_ERROR_HANDLER, new_val);
if (!old_val)
return am_error_handler;
else {
@@ -2317,14 +2356,17 @@ erts_alloc_message_heap_state(Process *pp,
ErlOffHeap **ohpp)
{
int on_heap;
+ ErtsMessage *mp;
if ((*psp) & ERTS_PSFLG_OFF_HEAP_MSGQ) {
- ErtsMessage *mp = erts_alloc_message(sz, hpp);
+ mp = erts_alloc_message(sz, hpp);
*ohpp = sz == 0 ? NULL : &mp->hfrag.off_heap;
return mp;
}
- return erts_try_alloc_message_on_heap(pp, psp, plp, sz, hpp, ohpp, &on_heap);
+ mp = erts_try_alloc_message_on_heap(pp, psp, plp, sz, hpp, ohpp, &on_heap);
+ ASSERT(pp || !on_heap);
+ return mp;
}
ERTS_GLB_INLINE ErtsMessage *
@@ -2334,7 +2376,7 @@ erts_alloc_message_heap(Process *pp,
Eterm **hpp,
ErlOffHeap **ohpp)
{
- erts_aint32_t state = erts_smp_atomic32_read_nob(&pp->state);
+ erts_aint32_t state = pp ? erts_smp_atomic32_read_nob(&pp->state) : 0;
return erts_alloc_message_heap_state(pp, &state, plp, sz, hpp, ohpp);
}
diff --git a/erts/emulator/beam/erl_process_dict.c b/erts/emulator/beam/erl_process_dict.c
index 487b944fc0..d8c2eaba94 100644
--- a/erts/emulator/beam/erl_process_dict.c
+++ b/erts/emulator/beam/erl_process_dict.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/beam/erl_process_dict.h b/erts/emulator/beam/erl_process_dict.h
index dac214c8a1..387562058c 100644
--- a/erts/emulator/beam/erl_process_dict.h
+++ b/erts/emulator/beam/erl_process_dict.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c
index 39c36ee7a9..fa76773cac 100644
--- a/erts/emulator/beam/erl_process_dump.c
+++ b/erts/emulator/beam/erl_process_dump.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
@@ -103,7 +103,7 @@ Uint erts_process_memory(Process *p, int incl_msg_inq) {
size += p->arity * sizeof(p->arg_reg[0]);
}
- if (p->psd)
+ if (erts_smp_atomic_read_nob(&p->psd) != (erts_aint_t) NULL)
size += sizeof(ErtsPSD);
scb = ERTS_PROC_GET_SAVED_CALLS_BUF(p);
diff --git a/erts/emulator/beam/erl_process_lock.c b/erts/emulator/beam/erl_process_lock.c
index 0bee2c848c..a69185bc5c 100644
--- a/erts/emulator/beam/erl_process_lock.c
+++ b/erts/emulator/beam/erl_process_lock.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2007-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2007-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.
@@ -106,6 +106,7 @@ static struct {
Sint16 proc_lock_msgq;
Sint16 proc_lock_btm;
Sint16 proc_lock_status;
+ Sint16 proc_lock_trace;
} lc_id;
#endif
@@ -152,6 +153,7 @@ erts_init_proc_lock(int cpus)
lc_id.proc_lock_msgq = erts_lc_get_lock_order_id("proc_msgq");
lc_id.proc_lock_btm = erts_lc_get_lock_order_id("proc_btm");
lc_id.proc_lock_status = erts_lc_get_lock_order_id("proc_status");
+ lc_id.proc_lock_trace = erts_lc_get_lock_order_id("proc_trace");
#endif
}
@@ -1057,6 +1059,11 @@ erts_proc_lock_init(Process *p)
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_trylock(1, &p->lock.status.lc);
#endif
+ erts_mtx_init_x(&p->lock.trace, "proc_trace", p->common.id, do_lock_count);
+ ethr_mutex_lock(&p->lock.trace.mtx);
+#ifdef ERTS_ENABLE_LOCK_CHECK
+ erts_lc_trylock(1, &p->lock.trace.lc);
+#endif
#endif
#ifdef ERTS_PROC_LOCK_DEBUG
for (i = 0; i <= ERTS_PROC_LOCK_MAX_BIT; i++)
@@ -1078,6 +1085,7 @@ erts_proc_lock_fin(Process *p)
erts_mtx_destroy(&p->lock.msgq);
erts_mtx_destroy(&p->lock.btm);
erts_mtx_destroy(&p->lock.status);
+ erts_mtx_destroy(&p->lock.trace);
#endif
#if defined(ERTS_ENABLE_LOCK_COUNT) && defined(ERTS_SMP)
erts_lcnt_proc_lock_destroy(p);
@@ -1100,26 +1108,29 @@ void erts_lcnt_enable_proc_lock_count(int enable) {
void erts_lcnt_proc_lock_init(Process *p) {
if (!(erts_lcnt_rt_options & ERTS_LCNT_OPT_PROCLOCK)) {
erts_lcnt_init_lock_empty(&(p->lock.lcnt_main));
+ erts_lcnt_init_lock_empty(&(p->lock.lcnt_link));
erts_lcnt_init_lock_empty(&(p->lock.lcnt_msgq));
erts_lcnt_init_lock_empty(&(p->lock.lcnt_btm));
- erts_lcnt_init_lock_empty(&(p->lock.lcnt_link));
erts_lcnt_init_lock_empty(&(p->lock.lcnt_status));
+ erts_lcnt_init_lock_empty(&(p->lock.lcnt_trace));
} else { /* now the common case */
Eterm pid = (p->common.id != ERTS_INVALID_PID) ? p->common.id : NIL;
erts_lcnt_init_lock_x(&(p->lock.lcnt_main), "proc_main", ERTS_LCNT_LT_PROCLOCK, pid);
+ erts_lcnt_init_lock_x(&(p->lock.lcnt_link), "proc_link", ERTS_LCNT_LT_PROCLOCK, pid);
erts_lcnt_init_lock_x(&(p->lock.lcnt_msgq), "proc_msgq", ERTS_LCNT_LT_PROCLOCK, pid);
erts_lcnt_init_lock_x(&(p->lock.lcnt_btm), "proc_btm", ERTS_LCNT_LT_PROCLOCK, pid);
- erts_lcnt_init_lock_x(&(p->lock.lcnt_link), "proc_link", ERTS_LCNT_LT_PROCLOCK, pid);
erts_lcnt_init_lock_x(&(p->lock.lcnt_status),"proc_status",ERTS_LCNT_LT_PROCLOCK, pid);
+ erts_lcnt_init_lock_x(&(p->lock.lcnt_trace), "proc_trace", ERTS_LCNT_LT_PROCLOCK, pid);
} /* the lock names should really be aligned to four characters */
} /* logic reversed */
void erts_lcnt_proc_lock_destroy(Process *p) {
erts_lcnt_destroy_lock(&(p->lock.lcnt_main));
+ erts_lcnt_destroy_lock(&(p->lock.lcnt_link));
erts_lcnt_destroy_lock(&(p->lock.lcnt_msgq));
erts_lcnt_destroy_lock(&(p->lock.lcnt_btm));
- erts_lcnt_destroy_lock(&(p->lock.lcnt_link));
erts_lcnt_destroy_lock(&(p->lock.lcnt_status));
+ erts_lcnt_destroy_lock(&(p->lock.lcnt_trace));
}
static void lcnt_enable_proc_lock_count(Process *proc, int enable) {
@@ -1138,10 +1149,11 @@ static void lcnt_enable_proc_lock_count(Process *proc, int enable) {
void erts_lcnt_proc_lock(erts_proc_lock_t *lock, ErtsProcLocks locks) {
if (!(erts_lcnt_rt_options & ERTS_LCNT_OPT_PROCLOCK)) return;
if (locks & ERTS_PROC_LOCK_MAIN) { erts_lcnt_lock(&(lock->lcnt_main)); }
+ if (locks & ERTS_PROC_LOCK_LINK) { erts_lcnt_lock(&(lock->lcnt_link)); }
if (locks & ERTS_PROC_LOCK_MSGQ) { erts_lcnt_lock(&(lock->lcnt_msgq)); }
if (locks & ERTS_PROC_LOCK_BTM) { erts_lcnt_lock(&(lock->lcnt_btm)); }
- if (locks & ERTS_PROC_LOCK_LINK) { erts_lcnt_lock(&(lock->lcnt_link)); }
if (locks & ERTS_PROC_LOCK_STATUS) { erts_lcnt_lock(&(lock->lcnt_status)); }
+ if (locks & ERTS_PROC_LOCK_TRACE) { erts_lcnt_lock(&(lock->lcnt_trace)); }
}
void erts_lcnt_proc_lock_post_x(erts_proc_lock_t *lock, ErtsProcLocks locks,
@@ -1150,44 +1162,50 @@ void erts_lcnt_proc_lock_post_x(erts_proc_lock_t *lock, ErtsProcLocks locks,
if (locks & ERTS_PROC_LOCK_MAIN) {
erts_lcnt_lock_post_x(&(lock->lcnt_main), file, line);
}
+ if (locks & ERTS_PROC_LOCK_LINK) {
+ erts_lcnt_lock_post_x(&(lock->lcnt_link), file, line);
+ }
if (locks & ERTS_PROC_LOCK_MSGQ) {
erts_lcnt_lock_post_x(&(lock->lcnt_msgq), file, line);
}
if (locks & ERTS_PROC_LOCK_BTM) {
erts_lcnt_lock_post_x(&(lock->lcnt_btm), file, line);
}
- if (locks & ERTS_PROC_LOCK_LINK) {
- erts_lcnt_lock_post_x(&(lock->lcnt_link), file, line);
- }
if (locks & ERTS_PROC_LOCK_STATUS) {
erts_lcnt_lock_post_x(&(lock->lcnt_status), file, line);
}
+ if (locks & ERTS_PROC_LOCK_TRACE) {
+ erts_lcnt_lock_post_x(&(lock->lcnt_trace), file, line);
+ }
}
void erts_lcnt_proc_lock_unaquire(erts_proc_lock_t *lock, ErtsProcLocks locks) {
if (!(erts_lcnt_rt_options & ERTS_LCNT_OPT_PROCLOCK)) return;
if (locks & ERTS_PROC_LOCK_MAIN) { erts_lcnt_lock_unaquire(&(lock->lcnt_main)); }
+ if (locks & ERTS_PROC_LOCK_LINK) { erts_lcnt_lock_unaquire(&(lock->lcnt_link)); }
if (locks & ERTS_PROC_LOCK_MSGQ) { erts_lcnt_lock_unaquire(&(lock->lcnt_msgq)); }
if (locks & ERTS_PROC_LOCK_BTM) { erts_lcnt_lock_unaquire(&(lock->lcnt_btm)); }
- if (locks & ERTS_PROC_LOCK_LINK) { erts_lcnt_lock_unaquire(&(lock->lcnt_link)); }
if (locks & ERTS_PROC_LOCK_STATUS) { erts_lcnt_lock_unaquire(&(lock->lcnt_status)); }
+ if (locks & ERTS_PROC_LOCK_TRACE) { erts_lcnt_lock_unaquire(&(lock->lcnt_trace)); }
}
void erts_lcnt_proc_unlock(erts_proc_lock_t *lock, ErtsProcLocks locks) {
if (!(erts_lcnt_rt_options & ERTS_LCNT_OPT_PROCLOCK)) return;
if (locks & ERTS_PROC_LOCK_MAIN) { erts_lcnt_unlock(&(lock->lcnt_main)); }
+ if (locks & ERTS_PROC_LOCK_LINK) { erts_lcnt_unlock(&(lock->lcnt_link)); }
if (locks & ERTS_PROC_LOCK_MSGQ) { erts_lcnt_unlock(&(lock->lcnt_msgq)); }
if (locks & ERTS_PROC_LOCK_BTM) { erts_lcnt_unlock(&(lock->lcnt_btm)); }
- if (locks & ERTS_PROC_LOCK_LINK) { erts_lcnt_unlock(&(lock->lcnt_link)); }
if (locks & ERTS_PROC_LOCK_STATUS) { erts_lcnt_unlock(&(lock->lcnt_status)); }
+ if (locks & ERTS_PROC_LOCK_TRACE) { erts_lcnt_unlock(&(lock->lcnt_trace)); }
}
void erts_lcnt_proc_trylock(erts_proc_lock_t *lock, ErtsProcLocks locks, int res) {
if (!(erts_lcnt_rt_options & ERTS_LCNT_OPT_PROCLOCK)) return;
if (locks & ERTS_PROC_LOCK_MAIN) { erts_lcnt_trylock(&(lock->lcnt_main), res); }
+ if (locks & ERTS_PROC_LOCK_LINK) { erts_lcnt_trylock(&(lock->lcnt_link), res); }
if (locks & ERTS_PROC_LOCK_MSGQ) { erts_lcnt_trylock(&(lock->lcnt_msgq), res); }
if (locks & ERTS_PROC_LOCK_BTM) { erts_lcnt_trylock(&(lock->lcnt_btm), res); }
- if (locks & ERTS_PROC_LOCK_LINK) { erts_lcnt_trylock(&(lock->lcnt_link), res); }
if (locks & ERTS_PROC_LOCK_STATUS) { erts_lcnt_trylock(&(lock->lcnt_status), res); }
+ if (locks & ERTS_PROC_LOCK_TRACE) { erts_lcnt_trylock(&(lock->lcnt_trace), res); }
} /* reversed logic */
#endif /* ERTS_ENABLE_LOCK_COUNT */
@@ -1224,6 +1242,10 @@ erts_proc_lc_lock(Process *p, ErtsProcLocks locks, char *file, unsigned int line
lck.id = lc_id.proc_lock_status;
erts_lc_lock_x(&lck,file,line);
}
+ if (locks & ERTS_PROC_LOCK_TRACE) {
+ lck.id = lc_id.proc_lock_trace;
+ erts_lc_lock_x(&lck,file,line);
+ }
}
void
@@ -1253,6 +1275,10 @@ erts_proc_lc_trylock(Process *p, ErtsProcLocks locks, int locked,
lck.id = lc_id.proc_lock_status;
erts_lc_trylock_x(locked, &lck, file, line);
}
+ if (locks & ERTS_PROC_LOCK_TRACE) {
+ lck.id = lc_id.proc_lock_trace;
+ erts_lc_trylock_x(locked, &lck, file, line);
+ }
}
void
@@ -1261,6 +1287,10 @@ erts_proc_lc_unlock(Process *p, ErtsProcLocks locks)
erts_lc_lock_t lck = ERTS_LC_LOCK_INIT(-1,
p->common.id,
ERTS_LC_FLG_LT_PROCLOCK);
+ if (locks & ERTS_PROC_LOCK_TRACE) {
+ lck.id = lc_id.proc_lock_trace;
+ erts_lc_unlock(&lck);
+ }
if (locks & ERTS_PROC_LOCK_STATUS) {
lck.id = lc_id.proc_lock_status;
erts_lc_unlock(&lck);
@@ -1292,6 +1322,10 @@ erts_proc_lc_might_unlock(Process *p, ErtsProcLocks locks)
erts_lc_lock_t lck = ERTS_LC_LOCK_INIT(-1,
p->common.id,
ERTS_LC_FLG_LT_PROCLOCK);
+ if (locks & ERTS_PROC_LOCK_TRACE) {
+ lck.id = lc_id.proc_lock_trace;
+ erts_lc_might_unlock(&lck);
+ }
if (locks & ERTS_PROC_LOCK_STATUS) {
lck.id = lc_id.proc_lock_status;
erts_lc_might_unlock(&lck);
@@ -1323,6 +1357,8 @@ erts_proc_lc_might_unlock(Process *p, ErtsProcLocks locks)
erts_lc_might_unlock(&p->lock.btm.lc);
if (locks & ERTS_PROC_LOCK_STATUS)
erts_lc_might_unlock(&p->lock.status.lc);
+ if (locks & ERTS_PROC_LOCK_TRACE)
+ erts_lc_might_unlock(&p->lock.trace.lc);
#endif
}
@@ -1354,6 +1390,10 @@ erts_proc_lc_require_lock(Process *p, ErtsProcLocks locks, char *file,
lck.id = lc_id.proc_lock_status;
erts_lc_require_lock(&lck, file, line);
}
+ if (locks & ERTS_PROC_LOCK_TRACE) {
+ lck.id = lc_id.proc_lock_trace;
+ erts_lc_require_lock(&lck, file, line);
+ }
#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL
if (locks & ERTS_PROC_LOCK_MAIN)
erts_lc_require_lock(&p->lock.main.lc, file, line);
@@ -1365,6 +1405,8 @@ erts_proc_lc_require_lock(Process *p, ErtsProcLocks locks, char *file,
erts_lc_require_lock(&p->lock.btm.lc, file, line);
if (locks & ERTS_PROC_LOCK_STATUS)
erts_lc_require_lock(&p->lock.status.lc, file, line);
+ if (locks & ERTS_PROC_LOCK_TRACE)
+ erts_lc_require_lock(&p->lock.trace.lc, file, line);
#endif
}
@@ -1375,6 +1417,10 @@ erts_proc_lc_unrequire_lock(Process *p, ErtsProcLocks locks)
erts_lc_lock_t lck = ERTS_LC_LOCK_INIT(-1,
p->common.id,
ERTS_LC_FLG_LT_PROCLOCK);
+ if (locks & ERTS_PROC_LOCK_TRACE) {
+ lck.id = lc_id.proc_lock_trace;
+ erts_lc_unrequire_lock(&lck);
+ }
if (locks & ERTS_PROC_LOCK_STATUS) {
lck.id = lc_id.proc_lock_status;
erts_lc_unrequire_lock(&lck);
@@ -1406,6 +1452,8 @@ erts_proc_lc_unrequire_lock(Process *p, ErtsProcLocks locks)
erts_lc_unrequire_lock(&p->lock.btm.lc);
if (locks & ERTS_PROC_LOCK_STATUS)
erts_lc_unrequire_lock(&p->lock.status.lc);
+ if (locks & ERTS_PROC_LOCK_TRACE)
+ erts_lc_unrequire_lock(&p->lock.trace.lc);
#endif
}
@@ -1429,6 +1477,8 @@ erts_proc_lc_trylock_force_busy(Process *p, ErtsProcLocks locks)
lck.id = lc_id.proc_lock_btm;
else if (locks & ERTS_PROC_LOCK_STATUS)
lck.id = lc_id.proc_lock_status;
+ else if (locks & ERTS_PROC_LOCK_TRACE)
+ lck.id = lc_id.proc_lock_trace;
else
erts_lc_fail("Unknown proc lock found");
@@ -1441,14 +1491,7 @@ erts_proc_lc_trylock_force_busy(Process *p, ErtsProcLocks locks)
void erts_proc_lc_chk_only_proc_main(Process *p)
{
-#if ERTS_PROC_LOCK_OWN_IMPL
- erts_lc_lock_t proc_main = ERTS_LC_LOCK_INIT(lc_id.proc_lock_main,
- p->common.id,
- ERTS_LC_FLG_LT_PROCLOCK);
- erts_lc_check_exact(&proc_main, 1);
-#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL
- erts_lc_check_exact(&p->lock.main.lc, 1);
-#endif
+ erts_proc_lc_chk_only_proc(p, ERTS_PROC_LOCK_MAIN);
}
#if ERTS_PROC_LOCK_OWN_IMPL
@@ -1456,14 +1499,67 @@ void erts_proc_lc_chk_only_proc_main(Process *p)
ERTS_LC_LOCK_INIT(-1, THE_NON_VALUE, ERTS_LC_FLG_LT_PROCLOCK)
#endif /* ERTS_PROC_LOCK_OWN_IMPL */
+void erts_proc_lc_chk_only_proc(Process *p, ErtsProcLocks locks)
+{
+ int have_locks_len = 0;
+#if ERTS_PROC_LOCK_OWN_IMPL
+ erts_lc_lock_t have_locks[6] = {ERTS_PROC_LC_EMPTY_LOCK_INIT,
+ ERTS_PROC_LC_EMPTY_LOCK_INIT,
+ ERTS_PROC_LC_EMPTY_LOCK_INIT,
+ ERTS_PROC_LC_EMPTY_LOCK_INIT,
+ ERTS_PROC_LC_EMPTY_LOCK_INIT,
+ ERTS_PROC_LC_EMPTY_LOCK_INIT};
+ if (locks & ERTS_PROC_LOCK_MAIN) {
+ have_locks[have_locks_len].id = lc_id.proc_lock_main;
+ have_locks[have_locks_len++].extra = p->common.id;
+ }
+ if (locks & ERTS_PROC_LOCK_LINK) {
+ have_locks[have_locks_len].id = lc_id.proc_lock_link;
+ have_locks[have_locks_len++].extra = p->common.id;
+ }
+ if (locks & ERTS_PROC_LOCK_MSGQ) {
+ have_locks[have_locks_len].id = lc_id.proc_lock_msgq;
+ have_locks[have_locks_len++].extra = p->common.id;
+ }
+ if (locks & ERTS_PROC_LOCK_BTM) {
+ have_locks[have_locks_len].id = lc_id.proc_lock_btm;
+ have_locks[have_locks_len++].extra = p->common.id;
+ }
+ if (locks & ERTS_PROC_LOCK_STATUS) {
+ have_locks[have_locks_len].id = lc_id.proc_lock_status;
+ have_locks[have_locks_len++].extra = p->common.id;
+ }
+ if (locks & ERTS_PROC_LOCK_TRACE) {
+ have_locks[have_locks_len].id = lc_id.proc_lock_trace;
+ have_locks[have_locks_len++].extra = p->common.id;
+ }
+#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL
+ erts_lc_lock_t have_locks[6];
+ if (locks & ERTS_PROC_LOCK_MAIN)
+ have_locks[have_locks_len++] = p->lock.main.lc;
+ if (locks & ERTS_PROC_LOCK_LINK)
+ have_locks[have_locks_len++] = p->lock.link.lc;
+ if (locks & ERTS_PROC_LOCK_MSGQ)
+ have_locks[have_locks_len++] = p->lock.msgq.lc;
+ if (locks & ERTS_PROC_LOCK_BTM)
+ have_locks[have_locks_len++] = p->lock.btm.lc;
+ if (locks & ERTS_PROC_LOCK_STATUS)
+ have_locks[have_locks_len++] = p->lock.status.lc;
+ if (locks & ERTS_PROC_LOCK_TRACE)
+ have_locks[have_locks_len++] = p->lock.trace.lc;
+#endif
+ erts_lc_check_exact(have_locks, have_locks_len);
+}
+
void
erts_proc_lc_chk_have_proc_locks(Process *p, ErtsProcLocks locks)
{
int have_locks_len = 0;
#if ERTS_PROC_LOCK_OWN_IMPL
- erts_lc_lock_t have_locks[5] = {ERTS_PROC_LC_EMPTY_LOCK_INIT,
+ erts_lc_lock_t have_locks[6] = {ERTS_PROC_LC_EMPTY_LOCK_INIT,
ERTS_PROC_LC_EMPTY_LOCK_INIT,
ERTS_PROC_LC_EMPTY_LOCK_INIT,
+ ERTS_PROC_LC_EMPTY_LOCK_INIT,
ERTS_PROC_LC_EMPTY_LOCK_INIT,
ERTS_PROC_LC_EMPTY_LOCK_INIT};
if (locks & ERTS_PROC_LOCK_MAIN) {
@@ -1486,8 +1582,12 @@ erts_proc_lc_chk_have_proc_locks(Process *p, ErtsProcLocks locks)
have_locks[have_locks_len].id = lc_id.proc_lock_status;
have_locks[have_locks_len++].extra = p->common.id;
}
+ if (locks & ERTS_PROC_LOCK_TRACE) {
+ have_locks[have_locks_len].id = lc_id.proc_lock_trace;
+ have_locks[have_locks_len++].extra = p->common.id;
+ }
#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL
- erts_lc_lock_t have_locks[5];
+ erts_lc_lock_t have_locks[6];
if (locks & ERTS_PROC_LOCK_MAIN)
have_locks[have_locks_len++] = p->lock.main.lc;
if (locks & ERTS_PROC_LOCK_LINK)
@@ -1498,6 +1598,8 @@ erts_proc_lc_chk_have_proc_locks(Process *p, ErtsProcLocks locks)
have_locks[have_locks_len++] = p->lock.btm.lc;
if (locks & ERTS_PROC_LOCK_STATUS)
have_locks[have_locks_len++] = p->lock.status.lc;
+ if (locks & ERTS_PROC_LOCK_TRACE)
+ have_locks[have_locks_len++] = p->lock.trace.lc;
#endif
erts_lc_check(have_locks, have_locks_len, NULL, 0);
}
@@ -1508,12 +1610,14 @@ erts_proc_lc_chk_proc_locks(Process *p, ErtsProcLocks locks)
int have_locks_len = 0;
int have_not_locks_len = 0;
#if ERTS_PROC_LOCK_OWN_IMPL
- erts_lc_lock_t have_locks[5] = {ERTS_PROC_LC_EMPTY_LOCK_INIT,
+ erts_lc_lock_t have_locks[6] = {ERTS_PROC_LC_EMPTY_LOCK_INIT,
ERTS_PROC_LC_EMPTY_LOCK_INIT,
+ ERTS_PROC_LC_EMPTY_LOCK_INIT,
ERTS_PROC_LC_EMPTY_LOCK_INIT,
ERTS_PROC_LC_EMPTY_LOCK_INIT};
- erts_lc_lock_t have_not_locks[5] = {ERTS_PROC_LC_EMPTY_LOCK_INIT,
+ erts_lc_lock_t have_not_locks[6] = {ERTS_PROC_LC_EMPTY_LOCK_INIT,
ERTS_PROC_LC_EMPTY_LOCK_INIT,
+ ERTS_PROC_LC_EMPTY_LOCK_INIT,
ERTS_PROC_LC_EMPTY_LOCK_INIT,
ERTS_PROC_LC_EMPTY_LOCK_INIT};
@@ -1557,9 +1661,17 @@ erts_proc_lc_chk_proc_locks(Process *p, ErtsProcLocks locks)
have_not_locks[have_not_locks_len].id = lc_id.proc_lock_status;
have_not_locks[have_not_locks_len++].extra = p->common.id;
}
+ if (locks & ERTS_PROC_LOCK_TRACE) {
+ have_locks[have_locks_len].id = lc_id.proc_lock_trace;
+ have_locks[have_locks_len++].extra = p->common.id;
+ }
+ else {
+ have_not_locks[have_not_locks_len].id = lc_id.proc_lock_trace;
+ have_not_locks[have_not_locks_len++].extra = p->common.id;
+ }
#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL
- erts_lc_lock_t have_locks[5];
- erts_lc_lock_t have_not_locks[5];
+ erts_lc_lock_t have_locks[6];
+ erts_lc_lock_t have_not_locks[6];
if (locks & ERTS_PROC_LOCK_MAIN)
have_locks[have_locks_len++] = p->lock.main.lc;
@@ -1581,6 +1693,10 @@ erts_proc_lc_chk_proc_locks(Process *p, ErtsProcLocks locks)
have_locks[have_locks_len++] = p->lock.status.lc;
else
have_not_locks[have_not_locks_len++] = p->lock.status.lc;
+ if (locks & ERTS_PROC_LOCK_TRACE)
+ have_locks[have_locks_len++] = p->lock.trace.lc;
+ else
+ have_not_locks[have_not_locks_len++] = p->lock.trace.lc;
#endif
erts_lc_check(have_locks, have_locks_len,
@@ -1590,10 +1706,10 @@ erts_proc_lc_chk_proc_locks(Process *p, ErtsProcLocks locks)
ErtsProcLocks
erts_proc_lc_my_proc_locks(Process *p)
{
- int resv[5];
+ int resv[6];
ErtsProcLocks res = 0;
#if ERTS_PROC_LOCK_OWN_IMPL
- erts_lc_lock_t locks[5] = {ERTS_LC_LOCK_INIT(lc_id.proc_lock_main,
+ erts_lc_lock_t locks[6] = {ERTS_LC_LOCK_INIT(lc_id.proc_lock_main,
p->common.id,
ERTS_LC_FLG_LT_PROCLOCK),
ERTS_LC_LOCK_INIT(lc_id.proc_lock_link,
@@ -1607,16 +1723,20 @@ erts_proc_lc_my_proc_locks(Process *p)
ERTS_LC_FLG_LT_PROCLOCK),
ERTS_LC_LOCK_INIT(lc_id.proc_lock_status,
p->common.id,
+ ERTS_LC_FLG_LT_PROCLOCK),
+ ERTS_LC_LOCK_INIT(lc_id.proc_lock_trace,
+ p->common.id,
ERTS_LC_FLG_LT_PROCLOCK)};
#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL
- erts_lc_lock_t locks[5] = {p->lock.main.lc,
+ erts_lc_lock_t locks[6] = {p->lock.main.lc,
p->lock.link.lc,
p->lock.msgq.lc,
p->lock.btm.lc,
- p->lock.status.lc};
+ p->lock.status.lc,
+ p->lock.trace.lc};
#endif
- erts_lc_have_locks(resv, locks, 5);
+ erts_lc_have_locks(resv, locks, 6);
if (resv[0])
res |= ERTS_PROC_LOCK_MAIN;
if (resv[1])
@@ -1627,6 +1747,8 @@ erts_proc_lc_my_proc_locks(Process *p)
res |= ERTS_PROC_LOCK_BTM;
if (resv[4])
res |= ERTS_PROC_LOCK_STATUS;
+ if (resv[5])
+ res |= ERTS_PROC_LOCK_TRACE;
return res;
}
@@ -1634,14 +1756,15 @@ erts_proc_lc_my_proc_locks(Process *p)
void
erts_proc_lc_chk_no_proc_locks(char *file, int line)
{
- int resv[5];
- int ids[5] = {lc_id.proc_lock_main,
+ int resv[6];
+ int ids[6] = {lc_id.proc_lock_main,
lc_id.proc_lock_link,
lc_id.proc_lock_msgq,
lc_id.proc_lock_btm,
- lc_id.proc_lock_status};
- erts_lc_have_lock_ids(resv, ids, 5);
- if (!ERTS_IS_CRASH_DUMPING && (resv[0] || resv[1] || resv[2] || resv[3] || resv[4])) {
+ lc_id.proc_lock_status,
+ lc_id.proc_lock_trace};
+ erts_lc_have_lock_ids(resv, ids, 6);
+ if (!ERTS_IS_CRASH_DUMPING && (resv[0] || resv[1] || resv[2] || resv[3] || resv[4] || resv[5])) {
erts_lc_fail("%s:%d: Thread has process locks locked when expected "
"not to have any process locks locked",
file, line);
diff --git a/erts/emulator/beam/erl_process_lock.h b/erts/emulator/beam/erl_process_lock.h
index 9c59301086..2cccf0697a 100644
--- a/erts/emulator/beam/erl_process_lock.h
+++ b/erts/emulator/beam/erl_process_lock.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2007-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2007-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.
@@ -66,7 +66,7 @@
#endif
-#define ERTS_PROC_LOCK_MAX_BIT 4
+#define ERTS_PROC_LOCK_MAX_BIT 5
typedef erts_aint32_t ErtsProcLocks;
@@ -84,6 +84,7 @@ typedef struct erts_proc_lock_t_ {
erts_lcnt_lock_t lcnt_msgq;
erts_lcnt_lock_t lcnt_btm;
erts_lcnt_lock_t lcnt_status;
+ erts_lcnt_lock_t lcnt_trace;
#endif
#elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL
erts_mtx_t main;
@@ -91,6 +92,7 @@ typedef struct erts_proc_lock_t_ {
erts_mtx_t msgq;
erts_mtx_t btm;
erts_mtx_t status;
+ erts_mtx_t trace;
#else
# error "no implementation"
#endif
@@ -137,9 +139,18 @@ typedef struct erts_proc_lock_t_ {
* Protects the following fields in the process structure:
* * pending_suspenders
* * suspendee
+ * * sys_tasks
* * ...
*/
-#define ERTS_PROC_LOCK_STATUS (((ErtsProcLocks) 1) << ERTS_PROC_LOCK_MAX_BIT)
+#define ERTS_PROC_LOCK_STATUS (((ErtsProcLocks) 1) << 4)
+
+/*
+ * Trace message lock:
+ * Protects the order in which messages are sent
+ * from trace nifs. This lock is taken inside enif_send.
+ *
+ */
+#define ERTS_PROC_LOCK_TRACE (((ErtsProcLocks) 1) << ERTS_PROC_LOCK_MAX_BIT)
/*
* Special fields:
@@ -154,8 +165,8 @@ typedef struct erts_proc_lock_t_ {
* all process locks are held, and are allowed to be read if
* at least one process lock (whichever one doesn't matter)
* is held:
- * * tracer_proc
- * * tracer_flags
+ * * common.tracer
+ * * common.trace_flags
*
* The following fields are only allowed to be accessed if
* both the schedule queue lock and at least one process lock
@@ -198,17 +209,15 @@ typedef struct erts_proc_lock_t_ {
/* ERTS_PROC_LOCKS_* are combinations of process locks */
-#define ERTS_PROC_LOCKS_MSG_RECEIVE (ERTS_PROC_LOCK_MSGQ \
- | ERTS_PROC_LOCK_STATUS)
-#define ERTS_PROC_LOCKS_MSG_SEND (ERTS_PROC_LOCK_MSGQ \
- | ERTS_PROC_LOCK_STATUS)
+#define ERTS_PROC_LOCKS_MSG_RECEIVE ERTS_PROC_LOCK_MSGQ
+#define ERTS_PROC_LOCKS_MSG_SEND ERTS_PROC_LOCK_MSGQ
#define ERTS_PROC_LOCKS_XSIG_SEND ERTS_PROC_LOCK_STATUS
#define ERTS_PROC_LOCKS_ALL \
((((ErtsProcLocks) 1) << (ERTS_PROC_LOCK_MAX_BIT + 1)) - 1)
#define ERTS_PROC_LOCKS_ALL_MINOR (ERTS_PROC_LOCKS_ALL \
- & ~ERTS_PROC_LOCK_MAIN)
+ & ~ERTS_PROC_LOCK_MAIN)
#define ERTS_PIX_LOCKS_BITS 10
@@ -260,6 +269,7 @@ void erts_proc_lc_might_unlock(Process *p, ErtsProcLocks locks);
void erts_proc_lc_chk_have_proc_locks(Process *p, ErtsProcLocks locks);
void erts_proc_lc_chk_proc_locks(Process *p, ErtsProcLocks locks);
void erts_proc_lc_chk_only_proc_main(Process *p);
+void erts_proc_lc_chk_only_proc(Process *p, ErtsProcLocks locks);
void erts_proc_lc_chk_no_proc_locks(char *file, int line);
ErtsProcLocks erts_proc_lc_my_proc_locks(Process *p);
int erts_proc_lc_trylock_force_busy(Process *p, ErtsProcLocks locks);
@@ -477,9 +487,15 @@ erts_smp_proc_raw_trylock__(Process *p, ErtsProcLocks locks)
if (locks & ERTS_PROC_LOCK_STATUS)
if (erts_mtx_trylock(&p->lock.status) == EBUSY)
goto busy_status;
+ if (locks & ERTS_PROC_LOCK_TRACE)
+ if (erts_mtx_trylock(&p->lock.trace) == EBUSY)
+ goto busy_trace;
return 0;
+busy_trace:
+ if (locks & ERTS_PROC_LOCK_TRACE)
+ erts_mtx_unlock(&p->lock.trace);
busy_status:
if (locks & ERTS_PROC_LOCK_BTM)
erts_mtx_unlock(&p->lock.btm);
@@ -568,6 +584,8 @@ erts_smp_proc_lock__(Process *p,
erts_mtx_lock(&p->lock.btm);
if (locks & ERTS_PROC_LOCK_STATUS)
erts_mtx_lock(&p->lock.status);
+ if (locks & ERTS_PROC_LOCK_TRACE)
+ erts_mtx_lock(&p->lock.trace);
#ifdef ERTS_PROC_LOCK_DEBUG
erts_proc_lock_op_debug(p, locks, 1);
@@ -653,6 +671,8 @@ erts_smp_proc_unlock__(Process *p,
erts_proc_lock_op_debug(p, locks, 0);
#endif
+ if (locks & ERTS_PROC_LOCK_TRACE)
+ erts_mtx_unlock(&p->lock.trace);
if (locks & ERTS_PROC_LOCK_STATUS)
erts_mtx_unlock(&p->lock.status);
if (locks & ERTS_PROC_LOCK_BTM)
diff --git a/erts/emulator/beam/erl_ptab.c b/erts/emulator/beam/erl_ptab.c
index 9ed175fe01..22830a19c4 100644
--- a/erts/emulator/beam/erl_ptab.c
+++ b/erts/emulator/beam/erl_ptab.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2012-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2012-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.
diff --git a/erts/emulator/beam/erl_ptab.h b/erts/emulator/beam/erl_ptab.h
index 8fd961e3ce..a5931ffc25 100644
--- a/erts/emulator/beam/erl_ptab.h
+++ b/erts/emulator/beam/erl_ptab.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2012-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2012-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.
@@ -37,14 +37,16 @@
#include "erl_alloc.h"
#include "erl_monitors.h"
-#define ERTS_TRACER_PROC(P) ((P)->common.tracer_proc)
+#define ERTS_TRACER(P) ((P)->common.tracer)
+#define ERTS_TRACER_MODULE(T) (CAR(list_val(T)))
+#define ERTS_TRACER_STATE(T) (CDR(list_val(T)))
#define ERTS_TRACE_FLAGS(P) ((P)->common.trace_flags)
#define ERTS_P_LINKS(P) ((P)->common.u.alive.links)
#define ERTS_P_MONITORS(P) ((P)->common.u.alive.monitors)
#define IS_TRACED(p) \
- (ERTS_TRACER_PROC((p)) != NIL)
+ (ERTS_TRACER(p) != NIL)
#define ARE_TRACE_FLAGS_ON(p,tf) \
((ERTS_TRACE_FLAGS((p)) & (tf|F_SENSITIVE)) == (tf))
#define IS_TRACED_FL(p,tf) \
@@ -56,7 +58,7 @@ typedef struct {
erts_atomic_t atmc;
Sint sint;
} refc;
- Eterm tracer_proc;
+ ErtsTracer tracer;
Uint trace_flags;
erts_smp_atomic_t timer;
union {
diff --git a/erts/emulator/beam/erl_sched_spec_pre_alloc.c b/erts/emulator/beam/erl_sched_spec_pre_alloc.c
index caec24bc03..cab4bd73db 100644
--- a/erts/emulator/beam/erl_sched_spec_pre_alloc.c
+++ b/erts/emulator/beam/erl_sched_spec_pre_alloc.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
diff --git a/erts/emulator/beam/erl_sched_spec_pre_alloc.h b/erts/emulator/beam/erl_sched_spec_pre_alloc.h
index 4d07b0f674..7808d7d438 100644
--- a/erts/emulator/beam/erl_sched_spec_pre_alloc.h
+++ b/erts/emulator/beam/erl_sched_spec_pre_alloc.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
diff --git a/erts/emulator/beam/erl_smp.h b/erts/emulator/beam/erl_smp.h
index 5fc5e989a6..713ed50b86 100644
--- a/erts/emulator/beam/erl_smp.h
+++ b/erts/emulator/beam/erl_smp.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/beam/erl_sock.h b/erts/emulator/beam/erl_sock.h
index 7be6062115..3429a52d7e 100644
--- a/erts/emulator/beam/erl_sock.h
+++ b/erts/emulator/beam/erl_sock.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/beam/erl_sys_driver.h b/erts/emulator/beam/erl_sys_driver.h
index 4031eef0aa..d46e88cb05 100644
--- a/erts/emulator/beam/erl_sys_driver.h
+++ b/erts/emulator/beam/erl_sys_driver.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/beam/erl_term.c b/erts/emulator/beam/erl_term.c
index d2343912b4..7d857ad326 100644
--- a/erts/emulator/beam/erl_term.c
+++ b/erts/emulator/beam/erl_term.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2000-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2000-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.
@@ -59,96 +59,6 @@ erts_set_literal_tag(Eterm *term, Eterm *hp_start, Eterm hsz)
#endif
}
-__decl_noreturn static void __noreturn
-et_abort(const char *expr, const char *file, unsigned line)
-{
-#ifdef EXIT_ON_ET_ABORT
- static int have_been_called = 0;
-
- if (have_been_called) {
- abort();
- } else {
- /*
- * Prevent infinite loop.
- */
- have_been_called = 1;
- erts_exit(ERTS_ERROR_EXIT, "TYPE ASSERTION FAILED, file %s, line %u: %s\n", file, line, expr);
- }
-#else
- erts_fprintf(stderr, "TYPE ASSERTION FAILED, file %s, line %u: %s\n", file, line, expr);
- abort();
-#endif
-}
-
-#if ET_DEBUG
-#define ET_ASSERT(expr,file,line) \
-do { \
- if (!(expr)) \
- et_abort(#expr, file, line); \
-} while(0)
-#else
-#define ET_ASSERT(expr,file,line) do { } while(0)
-#endif
-
-#if ET_DEBUG
-unsigned tag_val_def_debug(Wterm x, const char *file, unsigned line)
-#else
-unsigned tag_val_def(Wterm x)
-#define file __FILE__
-#define line __LINE__
-#endif
-{
- static char msg[32];
-
- switch (x & _TAG_PRIMARY_MASK) {
- case TAG_PRIMARY_LIST:
- ET_ASSERT(_list_precond(x),file,line);
- return LIST_DEF;
- case TAG_PRIMARY_BOXED: {
- Eterm hdr = *boxed_val(x);
- ET_ASSERT(is_header(hdr),file,line);
- switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) {
- case (_TAG_HEADER_ARITYVAL >> _TAG_PRIMARY_SIZE): return TUPLE_DEF;
- case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): return BIG_DEF;
- case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): return BIG_DEF;
- case (_TAG_HEADER_REF >> _TAG_PRIMARY_SIZE): return REF_DEF;
- case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): return FLOAT_DEF;
- case (_TAG_HEADER_EXPORT >> _TAG_PRIMARY_SIZE): return EXPORT_DEF;
- case (_TAG_HEADER_FUN >> _TAG_PRIMARY_SIZE): return FUN_DEF;
- case (_TAG_HEADER_EXTERNAL_PID >> _TAG_PRIMARY_SIZE): return EXTERNAL_PID_DEF;
- case (_TAG_HEADER_EXTERNAL_PORT >> _TAG_PRIMARY_SIZE): return EXTERNAL_PORT_DEF;
- case (_TAG_HEADER_EXTERNAL_REF >> _TAG_PRIMARY_SIZE): return EXTERNAL_REF_DEF;
- case (_TAG_HEADER_MAP >> _TAG_PRIMARY_SIZE): return MAP_DEF;
- case (_TAG_HEADER_REFC_BIN >> _TAG_PRIMARY_SIZE): return BINARY_DEF;
- case (_TAG_HEADER_HEAP_BIN >> _TAG_PRIMARY_SIZE): return BINARY_DEF;
- case (_TAG_HEADER_SUB_BIN >> _TAG_PRIMARY_SIZE): return BINARY_DEF;
- case (_TAG_HEADER_BIN_MATCHSTATE >> _TAG_PRIMARY_SIZE): return MATCHSTATE_DEF;
- }
-
- break;
- }
- case TAG_PRIMARY_IMMED1: {
- switch ((x & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
- case (_TAG_IMMED1_PID >> _TAG_PRIMARY_SIZE): return PID_DEF;
- case (_TAG_IMMED1_PORT >> _TAG_PRIMARY_SIZE): return PORT_DEF;
- case (_TAG_IMMED1_IMMED2 >> _TAG_PRIMARY_SIZE): {
- switch ((x & _TAG_IMMED2_MASK) >> _TAG_IMMED1_SIZE) {
- case (_TAG_IMMED2_ATOM >> _TAG_IMMED1_SIZE): return ATOM_DEF;
- case (_TAG_IMMED2_NIL >> _TAG_IMMED1_SIZE): return NIL_DEF;
- }
- break;
- }
- case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): return SMALL_DEF;
- }
- break;
- }
- }
- erts_snprintf(msg, sizeof(msg), "tag_val_def: %#lx", (unsigned long) x);
- et_abort(msg, file, line);
-#undef file
-#undef line
-}
-
/*
* XXX: define NUMBER_CODE() here when new representation is used
*/
diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h
index 2b28762db5..c3234ee349 100644
--- a/erts/emulator/beam/erl_term.h
+++ b/erts/emulator/beam/erl_term.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2000-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2000-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.
@@ -558,14 +558,6 @@ _ET_DECLARE_CHECKED(Eterm*,tuple_val,Wterm)
#define _GETBITS(X,Pos,Size) (((X) >> (Pos)) & ~(~((Uint) 0) << (Size)))
-/*
- * Creation in node specific data (pids, ports, refs)
- */
-
-#define _CRE_SIZE 2
-
-/* MAX value for the creation field in pid, port and reference */
-#define MAX_CREATION (1 << _CRE_SIZE)
/*
* PID layout (internal pids):
@@ -579,7 +571,7 @@ _ET_DECLARE_CHECKED(Eterm*,tuple_val,Wterm)
*
* n : number
*
- * Old pid layout:
+ * Very old pid layout:
*
* |3 3 2 2 2 2 2 2|2 2 2 2 1 1 1 1|1 1 1 1 1 1 | |
* |1 0 9 8 7 6 5 4|3 2 1 0 9 8 7 6|5 4 3 2 1 0 9 8|7 6 5 4 3 2 1 0|
@@ -1129,11 +1121,11 @@ _ET_DECLARE_CHECKED(Uint,loader_y_reg_index,Uint)
#define FIRST_VACANT_TAG_DEF 0x12
#if ET_DEBUG
-extern unsigned tag_val_def_debug(Wterm, const char*, unsigned);
-#define tag_val_def(x) tag_val_def_debug((x),__FILE__,__LINE__)
+ERTS_GLB_INLINE unsigned tag_val_def(Wterm, const char*, unsigned);
#else
-extern unsigned tag_val_def(Wterm);
+ERTS_GLB_INLINE unsigned tag_val_def(Wterm);
#endif
+
#define not_eq_tags(X,Y) (tag_val_def((X)) ^ tag_val_def((Y)))
#define NUMBER_CODE(x,y) ((tag_val_def(x) << 5) | tag_val_def(y))
@@ -1152,5 +1144,80 @@ extern unsigned tag_val_def(Wterm);
void erts_set_literal_tag(Eterm *term, Eterm *hp_start, Eterm hsz);
+#if ET_DEBUG
+#define ET_ASSERT(expr,file,line) \
+do { \
+ if (!(expr)) \
+ erl_assert_error("TYPE ASSERTION: " #expr, __FUNCTION__, file, line); \
+} while(0)
+#else
+#define ET_ASSERT(expr,file,line) do { } while(0)
+#endif
+
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+
+#if ET_DEBUG
+ERTS_GLB_INLINE unsigned tag_val_def(Wterm x, const char *file, unsigned line)
+#else
+ERTS_GLB_INLINE unsigned tag_val_def(Wterm x)
+#define file __FILE__
+#define line __LINE__
+#endif
+{
+ static char *msg = "tag_val_def error";
+
+ switch (x & _TAG_PRIMARY_MASK) {
+ case TAG_PRIMARY_LIST:
+ ET_ASSERT(_list_precond(x),file,line);
+ return LIST_DEF;
+ case TAG_PRIMARY_BOXED: {
+ Eterm hdr = *boxed_val(x);
+ ET_ASSERT(is_header(hdr),file,line);
+ switch ((hdr & _TAG_HEADER_MASK) >> _TAG_PRIMARY_SIZE) {
+ case (_TAG_HEADER_ARITYVAL >> _TAG_PRIMARY_SIZE): return TUPLE_DEF;
+ case (_TAG_HEADER_POS_BIG >> _TAG_PRIMARY_SIZE): return BIG_DEF;
+ case (_TAG_HEADER_NEG_BIG >> _TAG_PRIMARY_SIZE): return BIG_DEF;
+ case (_TAG_HEADER_REF >> _TAG_PRIMARY_SIZE): return REF_DEF;
+ case (_TAG_HEADER_FLOAT >> _TAG_PRIMARY_SIZE): return FLOAT_DEF;
+ case (_TAG_HEADER_EXPORT >> _TAG_PRIMARY_SIZE): return EXPORT_DEF;
+ case (_TAG_HEADER_FUN >> _TAG_PRIMARY_SIZE): return FUN_DEF;
+ case (_TAG_HEADER_EXTERNAL_PID >> _TAG_PRIMARY_SIZE): return EXTERNAL_PID_DEF;
+ case (_TAG_HEADER_EXTERNAL_PORT >> _TAG_PRIMARY_SIZE): return EXTERNAL_PORT_DEF;
+ case (_TAG_HEADER_EXTERNAL_REF >> _TAG_PRIMARY_SIZE): return EXTERNAL_REF_DEF;
+ case (_TAG_HEADER_MAP >> _TAG_PRIMARY_SIZE): return MAP_DEF;
+ case (_TAG_HEADER_REFC_BIN >> _TAG_PRIMARY_SIZE): return BINARY_DEF;
+ case (_TAG_HEADER_HEAP_BIN >> _TAG_PRIMARY_SIZE): return BINARY_DEF;
+ case (_TAG_HEADER_SUB_BIN >> _TAG_PRIMARY_SIZE): return BINARY_DEF;
+ case (_TAG_HEADER_BIN_MATCHSTATE >> _TAG_PRIMARY_SIZE): return MATCHSTATE_DEF;
+ }
+
+ break;
+ }
+ case TAG_PRIMARY_IMMED1: {
+ switch ((x & _TAG_IMMED1_MASK) >> _TAG_PRIMARY_SIZE) {
+ case (_TAG_IMMED1_PID >> _TAG_PRIMARY_SIZE): return PID_DEF;
+ case (_TAG_IMMED1_PORT >> _TAG_PRIMARY_SIZE): return PORT_DEF;
+ case (_TAG_IMMED1_IMMED2 >> _TAG_PRIMARY_SIZE): {
+ switch ((x & _TAG_IMMED2_MASK) >> _TAG_IMMED1_SIZE) {
+ case (_TAG_IMMED2_ATOM >> _TAG_IMMED1_SIZE): return ATOM_DEF;
+ case (_TAG_IMMED2_NIL >> _TAG_IMMED1_SIZE): return NIL_DEF;
+ }
+ break;
+ }
+ case (_TAG_IMMED1_SMALL >> _TAG_PRIMARY_SIZE): return SMALL_DEF;
+ }
+ break;
+ }
+ }
+ erl_assert_error(msg, __FUNCTION__, file, line);
+#undef file
+#undef line
+}
+#endif
+
+#if ET_DEBUG
+#define tag_val_def(X) tag_val_def(X, __FILE__, __LINE__)
+#endif
+
#endif /* __ERL_TERM_H */
diff --git a/erts/emulator/beam/erl_thr_progress.c b/erts/emulator/beam/erl_thr_progress.c
index 7b06fd840f..542541165b 100644
--- a/erts/emulator/beam/erl_thr_progress.c
+++ b/erts/emulator/beam/erl_thr_progress.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
diff --git a/erts/emulator/beam/erl_thr_progress.h b/erts/emulator/beam/erl_thr_progress.h
index b89cc4c267..b2894ba1fe 100644
--- a/erts/emulator/beam/erl_thr_progress.h
+++ b/erts/emulator/beam/erl_thr_progress.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
diff --git a/erts/emulator/beam/erl_thr_queue.c b/erts/emulator/beam/erl_thr_queue.c
index 7ff456b915..f56d0828dd 100644
--- a/erts/emulator/beam/erl_thr_queue.c
+++ b/erts/emulator/beam/erl_thr_queue.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
@@ -780,3 +780,35 @@ erts_thr_q_dequeue(ErtsThrQ_t *q)
return res;
#endif
}
+
+#ifdef USE_LTTNG_VM_TRACEPOINTS
+int
+erts_thr_q_length_dirty(ErtsThrQ_t *q)
+{
+ int n = 0;
+#ifndef USE_THREADS
+ void *res;
+ ErtsThrQElement_t *tmp;
+
+ for (tmp = q->first; tmp != NULL; tmp = tmp->next) {
+ n++;
+ }
+#else
+ ErtsThrQElement_t *e;
+ erts_aint_t inext;
+
+ e = ErtsThrQDirtyReadEl(&q->head.head);
+ inext = erts_atomic_read_acqb(&e->next);
+
+ while (inext != ERTS_AINT_NULL) {
+ e = (ErtsThrQElement_t *) inext;
+ if (e != &q->tail.data.marker) {
+ /* don't count marker */
+ n++;
+ }
+ inext = erts_atomic_read_acqb(&e->next);
+ }
+#endif
+ return n;
+}
+#endif
diff --git a/erts/emulator/beam/erl_thr_queue.h b/erts/emulator/beam/erl_thr_queue.h
index 27a6d03224..705a67af4c 100644
--- a/erts/emulator/beam/erl_thr_queue.h
+++ b/erts/emulator/beam/erl_thr_queue.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
@@ -190,6 +190,10 @@ void erts_thr_q_append_finalize_dequeue_data(ErtsThrQFinDeQ_t *,
int erts_thr_q_finalize_dequeue(ErtsThrQFinDeQ_t *);
void erts_thr_q_finalize_dequeue_state_init(ErtsThrQFinDeQ_t *);
+#ifdef USE_LTTNG_VM_TRACEPOINTS
+int erts_thr_q_length_dirty(ErtsThrQ_t *);
+#endif
+
#ifdef ERTS_SMP
ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_q_need_thr_progress(ErtsThrQ_t *q);
#endif
diff --git a/erts/emulator/beam/erl_threads.h b/erts/emulator/beam/erl_threads.h
index e689547d1d..eccd49f2a9 100644
--- a/erts/emulator/beam/erl_threads.h
+++ b/erts/emulator/beam/erl_threads.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/beam/erl_time.h b/erts/emulator/beam/erl_time.h
index 5242063550..a1c4220633 100644
--- a/erts/emulator/beam/erl_time.h
+++ b/erts/emulator/beam/erl_time.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c
index f3f528eaf6..fadbd704bd 100644
--- a/erts/emulator/beam/erl_time_sup.c
+++ b/erts/emulator/beam/erl_time_sup.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2015. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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.
@@ -1966,7 +1966,7 @@ send_time_offset_changed_notifications(void *new_offsetp)
*patch_refp = ref;
ASSERT(hsz == size_object(message_template));
message = copy_struct(message_template, hsz, &hp, ohp);
- erts_queue_message(rp, &rp_locks, mp, message, NIL);
+ erts_queue_message(rp, rp_locks, mp, message, am_clock_service);
}
erts_smp_proc_unlock(rp, rp_locks);
}
diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c
index 41876b8c62..1c0fc0a11f 100644
--- a/erts/emulator/beam/erl_trace.c
+++ b/erts/emulator/beam/erl_trace.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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.
@@ -20,6 +20,19 @@
/*
* Support functions for tracing.
+ *
+ * Ideas for future speed improvements in tracing framework:
+ * * Move ErtsTracerNif into ErtsTracer
+ * + Removes need for locking
+ * + Removes hash lookup overhead
+ * + Use a refc on the ErtsTracerNif to know when it can
+ * be freed. We don't want to allocate a separate
+ * ErtsTracerNif for each module used.
+ * * Optimize GenericBp for cache locality by reusing equivalent
+ * GenericBp and GenericBpData in multiple tracer points.
+ * + Possibly we want to use specialized instructions for different
+ * types of trace so that the knowledge of which struct is used
+ * can be in the instruction.
*/
#ifdef HAVE_CONFIG_H
@@ -39,6 +52,7 @@
#include "erl_bits.h"
#include "erl_thr_progress.h"
#include "erl_bif_unique.h"
+#include "erl_map.h"
#if 0
#define DEBUG_PRINTOUTS
@@ -46,17 +60,15 @@
#undef DEBUG_PRINTOUTS
#endif
-extern BeamInstr beam_return_to_trace[1]; /* OpCode(i_return_to_trace) */
-extern BeamInstr beam_return_trace[1]; /* OpCode(i_return_trace) */
-extern BeamInstr beam_return_time_trace[1]; /* OpCode(i_return_time_trace) */
-
/* Pseudo export entries. Never filled in with data, only used to
yield unique pointers of the correct type. */
Export exp_send, exp_receive, exp_timeout;
-static Eterm system_seq_tracer;
-static Uint default_trace_flags;
-static Eterm default_tracer;
+static ErtsTracer system_seq_tracer;
+static Uint default_proc_trace_flags;
+static ErtsTracer default_proc_tracer;
+static Uint default_port_trace_flags;
+static ErtsTracer default_port_tracer;
static Eterm system_monitor;
static Eterm system_profile;
@@ -70,8 +82,6 @@ static erts_smp_rwmtx_t sys_trace_rwmtx;
enum ErtsSysMsgType {
SYS_MSG_TYPE_UNDEFINED,
- SYS_MSG_TYPE_TRACE,
- SYS_MSG_TYPE_SEQTRACE,
SYS_MSG_TYPE_SYSMON,
SYS_MSG_TYPE_ERRLGR,
SYS_MSG_TYPE_PROC_MSG,
@@ -176,7 +186,7 @@ take_timestamp(ErtsTraceTimeStamp *tsp, int ts_type)
hsz += 3; /* 2-tuple */
raw_unique = erts_raw_get_unique_monotonic_integer();
tsp->u.monotonic.raw_unique = raw_unique;
- hsz += erts_raw_unique_monotonic_integer_heap_size(raw_unique);
+ hsz += erts_raw_unique_monotonic_integer_heap_size(raw_unique, 0);
}
return hsz;
}
@@ -216,8 +226,7 @@ write_timestamp(ErtsTraceTimeStamp *tsp, Eterm **hpp)
return emtime;
raw = tsp->u.monotonic.raw_unique;
- unique = erts_raw_make_unique_monotonic_integer_value(hpp,
- raw);
+ unique = erts_raw_make_unique_monotonic_integer_value(hpp, raw, 0);
res = TUPLE2(*hpp, emtime, unique);
*hpp += 3;
return res;
@@ -228,7 +237,7 @@ write_timestamp(ErtsTraceTimeStamp *tsp, Eterm **hpp)
}
}
-#define PATCH_TS_SIZE(p) patch_ts_size(TFLGS_TS_TYPE(p))
+#ifdef ERTS_SMP
static ERTS_INLINE Uint
patch_ts_size(int ts_type)
@@ -248,6 +257,7 @@ patch_ts_size(int ts_type)
return 0;
}
}
+#endif /* ERTS_SMP */
/*
* Write a timestamp. The timestamp MUST be the last
@@ -299,43 +309,6 @@ write_ts(int ts_type, Eterm *hp, ErlHeapFragment *bp, Process *tracer)
return res;
}
-/*
- * Patch a timestamp into a tuple. The tuple MUST be the last thing
- * built on the heap before the call, and the timestamp MUST be
- * the last thing after the call. This since patch_ts() might adjust
- * the size of the used area.
- */
-
-#define PATCH_TS__(Type, Tuple, Hp, Bp, Tracer) \
- do { \
- int ts_type__ = (Type); \
- if (ts_type__) \
- patch_ts(ts_type__, (Tuple), (Hp), (Bp), (Tracer)); \
- } while (0)
-
-#ifdef ERTS_SMP
-#define PATCH_TS(Type, Tuple, Hp, Bp, Tracer) \
- PATCH_TS__((Type), (Tuple), (Hp), (Bp), NULL)
-#else
-#define PATCH_TS(Type, Tuple, Hp, Bp, Tracer) \
- PATCH_TS__((Type), (Tuple), (Hp), (Bp), (Tracer))
-#endif
-
-static ERTS_INLINE void
-patch_ts(int ts_type, Eterm tuple, Eterm* hp, ErlHeapFragment *bp, Process *tracer)
-{
- Eterm *tptr = tuple_val(tuple);
- int arity = arityval(*tptr);
-
- ASSERT(ts_type);
- ASSERT((tptr+arity+1) == hp);
-
- tptr[0] = make_arityval(arity+1);
- tptr[1] = am_trace_ts;
-
- *hp = write_ts(ts_type, hp+1, bp, tracer);
-}
-
#ifdef ERTS_SMP
static void enqueue_sys_msg_unlocked(enum ErtsSysMsgType type,
Eterm from,
@@ -350,6 +323,14 @@ static void enqueue_sys_msg(enum ErtsSysMsgType type,
static void init_sys_msg_dispatcher(void);
#endif
+static void init_tracer_nif(void);
+static int tracer_cmp_fun(void*, void*);
+static HashValue tracer_hash_fun(void*);
+static void *tracer_alloc_fun(void*);
+static void tracer_free_fun(void*);
+
+typedef struct ErtsTracerNif_ ErtsTracerNif;
+
void erts_init_trace(void) {
erts_smp_rwmtx_opt_t rwmtx_opts = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER;
rwmtx_opts.type = ERTS_SMP_RWMTX_TYPE_EXTREMELY_FREQUENT_READ;
@@ -363,80 +344,67 @@ void erts_init_trace(void) {
erts_bif_trace_init();
erts_system_monitor_clear(NULL);
erts_system_profile_clear(NULL);
- default_trace_flags = F_INITIAL_TRACE_FLAGS;
- default_tracer = NIL;
- system_seq_tracer = am_false;
+ default_proc_trace_flags = F_INITIAL_TRACE_FLAGS;
+ default_proc_tracer = erts_tracer_nil;
+ default_port_trace_flags = F_INITIAL_TRACE_FLAGS;
+ default_port_tracer = erts_tracer_nil;
+ system_seq_tracer = erts_tracer_nil;
#ifdef ERTS_SMP
init_sys_msg_dispatcher();
#endif
+ init_tracer_nif();
}
-static Eterm system_seq_tracer;
-
#define ERTS_ALLOC_SYSMSG_HEAP(SZ, BPP, OHPP, UNUSED) \
(*(BPP) = new_message_buffer((SZ)), \
*(OHPP) = &(*(BPP))->off_heap, \
(*(BPP))->mem)
-#ifdef ERTS_SMP
-#define ERTS_ENQ_TRACE_MSG(FPID, TPID, MSG, BP) \
-do { \
- ERTS_LC_ASSERT(erts_smp_lc_mtx_is_locked(&smq_mtx)); \
- enqueue_sys_msg_unlocked(SYS_MSG_TYPE_TRACE, (FPID), (TPID), (MSG), (BP)); \
-} while(0)
-#else
-#define ERTS_ENQ_TRACE_MSG(FPID, TPROC, MSG, BP) \
- do { \
- ErtsMessage *mp__ = erts_alloc_message(0, NULL); \
- mp__->data.heap_frag = (BP); \
- erts_queue_message((TPROC), NULL, mp__, (MSG), NIL); \
- } while (0)
-#endif
+enum ErtsTracerOpt {
+ TRACE_FUN_DEFAULT = 0,
+ TRACE_FUN_ENABLED = 1,
+ TRACE_FUN_T_SEND = 2,
+ TRACE_FUN_T_RECEIVE = 3,
+ TRACE_FUN_T_CALL = 4,
+ TRACE_FUN_T_SCHED_PROC = 5,
+ TRACE_FUN_T_SCHED_PORT = 6,
+ TRACE_FUN_T_GC = 7,
+ TRACE_FUN_T_PROCS = 8,
+ TRACE_FUN_T_PORTS = 9,
+ TRACE_FUN_E_SEND = 10,
+ TRACE_FUN_E_RECEIVE = 11,
+ TRACE_FUN_E_CALL = 12,
+ TRACE_FUN_E_SCHED_PROC = 13,
+ TRACE_FUN_E_SCHED_PORT = 14,
+ TRACE_FUN_E_GC = 15,
+ TRACE_FUN_E_PROCS = 16,
+ TRACE_FUN_E_PORTS = 17
+};
-/*
- * NOTE that the ERTS_GET_TRACER_REF() returns from the function (!!!)
- * using it, and resets the parameters used if the tracer is invalid, i.e.,
- * use it with extreme care!
- */
-#ifdef ERTS_SMP
-#define ERTS_NULL_TRACER_REF NIL
-#define ERTS_TRACER_REF_TYPE Eterm
- /* In the smp case, we never find the tracer invalid here (the sys
- message dispatcher thread takes care of that). */
-#define ERTS_GET_TRACER_REF(RES, TPID, TRACEE_FLGS) \
-do { (RES) = (TPID); } while(0)
-int
-erts_is_tracer_proc_valid(Process* p)
-{
- return 1;
-}
-#else
-#define ERTS_NULL_TRACER_REF NULL
-#define ERTS_TRACER_REF_TYPE Process *
-#define ERTS_GET_TRACER_REF(RES, TPID, TRACEE_FLGS) \
-do { \
- (RES) = erts_proc_lookup((TPID)); \
- if (!(RES) || !(ERTS_TRACE_FLAGS((RES)) & F_TRACER)) { \
- (TPID) = NIL; \
- (TRACEE_FLGS) &= ~TRACEE_FLAGS; \
- return; \
- } \
-} while (0)
-int
-erts_is_tracer_proc_valid(Process* p)
-{
- Process* tracer;
+#define NIF_TRACER_TYPES (18)
- tracer = erts_proc_lookup(ERTS_TRACER_PROC(p));
- if (tracer && ERTS_TRACE_FLAGS(tracer) & F_TRACER) {
- return 1;
- } else {
- ERTS_TRACER_PROC(p) = NIL;
- ERTS_TRACE_FLAGS(p) = ~TRACEE_FLAGS;
- return 0;
- }
-}
-#endif
+
+static ERTS_INLINE int
+send_to_tracer_nif_raw(Process *c_p, Process *tracee, const ErtsTracer tracer,
+ Uint trace_flags, Eterm t_p_id, ErtsTracerNif *tnif,
+ enum ErtsTracerOpt topt,
+ Eterm tag, Eterm msg, Eterm extra, Eterm pam_result);
+static ERTS_INLINE int
+send_to_tracer_nif(Process *c_p, ErtsPTabElementCommon *t_p,
+ Eterm t_p_id, ErtsTracerNif *tnif,
+ enum ErtsTracerOpt topt,
+ Eterm tag, Eterm msg, Eterm extra,
+ Eterm pam_result);
+static ERTS_INLINE Eterm
+call_enabled_tracer(Process *c_p, const ErtsTracer tracer,
+ ErtsTracerNif **tnif_ref,
+ enum ErtsTracerOpt topt,
+ Eterm tag, Eterm t_p_id);
+static int
+is_tracer_enabled(Process* c_p, ErtsProcLocks c_p_locks,
+ ErtsPTabElementCommon *t_p,
+ ErtsTracerNif **tnif_ret,
+ enum ErtsTracerOpt topt, Eterm tag);
static Uint active_sched;
@@ -451,19 +419,6 @@ static void
exiting_reset(Eterm exiting)
{
erts_smp_rwmtx_rwlock(&sys_trace_rwmtx);
- if (exiting == default_tracer) {
- default_tracer = NIL;
- default_trace_flags &= TRACEE_FLAGS;
-#ifdef DEBUG
- default_trace_flags |= F_INITIAL_TRACE_FLAGS;
-#endif
- }
- if (exiting == system_seq_tracer) {
-#ifdef DEBUG_PRINTOUTS
- erts_fprintf(stderr, "seq tracer %T exited\n", exiting);
-#endif
- system_seq_tracer = am_false;
- }
if (exiting == system_monitor) {
#ifdef ERTS_SMP
system_monitor = NIL;
@@ -488,11 +443,7 @@ erts_trace_check_exiting(Eterm exiting)
{
int reset = 0;
erts_smp_rwmtx_rlock(&sys_trace_rwmtx);
- if (exiting == default_tracer)
- reset = 1;
- else if (exiting == system_seq_tracer)
- reset = 1;
- else if (exiting == system_monitor)
+ if (exiting == system_monitor)
reset = 1;
else if (exiting == system_profile)
reset = 1;
@@ -501,23 +452,26 @@ erts_trace_check_exiting(Eterm exiting)
exiting_reset(exiting);
}
-static ERTS_INLINE int
-is_valid_tracer(Eterm tracer)
+ErtsTracer
+erts_set_system_seq_tracer(Process *c_p, ErtsProcLocks c_p_locks, ErtsTracer new)
{
- return erts_proc_lookup(tracer) || erts_is_valid_tracer_port(tracer);
-}
+ ErtsTracer old;
-Eterm
-erts_set_system_seq_tracer(Process *c_p, ErtsProcLocks c_p_locks, Eterm new)
-{
- Eterm old;
-
- if (new != am_false && !is_valid_tracer(new))
- return THE_NON_VALUE;
+ if (!ERTS_TRACER_IS_NIL(new)) {
+ Eterm nif_result = call_enabled_tracer(
+ NULL, new, NULL,
+ TRACE_FUN_ENABLED, am_trace_status, am_undefined);
+ switch (nif_result) {
+ case am_trace: break;
+ default:
+ return THE_NON_VALUE;
+ }
+ }
erts_smp_rwmtx_rwlock(&sys_trace_rwmtx);
old = system_seq_tracer;
- system_seq_tracer = new;
+ system_seq_tracer = erts_tracer_nil;
+ erts_tracer_update(&system_seq_tracer, new);
#ifdef DEBUG_PRINTOUTS
erts_fprintf(stderr, "set seq tracer new=%T old=%T\n", new, old);
@@ -526,66 +480,134 @@ erts_set_system_seq_tracer(Process *c_p, ErtsProcLocks c_p_locks, Eterm new)
return old;
}
-Eterm
+ErtsTracer
erts_get_system_seq_tracer(void)
{
- Eterm st;
+ ErtsTracer st;
erts_smp_rwmtx_rlock(&sys_trace_rwmtx);
st = system_seq_tracer;
#ifdef DEBUG_PRINTOUTS
erts_fprintf(stderr, "get seq tracer %T\n", st);
#endif
erts_smp_rwmtx_runlock(&sys_trace_rwmtx);
+
+ if (st != erts_tracer_nil &&
+ call_enabled_tracer(NULL, st, NULL, TRACE_FUN_ENABLED,
+ am_trace_status, am_undefined) == am_remove) {
+ erts_set_system_seq_tracer(NULL, 0, erts_tracer_nil);
+ st = erts_tracer_nil;
+ }
+
return st;
}
static ERTS_INLINE void
-get_default_tracing(Uint *flagsp, Eterm *tracerp)
-{
- if (!(default_trace_flags & TRACEE_FLAGS))
- default_tracer = NIL;
-
- if (is_nil(default_tracer)) {
- default_trace_flags &= ~TRACEE_FLAGS;
- } else if (is_internal_pid(default_tracer)) {
- if (!erts_proc_lookup(default_tracer)) {
- reset_tracer:
- default_trace_flags &= ~TRACEE_FLAGS;
- default_tracer = NIL;
- }
+get_default_tracing(Uint *flagsp, ErtsTracer *tracerp,
+ Uint *default_trace_flags,
+ ErtsTracer *default_tracer)
+{
+ if (!(*default_trace_flags & TRACEE_FLAGS))
+ ERTS_TRACER_CLEAR(default_tracer);
+
+ if (ERTS_TRACER_IS_NIL(*default_tracer)) {
+ *default_trace_flags &= ~TRACEE_FLAGS;
} else {
- ASSERT(is_internal_port(default_tracer));
- if (!erts_is_valid_tracer_port(default_tracer))
- goto reset_tracer;
+ Eterm nif_res;
+ nif_res = call_enabled_tracer(NULL, *default_tracer,
+ NULL, TRACE_FUN_ENABLED,
+ am_trace_status, am_undefined);
+ switch (nif_res) {
+ case am_trace: break;
+ default: {
+ ErtsTracer curr_default_tracer = *default_tracer;
+ if (tracerp) {
+ /* we only have a rlock, so we have to unlock and then rwlock */
+ erts_smp_rwmtx_runlock(&sys_trace_rwmtx);
+ erts_smp_rwmtx_rwlock(&sys_trace_rwmtx);
+ }
+ /* check if someone else changed default tracer
+ while we got the write lock, if so we don't do
+ anything. */
+ if (curr_default_tracer == *default_tracer) {
+ *default_trace_flags &= ~TRACEE_FLAGS;
+ ERTS_TRACER_CLEAR(default_tracer);
+ }
+ if (tracerp) {
+ erts_smp_rwmtx_rwunlock(&sys_trace_rwmtx);
+ erts_smp_rwmtx_rlock(&sys_trace_rwmtx);
+ }
+ }
+ }
}
if (flagsp)
- *flagsp = default_trace_flags;
- if (tracerp)
- *tracerp = default_tracer;
+ *flagsp = *default_trace_flags;
+ if (tracerp) {
+ erts_tracer_update(tracerp,*default_tracer);
+ }
+}
+
+static ERTS_INLINE void
+erts_change_default_tracing(int setflags, Uint flags,
+ const ErtsTracer tracer,
+ Uint *default_trace_flags,
+ ErtsTracer *default_tracer)
+{
+ if (setflags)
+ *default_trace_flags |= flags;
+ else
+ *default_trace_flags &= ~flags;
+
+ erts_tracer_update(default_tracer, tracer);
+
+ get_default_tracing(NULL, NULL, default_trace_flags, default_tracer);
}
void
-erts_change_default_tracing(int setflags, Uint *flagsp, Eterm *tracerp)
+erts_change_default_proc_tracing(int setflags, Uint flagsp,
+ const ErtsTracer tracer)
{
erts_smp_rwmtx_rwlock(&sys_trace_rwmtx);
- if (flagsp) {
- if (setflags)
- default_trace_flags |= *flagsp;
- else
- default_trace_flags &= ~(*flagsp);
- }
- if (tracerp)
- default_tracer = *tracerp;
- get_default_tracing(flagsp, tracerp);
+ erts_change_default_tracing(
+ setflags, flagsp, tracer,
+ &default_proc_trace_flags,
+ &default_proc_tracer);
+ erts_smp_rwmtx_rwunlock(&sys_trace_rwmtx);
+}
+
+void
+erts_change_default_port_tracing(int setflags, Uint flagsp,
+ const ErtsTracer tracer)
+{
+ erts_smp_rwmtx_rwlock(&sys_trace_rwmtx);
+ erts_change_default_tracing(
+ setflags, flagsp, tracer,
+ &default_port_trace_flags,
+ &default_port_tracer);
erts_smp_rwmtx_rwunlock(&sys_trace_rwmtx);
}
void
-erts_get_default_tracing(Uint *flagsp, Eterm *tracerp)
+erts_get_default_proc_tracing(Uint *flagsp, ErtsTracer *tracerp)
+{
+ erts_smp_rwmtx_rlock(&sys_trace_rwmtx);
+ *tracerp = erts_tracer_nil; /* initialize */
+ get_default_tracing(
+ flagsp, tracerp,
+ &default_proc_trace_flags,
+ &default_proc_tracer);
+ erts_smp_rwmtx_runlock(&sys_trace_rwmtx);
+}
+
+void
+erts_get_default_port_tracing(Uint *flagsp, ErtsTracer *tracerp)
{
erts_smp_rwmtx_rlock(&sys_trace_rwmtx);
- get_default_tracing(flagsp, tracerp);
+ *tracerp = erts_tracer_nil; /* initialize */
+ get_default_tracing(
+ flagsp, tracerp,
+ &default_port_trace_flags,
+ &default_port_tracer);
erts_smp_rwmtx_runlock(&sys_trace_rwmtx);
}
@@ -623,29 +645,22 @@ erts_get_system_profile(void) {
return profile;
}
-#ifdef ERTS_SMP
-static void
-do_send_to_port(Eterm to,
- Port* unused_port,
- Eterm from,
- enum ErtsSysMsgType type,
- Eterm message)
-{
- Uint sz = size_object(message);
- ErlHeapFragment *bp = new_message_buffer(sz);
- Uint *hp = bp->mem;
- Eterm msg = copy_struct(message, sz, &hp, &bp->off_heap);
- enqueue_sys_msg_unlocked(type, from, to, msg, bp);
-}
-
-#define WRITE_SYS_MSG_TO_PORT write_sys_msg_to_port
+#ifdef HAVE_ERTS_NOW_CPU
+# define GET_NOW(m, s, u) \
+do { \
+ if (erts_cpu_timestamp) \
+ erts_get_now_cpu(m, s, u); \
+ else \
+ get_now(m, s, u); \
+} while (0)
#else
-#define WRITE_SYS_MSG_TO_PORT do_send_to_port
+# define GET_NOW(m, s, u) do {get_now(m, s, u);} while (0)
#endif
+
static void
-WRITE_SYS_MSG_TO_PORT(Eterm unused_to,
+write_sys_msg_to_port(Eterm unused_to,
Port* trace_port,
Eterm unused_from,
enum ErtsSysMsgType unused_type,
@@ -672,150 +687,6 @@ WRITE_SYS_MSG_TO_PORT(Eterm unused_to,
erts_free(ERTS_ALC_T_TMP, (void *) buffer);
}
-
-#ifndef ERTS_SMP
-/* Send {trace_ts, Pid, out, 0, Timestamp}
- * followed by {trace_ts, Pid, in, 0, NewTimestamp}
- *
- * 'NewTimestamp' through patch_ts().
- */
-static void
-do_send_schedfix_to_port(Port *trace_port, Eterm pid, Eterm timestamp, int ts_type) {
-#define LOCAL_HEAP_SIZE (5+5+ERTS_TRACE_PATCH_TS_MAX_SIZE)
- DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
- Eterm message;
- Eterm *hp;
- Eterm mfarity;
-
- UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
- ASSERT(is_pid(pid));
- ASSERT(is_tuple(timestamp));
- ASSERT(*tuple_val(timestamp) == make_arityval(3));
-
- hp = local_heap;
- mfarity = make_small(0);
- message = TUPLE5(hp, am_trace_ts, pid, am_out, mfarity, timestamp);
- /* Note, hp is deliberately NOT incremented since it will be reused */
-
- do_send_to_port(trace_port->common.id,
- trace_port,
- pid,
- SYS_MSG_TYPE_UNDEFINED,
- message);
-
-
- message = TUPLE5(hp, am_trace_ts, pid, am_in, mfarity,
- NIL /* Will be overwritten by timestamp */);
- hp += 6;
- hp[-1] = write_ts(ts_type, hp, NULL, NULL);
-
- do_send_to_port(trace_port->common.id,
- trace_port,
- pid,
- SYS_MSG_TYPE_UNDEFINED,
- message);
- UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-#undef LOCAL_HEAP_SIZE
-}
-#endif
-
-/* If (c_p != NULL), a fake schedule out/in message pair will be sent,
- * if the driver so requests.
- * It is assumed that 'message' is not an 'out' message.
- *
- * 'c_p' is the currently executing process, "tracee" is the traced process
- * which 'message' concerns => if (*tracee_flags & F_TIMESTAMP_MASK),
- * 'message' must contain a timestamp.
- */
-static void
-send_to_port(Process *c_p, Eterm message,
- Eterm *tracer_pid, Uint *tracee_flags) {
- Port* trace_port;
-#ifndef ERTS_SMP
- int ts_type;
-#define LOCAL_HEAP_SIZE ERTS_TRACE_PATCH_TS_MAX_SIZE
- Eterm ts;
- DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
-#endif
-
- ASSERT(is_internal_port(*tracer_pid));
-#ifdef ERTS_SMP
- if (is_not_internal_port(*tracer_pid))
- return;
-
- trace_port = NULL;
-#else
-
- trace_port = erts_id2port_sflgs(*tracer_pid,
- NULL,
- 0,
- ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP);
-
- if (!trace_port) {
- *tracee_flags &= ~TRACEE_FLAGS;
- *tracer_pid = NIL;
- return;
- }
-
- /*
- * Make a fake schedule only if the current process is traced
- * with 'running' and 'timestamp'.
- */
-
- if ( c_p == NULL ||
- (! IS_TRACED_FL(c_p, F_TRACE_SCHED | F_TIMESTAMP_MASK))) {
-#endif
- do_send_to_port(*tracer_pid,
- trace_port,
- c_p ? c_p->common.id : NIL,
- SYS_MSG_TYPE_TRACE,
- message);
-#ifndef ERTS_SMP
- erts_port_release(trace_port);
- return;
- }
-
- /*
- * Note that the process being traced for some type of trace messages
- * (e.g. getting_linked) need not be the current process. That other
- * process might not have timestamps enabled.
- */
- UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-
- /* A fake schedule might be needed.
- * Create a dummy trace message with timestamp to be
- * passed to do_send_schedfix_to_port().
- */
- ts_type = TFLGS_TS_TYPE(c_p);
- ts = write_ts(ts_type, local_heap, NULL, NULL);
-
- trace_port->control_flags &= ~PORT_CONTROL_FLAG_HEAVY;
- do_send_to_port(*tracer_pid,
- trace_port,
- c_p ? c_p->common.id : NIL,
- SYS_MSG_TYPE_TRACE,
- message);
-
- if (trace_port->control_flags & PORT_CONTROL_FLAG_HEAVY) {
- /* The driver has just informed us that the last write took a
- * non-neglectible amount of time.
- *
- * We need to fake some trace messages to compensate for the time the
- * current process had to sacrifice for the writing of the previous
- * trace message. We pretend that the process got scheduled out
- * just after writning the real trace message, and now gets scheduled
- * in again.
- */
- do_send_schedfix_to_port(trace_port, c_p->common.id, ts, ts_type);
- }
-
- erts_port_release(trace_port);
-
- UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-#undef LOCAL_HEAP_SIZE
-#endif
-}
-
#ifndef ERTS_SMP
/* Profile send
* Checks if profiler is port or process
@@ -844,11 +715,11 @@ profile_send(Eterm from, Eterm message) {
0,
ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP);
if (profiler_port) {
- do_send_to_port(profiler,
- profiler_port,
- NIL, /* or current process->common.id */
- SYS_MSG_TYPE_SYSPROF,
- message);
+ write_sys_msg_to_port(profiler,
+ profiler_port,
+ NIL, /* or current process->common.id */
+ SYS_MSG_TYPE_SYSPROF,
+ message);
erts_port_release(profiler_port);
}
@@ -868,154 +739,26 @@ profile_send(Eterm from, Eterm message) {
else
msg = copy_struct(message, sz, &hp, &mp->hfrag.off_heap);
- erts_queue_message(profile_p, NULL, mp, msg, NIL);
+ erts_queue_message(profile_p, 0, mp, msg, from);
}
}
#endif
-
-/* A fake schedule out/in message pair will be sent,
- * if the driver so requests.
- *
- * 'c_p' is the currently executing process, may be NULL.
- */
static void
-seq_trace_send_to_port(Process *c_p,
- Eterm seq_tracer,
- Eterm message)
+trace_sched_aux(Process *p, ErtsProcLocks locks, Eterm what)
{
- Port* trace_port;
-#ifndef ERTS_SMP
- int ts_type;
- Eterm ts;
-#define LOCAL_HEAP_SIZE ERTS_TRACE_PATCH_TS_MAX_SIZE
- DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
- UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-#endif
-
- ASSERT(is_internal_port(seq_tracer));
-#ifdef ERTS_SMP
- if (is_not_internal_port(seq_tracer))
- return;
-
- trace_port = NULL;
-#else
- trace_port = erts_id2port_sflgs(seq_tracer,
- NULL,
- 0,
- ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP);
- if (!trace_port) {
- system_seq_tracer = am_false;
-#ifndef ERTS_SMP
- UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-#endif
- return;
- }
-
- if (c_p == NULL
- || (! IS_TRACED_FL(c_p, F_TRACE_SCHED | F_TIMESTAMP_MASK))) {
-#endif
- do_send_to_port(seq_tracer,
- trace_port,
- c_p ? c_p->common.id : NIL,
- SYS_MSG_TYPE_SEQTRACE,
- message);
-
-#ifndef ERTS_SMP
- erts_port_release(trace_port);
- UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
- return;
- }
- /* Make a fake schedule only if the current process is traced
- * with 'running' and 'timestamp'.
- */
-
- /* A fake schedule might be needed.
- * Create a dummy trace message with timestamp to be
- * passed to do_send_schedfix_to_port().
- */
- ts_type = TFLGS_TS_TYPE(c_p);
- ts = write_ts(ts_type, local_heap, NULL, NULL);
-
- trace_port->control_flags &= ~PORT_CONTROL_FLAG_HEAVY;
- do_send_to_port(seq_tracer,
- trace_port,
- c_p ? c_p->common.id : NIL,
- SYS_MSG_TYPE_SEQTRACE,
- message);
-
- if (trace_port->control_flags & PORT_CONTROL_FLAG_HEAVY) {
- /* The driver has just informed us that the last write took a
- * non-neglectible amount of time.
- *
- * We need to fake some trace messages to compensate for the time the
- * current process had to sacrifice for the writing of the previous
- * trace message. We pretend that the process got scheduled out
- * just after writing the real trace message, and now gets scheduled
- * in again.
- */
- do_send_schedfix_to_port(trace_port, c_p->common.id, ts, ts_type);
- }
-
- erts_port_release(trace_port);
-
- UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-#undef LOCAL_HEAP_SIZE
-#endif
-}
-
-static ERTS_INLINE void
-send_to_tracer(Process *tracee,
- ERTS_TRACER_REF_TYPE tracer_ref,
- Eterm msg,
- Eterm **hpp,
- ErlHeapFragment *bp,
- int no_fake_sched)
-{
- ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks(tracee));
-
- erts_smp_mtx_lock(&smq_mtx);
-
- if (is_internal_pid(ERTS_TRACER_PROC(tracee))) {
- PATCH_TS(TFLGS_TS_TYPE(tracee), msg, *hpp, bp, tracer_ref);
- ERTS_ENQ_TRACE_MSG(tracee->common.id, tracer_ref, msg, bp);
- }
- else {
- ASSERT(is_internal_port(ERTS_TRACER_PROC(tracee)));
- PATCH_TS(TFLGS_TS_TYPE(tracee), msg, *hpp, NULL, NULL);
- send_to_port(no_fake_sched ? NULL : tracee,
- msg,
- &ERTS_TRACER_PROC(tracee),
- &ERTS_TRACE_FLAGS(tracee));
- }
-
- erts_smp_mtx_unlock(&smq_mtx);
+ Eterm tmp, *hp;
+ int curr_func;
+ ErtsTracerNif *tnif = NULL;
-}
-
-static void
-trace_sched_aux(Process *p, Eterm what, int never_fake_sched)
-{
-#define LOCAL_HEAP_SIZE (5+4+1+ERTS_TRACE_PATCH_TS_MAX_SIZE)
- DeclareTmpHeap(local_heap,LOCAL_HEAP_SIZE,p);
- Eterm tmp, mess, *hp;
- ErlHeapFragment *bp = NULL;
- ErlOffHeap *off_heap;
- ERTS_TRACER_REF_TYPE tracer_ref = ERTS_NULL_TRACER_REF;
- int sched_no, curr_func, to_port, no_fake_sched;
-
- if (is_nil(ERTS_TRACER_PROC(p)))
+ if (ERTS_TRACER_IS_NIL(ERTS_TRACER(p)))
return;
- no_fake_sched = never_fake_sched;
-
switch (what) {
case am_out:
case am_out_exiting:
case am_out_exited:
- no_fake_sched = 1;
- break;
case am_in:
case am_in_exiting:
break;
@@ -1024,16 +767,8 @@ trace_sched_aux(Process *p, Eterm what, int never_fake_sched)
break;
}
- sched_no = IS_TRACED_FL(p, F_TRACE_SCHED_NO);
- to_port = is_internal_port(ERTS_TRACER_PROC(p));
-
- if (!to_port) {
- ASSERT(is_internal_pid(ERTS_TRACER_PROC(p)));
-
- ERTS_GET_TRACER_REF(tracer_ref,
- ERTS_TRACER_PROC(p),
- ERTS_TRACE_FLAGS(p));
- }
+ if (!is_tracer_enabled(p, locks, &p->common, &tnif, TRACE_FUN_E_SCHED_PROC, what))
+ return;
if (ERTS_PROC_IS_EXITING(p))
curr_func = 0;
@@ -1043,44 +778,16 @@ trace_sched_aux(Process *p, Eterm what, int never_fake_sched)
curr_func = p->current != NULL;
}
- UseTmpHeap(LOCAL_HEAP_SIZE,p);
-
- if (to_port)
- hp = local_heap;
- else {
- Uint size = 5;
- if (curr_func)
- size += 4;
- if (sched_no)
- size += 1;
- size += PATCH_TS_SIZE(p);
- hp = ERTS_ALLOC_SYSMSG_HEAP(size, &bp, &off_heap, tracer_ref);
- }
-
if (!curr_func) {
tmp = make_small(0);
} else {
+ hp = HAlloc(p, 4);
tmp = TUPLE3(hp,p->current[0],p->current[1],make_small(p->current[2]));
hp += 4;
}
- if (!sched_no) {
- mess = TUPLE4(hp, am_trace, p->common.id, what, tmp);
- hp += 5;
- }
- else {
-#ifdef ERTS_SMP
- Eterm sched_id = make_small(p->scheduler_data->no);
-#else
- Eterm sched_id = make_small(1);
-#endif
- mess = TUPLE5(hp, am_trace, p->common.id, what, sched_id, tmp);
- hp += 6;
- }
-
- send_to_tracer(p, tracer_ref, mess, &hp, bp, no_fake_sched);
- UnUseTmpHeap(LOCAL_HEAP_SIZE,p);
-#undef LOCAL_HEAP_SIZE
+ send_to_tracer_nif(p, &p->common, p->common.id, tnif, TRACE_FUN_T_SCHED_PROC,
+ what, tmp, THE_NON_VALUE, am_true);
}
/* Send {trace_ts, Pid, What, {Mod, Func, Arity}, Timestamp}
@@ -1090,9 +797,9 @@ trace_sched_aux(Process *p, Eterm what, int never_fake_sched)
* 'out_exiting', or 'out_exited'.
*/
void
-trace_sched(Process *p, Eterm what)
+trace_sched(Process *p, ErtsProcLocks locks, Eterm what)
{
- trace_sched_aux(p, what, 0);
+ trace_sched_aux(p, locks, what);
}
/* Send {trace_ts, Pid, Send, Msg, DestPid, Timestamp}
@@ -1103,140 +810,118 @@ trace_sched(Process *p, Eterm what)
void
trace_send(Process *p, Eterm to, Eterm msg)
{
- Eterm operation;
- unsigned sz_msg;
- unsigned sz_to;
- Eterm* hp;
- Eterm mess;
-
- if (!ARE_TRACE_FLAGS_ON(p, F_TRACE_SEND)) {
+ Eterm operation = am_send;
+ ErtsTracerNif *tnif = NULL;
+ ErtsTracingEvent* te;
+ Eterm pam_result;
+
+ ASSERT(ARE_TRACE_FLAGS_ON(p, F_TRACE_SEND));
+
+ te = &erts_send_tracing[erts_active_bp_ix()];
+ if (!te->on) {
return;
}
+ if (te->match_spec) {
+ Eterm args[2];
+ Uint32 return_flags;
+ args[0] = to;
+ args[1] = msg;
+ pam_result = erts_match_set_run_trace(p, p,
+ te->match_spec, args, 2,
+ ERTS_PAM_TMP_RESULT, &return_flags);
+ if (pam_result == am_false)
+ return;
+ if (ERTS_TRACE_FLAGS(p) & F_TRACE_SILENT) {
+ erts_match_set_release_result_trace(p, pam_result);
+ return;
+ }
+ } else
+ pam_result = am_true;
- operation = am_send;
if (is_internal_pid(to)) {
if (!erts_proc_lookup(to))
goto send_to_non_existing_process;
}
else if(is_external_pid(to)
&& external_pid_dist_entry(to) == erts_this_dist_entry) {
- char *s;
send_to_non_existing_process:
- s = "send_to_non_existing_process";
- operation = am_atom_put(s, sys_strlen(s));
+ operation = am_send_to_non_existing_process;
}
- if (is_internal_port(ERTS_TRACER_PROC(p))) {
-#define LOCAL_HEAP_SIZE (6 + ERTS_TRACE_PATCH_TS_MAX_SIZE)
- DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
- UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-
- hp = local_heap;
- mess = TUPLE5(hp, am_trace, p->common.id, operation, msg, to);
- hp += 6;
- erts_smp_mtx_lock(&smq_mtx);
- PATCH_TS(TFLGS_TS_TYPE(p), mess, hp, NULL, NULL);
- send_to_port(p, mess, &ERTS_TRACER_PROC(p), &ERTS_TRACE_FLAGS(p));
- UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-#undef LOCAL_HEAP_SIZE
- erts_smp_mtx_unlock(&smq_mtx);
- } else {
- Uint need;
- ErlHeapFragment *bp;
- ErlOffHeap *off_heap;
- ERTS_TRACER_REF_TYPE tracer_ref;
-
- ASSERT(is_internal_pid(ERTS_TRACER_PROC(p)));
-
- ERTS_GET_TRACER_REF(tracer_ref,
- ERTS_TRACER_PROC(p),
- ERTS_TRACE_FLAGS(p));
-
- sz_msg = size_object(msg);
- sz_to = size_object(to);
- need = sz_msg + sz_to + 6 + PATCH_TS_SIZE(p);
-
- hp = ERTS_ALLOC_SYSMSG_HEAP(need, &bp, &off_heap, tracer_ref);
-
- to = copy_struct(to,
- sz_to,
- &hp,
- off_heap);
- msg = copy_struct(msg,
- sz_msg,
- &hp,
- off_heap);
- mess = TUPLE5(hp, am_trace, p->common.id, operation, msg, to);
- hp += 6;
-
- erts_smp_mtx_lock(&smq_mtx);
-
- PATCH_TS(TFLGS_TS_TYPE(p), mess, hp, bp, tracer_ref);
- ERTS_ENQ_TRACE_MSG(p->common.id, tracer_ref, mess, bp);
- erts_smp_mtx_unlock(&smq_mtx);
+ if (is_tracer_enabled(p, ERTS_PROC_LOCK_MAIN, &p->common, &tnif,
+ TRACE_FUN_E_SEND, operation)) {
+ send_to_tracer_nif(p, &p->common, p->common.id, tnif, TRACE_FUN_T_SEND,
+ operation, msg, to, pam_result);
}
+ erts_match_set_release_result_trace(p, pam_result);
}
/* Send {trace_ts, Pid, receive, Msg, Timestamp}
* or {trace, Pid, receive, Msg}
*/
void
-trace_receive(Process *rp, Eterm msg)
+trace_receive(Process* receiver,
+ Eterm from,
+ Eterm msg, ErtsTracingEvent* te)
{
- Eterm mess;
- size_t sz_msg;
- Eterm* hp;
-
- if (is_internal_port(ERTS_TRACER_PROC(rp))) {
-#define LOCAL_HEAP_SIZE (5+ERTS_TRACE_PATCH_TS_MAX_SIZE)
- DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
- UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-
- hp = local_heap;
- mess = TUPLE4(hp, am_trace, rp->common.id, am_receive, msg);
- hp += 5;
- erts_smp_mtx_lock(&smq_mtx);
- PATCH_TS(TFLGS_TS_TYPE(rp), mess, hp, NULL, NULL);
- send_to_port(rp, mess, &ERTS_TRACER_PROC(rp), &ERTS_TRACE_FLAGS(rp));
- UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-#undef LOCAL_HEAP_SIZE
- erts_smp_mtx_unlock(&smq_mtx);
- } else {
- Uint hsz;
- ErlHeapFragment *bp;
- ErlOffHeap *off_heap;
- ERTS_TRACER_REF_TYPE tracer_ref;
-
- ASSERT(is_internal_pid(ERTS_TRACER_PROC(rp)));
-
- ERTS_GET_TRACER_REF(tracer_ref,
- ERTS_TRACER_PROC(rp),
- ERTS_TRACE_FLAGS(rp));
-
- sz_msg = size_object(msg);
-
- hsz = sz_msg + 5 + PATCH_TS_SIZE(rp);
-
- hp = ERTS_ALLOC_SYSMSG_HEAP(hsz, &bp, &off_heap, tracer_ref);
-
- msg = copy_struct(msg, sz_msg, &hp, off_heap);
- mess = TUPLE4(hp, am_trace, rp->common.id, am_receive, msg);
- hp += 5;
-
- erts_smp_mtx_lock(&smq_mtx);
-
- PATCH_TS(TFLGS_TS_TYPE(rp), mess, hp, bp, tracer_ref);
- ERTS_ENQ_TRACE_MSG(rp->common.id, tracer_ref, mess, bp);
- erts_smp_mtx_unlock(&smq_mtx);
- }
+ ErtsTracerNif *tnif = NULL;
+ Eterm pam_result;
+
+ if (!te) {
+ te = &erts_receive_tracing[erts_active_bp_ix()];
+ if (!te->on)
+ return;
+ }
+ else ASSERT(te->on);
+
+ if (te->match_spec) {
+ Eterm args[3];
+ Uint32 return_flags;
+ if (is_pid(from)) {
+ args[0] = pid_node_name(from);
+ args[1] = from;
+ }
+ else {
+ ASSERT(is_atom(from));
+ args[0] = from; /* node name or other atom (e.g 'system') */
+ args[1] = am_undefined;
+ }
+ args[2] = msg;
+ pam_result = erts_match_set_run_trace(NULL, receiver,
+ te->match_spec, args, 3,
+ ERTS_PAM_TMP_RESULT, &return_flags);
+ if (pam_result == am_false)
+ return;
+ if (ERTS_TRACE_FLAGS(receiver) & F_TRACE_SILENT) {
+ erts_match_set_release_result_trace(NULL, pam_result);
+ return;
+ }
+ } else
+ pam_result = am_true;
+
+ if (is_tracer_enabled(NULL, 0, &receiver->common, &tnif,
+ TRACE_FUN_E_RECEIVE, am_receive)) {
+ send_to_tracer_nif(NULL, &receiver->common, receiver->common.id,
+ tnif, TRACE_FUN_T_RECEIVE,
+ am_receive, msg, THE_NON_VALUE, pam_result);
+ }
+ erts_match_set_release_result_trace(NULL, pam_result);
}
int
seq_trace_update_send(Process *p)
{
- Eterm seq_tracer = erts_get_system_seq_tracer();
+ ErtsTracer seq_tracer = erts_get_system_seq_tracer();
ASSERT((is_tuple(SEQ_TRACE_TOKEN(p)) || is_nil(SEQ_TRACE_TOKEN(p))));
- if ((p->common.id == seq_tracer) || have_no_seqtrace(SEQ_TRACE_TOKEN(p))) {
+ if (have_no_seqtrace(SEQ_TRACE_TOKEN(p)) ||
+ (seq_tracer != NIL &&
+ call_enabled_tracer(NULL, seq_tracer, NULL,
+ TRACE_FUN_ENABLED, am_trace_status,
+ p ? p->common.id : am_undefined) != am_trace)
+#ifdef USE_VM_PROBES
+ || (SEQ_TRACE_TOKEN(p) == am_have_dt_utag)
+#endif
+ ) {
return 0;
}
SEQ_TRACE_TOKEN_SENDER(p) = p->common.id;
@@ -1264,20 +949,29 @@ seq_trace_output_generic(Eterm token, Eterm msg, Uint type,
Eterm receiver, Process *process, Eterm exitfrom)
{
Eterm mess;
- ErlHeapFragment* bp;
Eterm* hp;
Eterm label;
Eterm lastcnt_serial;
Eterm type_atom;
- int sz_exit;
- Eterm seq_tracer;
- int ts_type;
+ ErtsTracer seq_tracer;
+ int seq_tracer_flags = 0;
+#define LOCAL_HEAP_SIZE (64)
+ DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
seq_tracer = erts_get_system_seq_tracer();
ASSERT(is_tuple(token) || is_nil(token));
- if (SEQ_TRACE_T_SENDER(token) == seq_tracer || token == NIL ||
- (process && ERTS_TRACE_FLAGS(process) & F_SENSITIVE)) {
+ if (token == NIL || (process && ERTS_TRACE_FLAGS(process) & F_SENSITIVE) ||
+ ERTS_TRACER_IS_NIL(seq_tracer) ||
+ call_enabled_tracer(NULL, seq_tracer,
+ NULL, TRACE_FUN_ENABLED,
+ am_trace_status,
+ process ? process->common.id : am_undefined) != am_trace) {
+ return;
+ }
+
+ if ((unsigned_val(SEQ_TRACE_T_FLAGS(token)) & type) == 0) {
+ /* No flags set, nothing to do */
return;
}
@@ -1290,151 +984,28 @@ seq_trace_output_generic(Eterm token, Eterm msg, Uint type,
return; /* To avoid warning */
}
- if ((unsigned_val(SEQ_TRACE_T_FLAGS(token)) & type) == 0) {
- /* No flags set, nothing to do */
- return;
- }
+ UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
- if (seq_tracer == am_false) {
- return; /* no need to send anything */
+ hp = local_heap;
+ label = SEQ_TRACE_T_LABEL(token);
+ lastcnt_serial = TUPLE2(hp, SEQ_TRACE_T_LASTCNT(token),
+ SEQ_TRACE_T_SERIAL(token));
+ hp += 3;
+ if (exitfrom != NIL) {
+ msg = TUPLE3(hp, am_EXIT, exitfrom, msg);
+ hp += 4;
}
+ mess = TUPLE5(hp, type_atom, lastcnt_serial, SEQ_TRACE_T_SENDER(token), receiver, msg);
+ hp += 6;
- ts_type = ERTS_SEQTFLGS2TSTYPE(unsigned_val(SEQ_TRACE_T_FLAGS(token)));
+ seq_tracer_flags |= ERTS_SEQTFLGS2TFLGS(unsigned_val(SEQ_TRACE_T_FLAGS(token)));
- if (is_internal_port(seq_tracer)) {
-#define LOCAL_HEAP_SIZE (60 + ERTS_TRACE_PATCH_TS_MAX_SIZE)
- DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
- UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
+ send_to_tracer_nif_raw(NULL, process, seq_tracer, seq_tracer_flags,
+ label, NULL, TRACE_FUN_DEFAULT, am_seq_trace, mess,
+ THE_NON_VALUE, am_true);
- hp = local_heap;
- label = SEQ_TRACE_T_LABEL(token);
- lastcnt_serial = TUPLE2(hp, SEQ_TRACE_T_LASTCNT(token),
- SEQ_TRACE_T_SERIAL(token));
- hp += 3;
- if (exitfrom != NIL) {
- msg = TUPLE3(hp, am_EXIT, exitfrom, msg);
- hp += 4;
- }
- mess = TUPLE5(hp, type_atom, lastcnt_serial, SEQ_TRACE_T_SENDER(token),
- receiver, msg);
- hp += 6;
-
- erts_smp_mtx_lock(&smq_mtx);
- if (!ts_type) {
- mess = TUPLE3(hp, am_seq_trace, label, mess);
- seq_trace_send_to_port(NULL, seq_tracer, mess);
- } else {
- mess = TUPLE4(hp, am_seq_trace, label, mess,
- NIL /* Will be overwritten by timestamp */);
- hp += 5;
- hp[-1] = write_ts(ts_type, hp, NULL, NULL);
- seq_trace_send_to_port(process, seq_tracer, mess);
- }
- UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
+ UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
#undef LOCAL_HEAP_SIZE
- erts_smp_mtx_unlock(&smq_mtx);
- } else {
-#ifndef ERTS_SMP
- Process* tracer;
-#endif
- Eterm sender_copy;
- Eterm receiver_copy;
- Eterm m2;
- Uint sz_label, sz_lastcnt_serial, sz_msg, sz_ts, sz_sender,
- sz_exitfrom, sz_receiver;
-
- ASSERT(is_internal_pid(seq_tracer));
-
-#ifndef ERTS_SMP
-
- tracer = erts_proc_lookup(seq_tracer);
- if (!tracer) {
- system_seq_tracer = am_false;
- return; /* no need to send anything */
- }
-#endif
- if (receiver == seq_tracer) {
- return; /* no need to send anything */
- }
-
- sz_label = size_object(SEQ_TRACE_T_LABEL(token));
- sz_sender = size_object(SEQ_TRACE_T_SENDER(token));
- sz_receiver = size_object(receiver);
- sz_lastcnt_serial = 3; /* TUPLE2 */
- sz_msg = size_object(msg);
-
- sz_ts = patch_ts_size(ts_type);
- if (exitfrom != NIL) {
- sz_exit = 4; /* create {'EXIT',exitfrom,msg} */
- sz_exitfrom = size_object(exitfrom);
- }
- else {
- sz_exit = 0;
- sz_exitfrom = 0;
- }
- bp = new_message_buffer(4 /* TUPLE3 */ + sz_ts + 6 /* TUPLE5 */
- + sz_lastcnt_serial + sz_label + sz_msg
- + sz_exit + sz_exitfrom
- + sz_sender + sz_receiver);
- hp = bp->mem;
- label = copy_struct(SEQ_TRACE_T_LABEL(token), sz_label, &hp, &bp->off_heap);
- lastcnt_serial = TUPLE2(hp,SEQ_TRACE_T_LASTCNT(token),SEQ_TRACE_T_SERIAL(token));
- hp += 3;
- m2 = copy_struct(msg, sz_msg, &hp, &bp->off_heap);
- if (sz_exit) {
- Eterm exitfrom_copy = copy_struct(exitfrom,
- sz_exitfrom,
- &hp,
- &bp->off_heap);
- m2 = TUPLE3(hp, am_EXIT, exitfrom_copy, m2);
- hp += 4;
- }
- sender_copy = copy_struct(SEQ_TRACE_T_SENDER(token),
- sz_sender,
- &hp,
- &bp->off_heap);
- receiver_copy = copy_struct(receiver,
- sz_receiver,
- &hp,
- &bp->off_heap);
- mess = TUPLE5(hp,
- type_atom,
- lastcnt_serial,
- sender_copy,
- receiver_copy,
- m2);
- hp += 6;
-
- erts_smp_mtx_lock(&smq_mtx);
-
- if (!ts_type)
- mess = TUPLE3(hp, am_seq_trace, label, mess);
- else {
- mess = TUPLE4(hp, am_seq_trace, label, mess,
- NIL /* Will be overwritten by timestamp */);
- hp += 5;
- /* Write timestamp in element 6 of the 'msg' tuple */
- hp[-1] = write_ts(ts_type, hp, bp,
-#ifndef ERTS_SMP
- tracer
-#else
- NULL
-#endif
- );
- }
-
-#ifdef ERTS_SMP
- enqueue_sys_msg_unlocked(SYS_MSG_TYPE_SEQTRACE, NIL, NIL, mess, bp);
- erts_smp_mtx_unlock(&smq_mtx);
-#else
- /* trace_token must be NIL here */
- {
- ErtsMessage *mp = erts_alloc_message(0, NULL);
- mp->data.heap_frag = bp;
- erts_queue_message(tracer, NULL, mp, mess, NIL);
- }
-#endif
- }
}
/* Send {trace_ts, Pid, return_to, {Mod, Func, Arity}, Timestamp}
@@ -1443,63 +1014,20 @@ seq_trace_output_generic(Eterm token, Eterm msg, Uint type,
void
erts_trace_return_to(Process *p, BeamInstr *pc)
{
-#define LOCAL_HEAP_SIZE (4+5+ERTS_TRACE_PATCH_TS_MAX_SIZE)
- Eterm* hp;
Eterm mfa;
- Eterm mess;
- DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
BeamInstr *code_ptr = find_function_from_pc(pc);
- UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-
- hp = local_heap;
-
if (!code_ptr) {
mfa = am_undefined;
} else {
+ Eterm *hp = HAlloc(p, 4);
mfa = TUPLE3(hp, code_ptr[0], code_ptr[1], make_small(code_ptr[2]));
- hp += 4;
}
-
- mess = TUPLE4(hp, am_trace, p->common.id, am_return_to, mfa);
- hp += 5;
-
- erts_smp_mtx_lock(&smq_mtx);
-
- PATCH_TS(TFLGS_TS_TYPE(p), mess, hp, NULL, NULL);
-
- if (is_internal_port(ERTS_TRACER_PROC(p))) {
- send_to_port(p, mess, &ERTS_TRACER_PROC(p), &ERTS_TRACE_FLAGS(p));
- } else {
- ErlHeapFragment *bp;
- ErlOffHeap *off_heap;
- ERTS_TRACER_REF_TYPE tracer_ref;
- unsigned size;
-
- /*
- * Find the tracer.
- */
- ASSERT(is_internal_pid(ERTS_TRACER_PROC(p)));
-
- ERTS_GET_TRACER_REF(tracer_ref,
- ERTS_TRACER_PROC(p),
- ERTS_TRACE_FLAGS(p));
- size = size_object(mess);
-
- hp = ERTS_ALLOC_SYSMSG_HEAP(size, &bp, &off_heap, tracer_ref);
-
- /*
- * Copy the trace message into the buffer and enqueue it.
- */
- mess = copy_struct(mess, size, &hp, off_heap);
- ERTS_ENQ_TRACE_MSG(p->common.id, tracer_ref, mess, bp);
- }
- UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-#undef LOCAL_HEAP_SIZE
- erts_smp_mtx_unlock(&smq_mtx);
+ send_to_tracer_nif(p, &p->common, p->common.id, NULL, TRACE_FUN_T_CALL,
+ am_return_to, mfa, THE_NON_VALUE, am_true);
}
@@ -1507,114 +1035,53 @@ erts_trace_return_to(Process *p, BeamInstr *pc)
* or {trace, Pid, return_from, {Mod, Name, Arity}, Retval}
*/
void
-erts_trace_return(Process* p, BeamInstr* fi, Eterm retval, Eterm *tracer_pid)
+erts_trace_return(Process* p, BeamInstr* fi, Eterm retval, ErtsTracer *tracer)
{
Eterm* hp;
- Eterm mfa;
- Eterm mess;
- Eterm mod, name;
+ Eterm mfa, mod, name;
int arity;
Uint meta_flags, *tracee_flags;
- int ts_type;
-#ifdef ERTS_SMP
- Eterm tracee;
-#endif
-
- ASSERT(tracer_pid);
- if (*tracer_pid == am_true) {
+
+ ASSERT(tracer);
+ if (ERTS_TRACER_COMPARE(*tracer, erts_tracer_true)) {
/* Breakpoint trace enabled without specifying tracer =>
* use process tracer and flags
*/
- tracer_pid = &ERTS_TRACER_PROC(p);
+ tracer = &ERTS_TRACER(p);
}
- if (is_nil(*tracer_pid)) {
+ if (ERTS_TRACER_IS_NIL(*tracer)) {
/* Trace disabled */
return;
}
- ASSERT(is_internal_pid(*tracer_pid) || is_internal_port(*tracer_pid));
- if (*tracer_pid == p->common.id) {
- /* Do not generate trace messages to oneself */
- return;
- }
- if (tracer_pid == &ERTS_TRACER_PROC(p)) {
+ ASSERT(IS_TRACER_VALID(*tracer));
+ if (tracer == &ERTS_TRACER(p)) {
/* Tracer specified in process structure =>
* non-breakpoint trace =>
* use process flags
*/
tracee_flags = &ERTS_TRACE_FLAGS(p);
-#ifdef ERTS_SMP
- tracee = p->common.id;
-#endif
+ if (! (*tracee_flags & F_TRACE_CALLS)) {
+ return;
+ }
} else {
/* Tracer not specified in process structure =>
* tracer specified in breakpoint =>
* meta trace =>
* use fixed flag set instead of process flags
- */
+ */
meta_flags = F_TRACE_CALLS | F_NOW_TS;
tracee_flags = &meta_flags;
-#ifdef ERTS_SMP
- tracee = NIL;
-#endif
- }
- if (! (*tracee_flags & F_TRACE_CALLS)) {
- return;
}
-
+
mod = fi[0];
name = fi[1];
arity = fi[2];
-
- ts_type = ERTS_TFLGS2TSTYPE(*tracee_flags);
-
- if (is_internal_port(*tracer_pid)) {
-#define LOCAL_HEAP_SIZE (4+6+ERTS_TRACE_PATCH_TS_MAX_SIZE)
- DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
- UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
- hp = local_heap;
- mfa = TUPLE3(hp, mod, name, make_small(arity));
- hp += 4;
- mess = TUPLE5(hp, am_trace, p->common.id, am_return_from, mfa, retval);
- hp += 6;
- erts_smp_mtx_lock(&smq_mtx);
- PATCH_TS(ts_type, mess, hp, NULL, NULL);
- send_to_port(p, mess, tracer_pid, tracee_flags);
- UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-#undef LOCAL_HEAP_SIZE
- erts_smp_mtx_unlock(&smq_mtx);
- } else {
- ErlHeapFragment *bp;
- ErlOffHeap *off_heap;
- ERTS_TRACER_REF_TYPE tracer_ref;
- unsigned size;
- unsigned retval_size;
-
- ASSERT(is_internal_pid(*tracer_pid));
-
- ERTS_GET_TRACER_REF(tracer_ref, *tracer_pid, *tracee_flags);
- retval_size = size_object(retval);
- size = 6 + 4 + retval_size + patch_ts_size(ts_type);
-
- hp = ERTS_ALLOC_SYSMSG_HEAP(size, &bp, &off_heap, tracer_ref);
-
- /*
- * Build the trace tuple and put it into receive queue of the tracer process.
- */
-
- mfa = TUPLE3(hp, mod, name, make_small(arity));
- hp += 4;
- retval = copy_struct(retval, retval_size, &hp, off_heap);
- mess = TUPLE5(hp, am_trace, p->common.id, am_return_from, mfa, retval);
- hp += 6;
-
- erts_smp_mtx_lock(&smq_mtx);
-
- PATCH_TS(ts_type, mess, hp, bp, tracer_ref);
-
- ERTS_ENQ_TRACE_MSG(tracee, tracer_ref, mess, bp);
- erts_smp_mtx_unlock(&smq_mtx);
- }
+ hp = HAlloc(p, 4);
+ mfa = TUPLE3(hp, mod, name, make_small(arity));
+ hp += 4;
+ send_to_tracer_nif_raw(p, NULL, *tracer, *tracee_flags, p->common.id,
+ NULL, TRACE_FUN_T_CALL, am_return_from, mfa, retval, am_true);
}
/* Send {trace_ts, Pid, exception_from, {Mod, Name, Arity}, {Class,Value},
@@ -1626,116 +1093,50 @@ erts_trace_return(Process* p, BeamInstr* fi, Eterm retval, Eterm *tracer_pid)
*/
void
erts_trace_exception(Process* p, BeamInstr mfa[3], Eterm class, Eterm value,
- Eterm *tracer_pid)
+ ErtsTracer *tracer)
{
Eterm* hp;
- Eterm mfa_tuple;
- Eterm cv;
- Eterm mess;
+ Eterm mfa_tuple, cv;
Uint meta_flags, *tracee_flags;
- int ts_type;
-#ifdef ERTS_SMP
- Eterm tracee;
-#endif
-
- ASSERT(tracer_pid);
- if (*tracer_pid == am_true) {
+
+ ASSERT(tracer);
+ if (ERTS_TRACER_COMPARE(*tracer, erts_tracer_true)) {
/* Breakpoint trace enabled without specifying tracer =>
* use process tracer and flags
*/
- tracer_pid = &ERTS_TRACER_PROC(p);
+ tracer = &ERTS_TRACER(p);
}
- if (is_nil(*tracer_pid)) {
+ if (ERTS_TRACER_IS_NIL(*tracer)) {
/* Trace disabled */
return;
}
- ASSERT(is_internal_pid(*tracer_pid) || is_internal_port(*tracer_pid));
- if (*tracer_pid == p->common.id) {
- /* Do not generate trace messages to oneself */
- return;
- }
- if (tracer_pid == &ERTS_TRACER_PROC(p)) {
+ ASSERT(IS_TRACER_VALID(*tracer));
+ if (tracer == &ERTS_TRACER(p)) {
/* Tracer specified in process structure =>
* non-breakpoint trace =>
* use process flags
*/
tracee_flags = &ERTS_TRACE_FLAGS(p);
-#ifdef ERTS_SMP
- tracee = p->common.id;
-#endif
- if (! (*tracee_flags & F_TRACE_CALLS)) {
- return;
- }
+ if (! (*tracee_flags & F_TRACE_CALLS)) {
+ return;
+ }
} else {
/* Tracer not specified in process structure =>
* tracer specified in breakpoint =>
* meta trace =>
* use fixed flag set instead of process flags
- */
+ */
meta_flags = F_TRACE_CALLS | F_NOW_TS;
tracee_flags = &meta_flags;
-#ifdef ERTS_SMP
- tracee = NIL;
-#endif
}
-
- ts_type = ERTS_TFLGS2TSTYPE(*tracee_flags);
-
- if (is_internal_port(*tracer_pid)) {
-#define LOCAL_HEAP_SIZE (4+3+6+ERTS_TRACE_PATCH_TS_MAX_SIZE)
- DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
- UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-
- hp = local_heap;
- mfa_tuple = TUPLE3(hp, (Eterm) mfa[0], (Eterm) mfa[1], make_small((Eterm)mfa[2]));
- hp += 4;
- cv = TUPLE2(hp, class, value);
- hp += 3;
- mess = TUPLE5(hp, am_trace, p->common.id, am_exception_from, mfa_tuple, cv);
- hp += 6;
- ASSERT((hp - local_heap) <= LOCAL_HEAP_SIZE);
- erts_smp_mtx_lock(&smq_mtx);
- PATCH_TS(ts_type, mess, hp, NULL, NULL);
- send_to_port(p, mess, tracer_pid, tracee_flags);
- UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-#undef LOCAL_HEAP_SIZE
- erts_smp_mtx_unlock(&smq_mtx);
- } else {
- ErlHeapFragment *bp;
- ErlOffHeap *off_heap;
- ERTS_TRACER_REF_TYPE tracer_ref;
- unsigned size;
- unsigned value_size;
-
- ASSERT(is_internal_pid(*tracer_pid));
-
- ERTS_GET_TRACER_REF(tracer_ref, *tracer_pid, *tracee_flags);
-
- value_size = size_object(value);
- size = 6 + 4 + 3 + value_size + patch_ts_size(ts_type);
-
- hp = ERTS_ALLOC_SYSMSG_HEAP(size, &bp, &off_heap, tracer_ref);
-
- /*
- * Build the trace tuple and put it into receive queue of the tracer process.
- */
-
- mfa_tuple = TUPLE3(hp, (Eterm) mfa[0], (Eterm) mfa[1], make_small((Eterm) mfa[2]));
- hp += 4;
- value = copy_struct(value, value_size, &hp, off_heap);
- cv = TUPLE2(hp, class, value);
- hp += 3;
- mess = TUPLE5(hp, am_trace, p->common.id,
- am_exception_from, mfa_tuple, cv);
- hp += 6;
-
- erts_smp_mtx_lock(&smq_mtx);
- PATCH_TS(ts_type, mess, hp, bp, tracer_ref);
-
- ERTS_ENQ_TRACE_MSG(tracee, tracer_ref, mess, bp);
- erts_smp_mtx_unlock(&smq_mtx);
- }
+ hp = HAlloc(p, 7);;
+ mfa_tuple = TUPLE3(hp, (Eterm) mfa[0], (Eterm) mfa[1], make_small((Eterm)mfa[2]));
+ hp += 4;
+ cv = TUPLE2(hp, class, value);
+ hp += 3;
+ send_to_tracer_nif_raw(p, NULL, *tracer, *tracee_flags, p->common.id,
+ NULL, TRACE_FUN_T_CALL, am_exception_from, mfa_tuple, cv, am_true);
}
/*
@@ -1754,7 +1155,7 @@ erts_trace_exception(Process* p, BeamInstr mfa[3], Eterm class, Eterm value,
*/
Uint32
erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec,
- Eterm* args, int local, Eterm *tracer_pid)
+ Eterm* args, int local, ErtsTracer *tracer)
{
Eterm* hp;
Eterm mfa_tuple;
@@ -1762,55 +1163,53 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec,
int i;
Uint32 return_flags;
Eterm pam_result = am_true;
- Eterm mess;
Uint meta_flags, *tracee_flags;
- int ts_type;
-#ifdef ERTS_SMP
- Eterm tracee;
-#endif
+ ErtsTracerNif *tnif = NULL;
Eterm transformed_args[MAX_ARG];
- DeclareTypedTmpHeap(ErlSubBin,sub_bin_heap,p);
+ ErtsTracer pre_ms_tracer = erts_tracer_nil;
- ASSERT(tracer_pid);
- if (*tracer_pid == am_true) {
- /* Breakpoint trace enabled without specifying tracer =>
+ ASSERT(tracer);
+ if (ERTS_TRACER_COMPARE(*tracer, erts_tracer_true)) {
+ /* Breakpoint trace enabled without specifying tracer =>
* use process tracer and flags
*/
- tracer_pid = &ERTS_TRACER_PROC(p);
- }
- if (is_nil(*tracer_pid)) {
- /* Trace disabled */
- return 0;
+ tracer = &ERTS_TRACER(p);
}
- ASSERT(is_internal_pid(*tracer_pid) || is_internal_port(*tracer_pid));
- if (*tracer_pid == p->common.id) {
- /* Do not generate trace messages to oneself */
+ if (ERTS_TRACER_IS_NIL(*tracer)) {
+ /* Trace disabled */
return 0;
}
- if (tracer_pid == &ERTS_TRACER_PROC(p)) {
+ ASSERT(IS_TRACER_VALID(*tracer));
+ if (tracer == &ERTS_TRACER(p)) {
/* Tracer specified in process structure =>
* non-breakpoint trace =>
* use process flags
*/
tracee_flags = &ERTS_TRACE_FLAGS(p);
-#ifdef ERTS_SMP
- tracee = p->common.id;
-#endif
+ if (!is_tracer_enabled(p, ERTS_PROC_LOCK_MAIN, &p->common, &tnif,
+ TRACE_FUN_E_CALL, am_call)) {
+ return 0;
+ }
} else {
/* Tracer not specified in process structure =>
* tracer specified in breakpoint =>
* meta trace =>
* use fixed flag set instead of process flags
- */
- if (ERTS_TRACE_FLAGS(p) & F_SENSITIVE) {
- /* No trace messages for sensitive processes. */
- return 0;
- }
+ */
+ if (ERTS_TRACE_FLAGS(p) & F_SENSITIVE) {
+ /* No trace messages for sensitive processes. */
+ return 0;
+ }
meta_flags = F_TRACE_CALLS | F_NOW_TS;
tracee_flags = &meta_flags;
-#ifdef ERTS_SMP
- tracee = NIL;
-#endif
+ switch (call_enabled_tracer(p, *tracer,
+ &tnif, TRACE_FUN_T_CALL,
+ am_call, p->common.id)) {
+ default:
+ case am_remove: *tracer = erts_tracer_nil;
+ case am_discard: return 0;
+ case am_trace: break;
+ }
}
/*
@@ -1821,18 +1220,13 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec,
* temporarily convert any match contexts to sub binaries.
*/
arity = (Eterm) mfa[2];
- UseTmpHeap(ERL_SUB_BIN_SIZE,p);
-#ifdef DEBUG
- sub_bin_heap->thing_word = 0;
-#endif
for (i = 0; i < arity; i++) {
Eterm arg = args[i];
if (is_boxed(arg) && header_is_bin_matchstate(*boxed_val(arg))) {
ErlBinMatchState* ms = (ErlBinMatchState *) boxed_val(arg);
ErlBinMatchBuffer* mb = &ms->mb;
Uint bit_size;
-
- ASSERT(sub_bin_heap->thing_word == 0); /* At most one of match context */
+ ErlSubBin *sub_bin_heap = (ErlSubBin *)HAlloc(p, ERL_SUB_BIN_SIZE);
bit_size = mb->size - mb->offset;
sub_bin_heap->thing_word = HEADER_SUB_BIN;
@@ -1849,275 +1243,94 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec,
}
args = transformed_args;
- ts_type = ERTS_TFLGS2TSTYPE(*tracee_flags);
-
- if (is_internal_port(*tracer_pid)) {
- Eterm local_heap[64+ERTS_TRACE_PATCH_TS_MAX_SIZE+MAX_ARG];
- hp = local_heap;
-
- if (!erts_is_valid_tracer_port(*tracer_pid)) {
-#ifdef ERTS_SMP
- ASSERT(is_nil(tracee) || tracer_pid == &ERTS_TRACER_PROC(p));
- if (is_not_nil(tracee))
- erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL_MINOR);
-#endif
- *tracee_flags &= ~TRACEE_FLAGS;
- *tracer_pid = NIL;
-#ifdef ERTS_SMP
- if (is_not_nil(tracee))
- erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL_MINOR);
-#endif
- UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
- return 0;
- }
-
- /*
- * If there is a PAM program, run it. Return if it fails.
- *
- * Some precedence rules:
- *
- * - No proc flags, e.g 'silent' or 'return_to'
- * has any effect on meta trace.
- * - The 'silent' process trace flag silences all call
- * related messages, e.g 'call', 'return_to' and 'return_from'.
- * - The {message,_} PAM function does not affect {return_trace}.
- * - The {message,false} PAM function shall give the same
- * 'call' trace message as no PAM match.
- * - The {message,true} PAM function shall give the same
- * 'call' trace message as a nonexistent PAM program.
- */
-
- /* BEGIN this code should be the same for port and pid trace */
- return_flags = 0;
- if (match_spec) {
- pam_result = erts_match_set_run(p, match_spec, args, arity,
- ERTS_PAM_TMP_RESULT, &return_flags);
- if (is_non_value(pam_result)) {
- erts_match_set_release_result(p);
- UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
- return 0;
- }
- }
- if (tracee_flags == &meta_flags) {
- /* Meta trace */
- if (pam_result == am_false) {
- erts_match_set_release_result(p);
- UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
- return return_flags;
- }
- } else {
- /* Non-meta trace */
- if (*tracee_flags & F_TRACE_SILENT) {
- erts_match_set_release_result(p);
- UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
- return 0;
- }
- if (pam_result == am_false) {
- erts_match_set_release_result(p);
- UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
- return return_flags;
- }
- if (local && (*tracee_flags & F_TRACE_RETURN_TO)) {
- return_flags |= MATCH_SET_RETURN_TO_TRACE;
- }
- }
- /* END this code should be the same for port and pid trace */
-
- /*
- * Build the the {M,F,A} tuple in the local heap.
- * (A is arguments or arity.)
- */
-
- if (*tracee_flags & F_TRACE_ARITY_ONLY) {
- mfa_tuple = make_small(arity);
- } else {
- mfa_tuple = NIL;
- for (i = arity-1; i >= 0; i--) {
- mfa_tuple = CONS(hp, args[i], mfa_tuple);
- hp += 2;
- }
- }
- mfa_tuple = TUPLE3(hp, (Eterm) mfa[0], (Eterm) mfa[1], mfa_tuple);
- hp += 4;
-
- /*
- * Build the trace tuple and send it to the port.
- */
-
- mess = TUPLE4(hp, am_trace, p->common.id, am_call, mfa_tuple);
- hp += 5;
- if (pam_result != am_true) {
- hp[-5] = make_arityval(5);
- *hp++ = pam_result;
- }
- erts_smp_mtx_lock(&smq_mtx);
- PATCH_TS(ts_type, mess, hp, NULL, NULL);
- send_to_port(p, mess, tracer_pid, tracee_flags);
- erts_smp_mtx_unlock(&smq_mtx);
- erts_match_set_release_result(p);
- UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
- return *tracer_pid == NIL ? 0 : return_flags;
+ /*
+ * If there is a PAM program, run it. Return if it fails.
+ *
+ * Some precedence rules:
+ *
+ * - No proc flags, e.g 'silent' or 'return_to'
+ * has any effect on meta trace.
+ * - The 'silent' process trace flag silences all call
+ * related messages, e.g 'call', 'return_to' and 'return_from'.
+ * - The {message,_} PAM function does not affect {return_trace}.
+ * - The {message,false} PAM function shall give the same
+ * 'call' trace message as no PAM match.
+ * - The {message,true} PAM function shall give the same
+ * 'call' trace message as a nonexistent PAM program.
+ */
+ return_flags = 0;
+ if (match_spec) {
+ /* we have to make a copy of the tracer here as the match spec
+ may remove it, and we still want to generate a trace message */
+ erts_tracer_update(&pre_ms_tracer, *tracer);
+ tracer = &pre_ms_tracer;
+ pam_result = erts_match_set_run_trace(p, p,
+ match_spec, args, arity,
+ ERTS_PAM_TMP_RESULT, &return_flags);
+ }
+
+ if (tracee_flags == &meta_flags) {
+ /* Meta trace */
+ if (pam_result == am_false) {
+ UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
+ ERTS_TRACER_CLEAR(&pre_ms_tracer);
+ return return_flags;
+ }
} else {
- ErlHeapFragment *bp;
- ErlOffHeap *off_heap;
- Process *tracer;
- ERTS_TRACER_REF_TYPE tracer_ref;
-#ifdef ERTS_SMP
- Eterm tpid;
-#endif
- unsigned size;
- unsigned sizes[MAX_ARG];
- unsigned pam_result_size = 0;
- int invalid_tracer;
-
- ASSERT(is_internal_pid(*tracer_pid));
-
- tracer = erts_pid2proc(p, ERTS_PROC_LOCK_MAIN,
- *tracer_pid, ERTS_PROC_LOCK_STATUS);
- if (!tracer)
- invalid_tracer = 1;
- else {
- invalid_tracer = !(ERTS_TRACE_FLAGS(tracer) & F_TRACER);
- erts_smp_proc_unlock(tracer, ERTS_PROC_LOCK_STATUS);
- }
-
- if (invalid_tracer) {
-#ifdef ERTS_SMP
- ASSERT(is_nil(tracee)
- || tracer_pid == &ERTS_TRACER_PROC(p));
- if (is_not_nil(tracee))
- erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL_MINOR);
-#endif
- *tracee_flags &= ~TRACEE_FLAGS;
- *tracer_pid = NIL;
-#ifdef ERTS_SMP
- if (is_not_nil(tracee))
- erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL_MINOR);
-#endif
- UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
- return 0;
- }
+ /* Non-meta trace */
+ if (*tracee_flags & F_TRACE_SILENT) {
+ erts_match_set_release_result_trace(p, pam_result);
+ UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
+ ERTS_TRACER_CLEAR(&pre_ms_tracer);
+ return 0;
+ }
+ if (pam_result == am_false) {
+ UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
+ ERTS_TRACER_CLEAR(&pre_ms_tracer);
+ return return_flags;
+ }
+ if (local && (*tracee_flags & F_TRACE_RETURN_TO)) {
+ return_flags |= MATCH_SET_RETURN_TO_TRACE;
+ }
+ }
+
+ ASSERT(!ERTS_TRACER_IS_NIL(*tracer));
-#ifdef ERTS_SMP
- tpid = *tracer_pid; /* Need to save tracer pid,
- since *tracer_pid might
- be reset by erts_match_set_run() */
- tracer_ref = tpid;
-#else
- tracer_ref = tracer;
-#endif
-
- /*
- * If there is a PAM program, run it. Return if it fails.
- *
- * See the rules above in the port trace code.
- */
-
- /* BEGIN this code should be the same for port and pid trace */
- return_flags = 0;
- if (match_spec) {
- pam_result = erts_match_set_run(p, match_spec, args, arity,
- ERTS_PAM_TMP_RESULT, &return_flags);
- if (is_non_value(pam_result)) {
- erts_match_set_release_result(p);
- UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
- return 0;
- }
- }
- if (tracee_flags == &meta_flags) {
- /* Meta trace */
- if (pam_result == am_false) {
- erts_match_set_release_result(p);
- UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
- return return_flags;
- }
- } else {
- /* Non-meta trace */
- if (*tracee_flags & F_TRACE_SILENT) {
- erts_match_set_release_result(p);
- UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
- return 0;
- }
- if (pam_result == am_false) {
- erts_match_set_release_result(p);
- UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
- return return_flags;
- }
- if (local && (*tracee_flags & F_TRACE_RETURN_TO)) {
- return_flags |= MATCH_SET_RETURN_TO_TRACE;
- }
- }
- /* END this code should be the same for port and pid trace */
-
- /*
- * Calculate number of words needed on heap.
- */
-
- size = 4 + 5; /* Trace tuple + MFA tuple. */
- if (! (*tracee_flags & F_TRACE_ARITY_ONLY)) {
- size += 2*arity;
- for (i = arity-1; i >= 0; i--) {
- sizes[i] = size_object(args[i]);
- size += sizes[i];
- }
- }
- size += patch_ts_size(ts_type);
- if (pam_result != am_true) {
- pam_result_size = size_object(pam_result);
- size += 1 + pam_result_size;
- /* One element in trace tuple + term size. */
- }
-
- hp = ERTS_ALLOC_SYSMSG_HEAP(size, &bp, &off_heap, tracer_ref);
-
- /*
- * Build the the {M,F,A} tuple in the message buffer.
- * (A is arguments or arity.)
- */
-
- if (*tracee_flags & F_TRACE_ARITY_ONLY) {
- mfa_tuple = make_small(arity);
- } else {
- mfa_tuple = NIL;
- for (i = arity-1; i >= 0; i--) {
- Eterm term = copy_struct(args[i], sizes[i], &hp, off_heap);
- mfa_tuple = CONS(hp, term, mfa_tuple);
- hp += 2;
- }
- }
- mfa_tuple = TUPLE3(hp, (Eterm) mfa[0], (Eterm) mfa[1], mfa_tuple);
- hp += 4;
-
- /*
- * Copy the PAM result (if any) onto the heap.
- */
-
- if (pam_result != am_true) {
- pam_result = copy_struct(pam_result, pam_result_size, &hp, off_heap);
- }
+ /*
+ * Build the the {M,F,A} tuple in the local heap.
+ * (A is arguments or arity.)
+ */
- erts_match_set_release_result(p);
- /*
- * Build the trace tuple and enqueue it.
- */
-
- mess = TUPLE4(hp, am_trace, p->common.id, am_call, mfa_tuple);
- hp += 5;
- if (pam_result != am_true) {
- hp[-5] = make_arityval(5);
- *hp++ = pam_result;
- }
+ if (*tracee_flags & F_TRACE_ARITY_ONLY) {
+ hp = HAlloc(p, 4);
+ mfa_tuple = make_small(arity);
+ } else {
+ hp = HAlloc(p, 4 + arity * 2);
+ mfa_tuple = NIL;
+ for (i = arity-1; i >= 0; i--) {
+ mfa_tuple = CONS(hp, args[i], mfa_tuple);
+ hp += 2;
+ }
+ }
+ mfa_tuple = TUPLE3(hp, (Eterm) mfa[0], (Eterm) mfa[1], mfa_tuple);
+ hp += 4;
- erts_smp_mtx_lock(&smq_mtx);
+ /*
+ * Build the trace tuple and send it to the port.
+ */
+ send_to_tracer_nif_raw(p, NULL, *tracer, *tracee_flags, p->common.id,
+ tnif, TRACE_FUN_T_CALL, am_call, mfa_tuple,
+ THE_NON_VALUE, pam_result);
- PATCH_TS(ts_type, mess, hp, bp, tracer_ref);
- ERTS_ENQ_TRACE_MSG(tracee, tracer_ref, mess, bp);
- erts_smp_mtx_unlock(&smq_mtx);
- UnUseTmpHeap(ERL_SUB_BIN_SIZE,p);
- return return_flags;
+ if (match_spec) {
+ erts_match_set_release_result_trace(p, pam_result);
+ if (tracer == &pre_ms_tracer)
+ ERTS_TRACER_CLEAR(&pre_ms_tracer);
}
+
+ return return_flags;
}
/* Sends trace message:
@@ -2129,69 +1342,14 @@ erts_call_trace(Process* p, BeamInstr mfa[3], Binary *match_spec,
* 't_p' is the traced process.
*/
void
-trace_proc(Process *c_p, Process *t_p, Eterm what, Eterm data)
+trace_proc(Process *c_p, ErtsProcLocks c_p_locks,
+ Process *t_p, Eterm what, Eterm data)
{
- Eterm mess;
- Eterm* hp;
- int need;
-
- ERTS_SMP_LC_ASSERT((erts_proc_lc_my_proc_locks(t_p) != 0)
- || erts_thr_progress_is_blocking());
- if (is_internal_port(ERTS_TRACER_PROC(t_p))) {
-#define LOCAL_HEAP_SIZE (5+5)
- DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
- UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-
-
- hp = local_heap;
- mess = TUPLE4(hp, am_trace, t_p->common.id, what, data);
- hp += 5;
- erts_smp_mtx_lock(&smq_mtx);
- PATCH_TS(TFLGS_TS_TYPE(t_p), mess, hp, NULL, NULL);
- send_to_port(
-#ifndef ERTS_SMP
- /* No fake schedule out and in again after an exit */
- what == am_exit ? NULL : c_p,
-#else
- /* Fake schedule out and in are never sent when smp enabled */
- c_p,
-#endif
- mess,
- &ERTS_TRACER_PROC(t_p),
- &ERTS_TRACE_FLAGS(t_p));
- UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-#undef LOCAL_HEAP_SIZE
- erts_smp_mtx_unlock(&smq_mtx);
- } else {
- Eterm tmp;
- ErlHeapFragment *bp;
- ErlOffHeap *off_heap;
- ERTS_TRACER_REF_TYPE tracer_ref;
- size_t sz_data;
-
- ASSERT(is_internal_pid(ERTS_TRACER_PROC(t_p)));
-
- ERTS_GET_TRACER_REF(tracer_ref,
- ERTS_TRACER_PROC(t_p),
- ERTS_TRACE_FLAGS(t_p));
-
- sz_data = size_object(data);
-
- need = sz_data + 5 + PATCH_TS_SIZE(t_p);
-
- hp = ERTS_ALLOC_SYSMSG_HEAP(need, &bp, &off_heap, tracer_ref);
-
- tmp = copy_struct(data, sz_data, &hp, off_heap);
- mess = TUPLE4(hp, am_trace, t_p->common.id, what, tmp);
- hp += 5;
-
- erts_smp_mtx_lock(&smq_mtx);
-
- PATCH_TS(TFLGS_TS_TYPE(t_p), mess, hp, bp, tracer_ref);
-
- ERTS_ENQ_TRACE_MSG(t_p->common.id, tracer_ref, mess, bp);
- erts_smp_mtx_unlock(&smq_mtx);
- }
+ ErtsTracerNif *tnif = NULL;
+ if (is_tracer_enabled(c_p, c_p_locks, &t_p->common, &tnif,
+ TRACE_FUN_E_PROCS, what))
+ send_to_tracer_nif(c_p, &t_p->common, t_p->common.id, tnif, TRACE_FUN_T_PROCS,
+ what, data, THE_NON_VALUE, am_true);
}
@@ -2203,77 +1361,38 @@ trace_proc(Process *c_p, Process *t_p, Eterm what, Eterm data)
* and 'args' may be a deep term.
*/
void
-trace_proc_spawn(Process *p, Eterm pid,
+trace_proc_spawn(Process *p, Eterm what, Eterm pid,
Eterm mod, Eterm func, Eterm args)
{
- Eterm mfa;
- Eterm mess;
- Eterm* hp;
-
- if (is_internal_port(ERTS_TRACER_PROC(p))) {
-#define LOCAL_HEAP_SIZE (4+6+5)
- DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
- UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-
- hp = local_heap;
- mfa = TUPLE3(hp, mod, func, args);
- hp += 4;
- mess = TUPLE5(hp, am_trace, p->common.id, am_spawn, pid, mfa);
- hp += 6;
- erts_smp_mtx_lock(&smq_mtx);
- PATCH_TS(TFLGS_TS_TYPE(p), mess, hp, NULL, NULL);
- send_to_port(p, mess, &ERTS_TRACER_PROC(p), &ERTS_TRACE_FLAGS(p));
- UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-#undef LOCAL_HEAP_SIZE
- erts_smp_mtx_unlock(&smq_mtx);
- } else {
- Eterm tmp;
- ErlHeapFragment *bp;
- ErlOffHeap *off_heap;
- ERTS_TRACER_REF_TYPE tracer_ref;
- size_t sz_args, sz_pid;
- Uint need;
-
- ASSERT(is_internal_pid(ERTS_TRACER_PROC(p)));
-
- ERTS_GET_TRACER_REF(tracer_ref,
- ERTS_TRACER_PROC(p),
- ERTS_TRACE_FLAGS(p));
-
- sz_args = size_object(args);
- sz_pid = size_object(pid);
- need = sz_args + 4 + 6 + PATCH_TS_SIZE(p);
-
- hp = ERTS_ALLOC_SYSMSG_HEAP(need, &bp, &off_heap, tracer_ref);
-
- tmp = copy_struct(args, sz_args, &hp, off_heap);
- mfa = TUPLE3(hp, mod, func, tmp);
- hp += 4;
- tmp = copy_struct(pid, sz_pid, &hp, off_heap);
- mess = TUPLE5(hp, am_trace, p->common.id, am_spawn, tmp, mfa);
- hp += 6;
+ ErtsTracerNif *tnif = NULL;
+ if (is_tracer_enabled(p, ERTS_PROC_LOCKS_ALL &
+ ~(ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_TRACE),
+ &p->common, &tnif, TRACE_FUN_E_PROCS, what)) {
+ Eterm mfa;
+ Eterm* hp;
- erts_smp_mtx_lock(&smq_mtx);
-
- PATCH_TS(TFLGS_TS_TYPE(p), mess, hp, bp, tracer_ref);
-
- ERTS_ENQ_TRACE_MSG(p->common.id, tracer_ref, mess, bp);
- erts_smp_mtx_unlock(&smq_mtx);
+ hp = HAlloc(p, 4);
+ mfa = TUPLE3(hp, mod, func, args);
+ hp += 4;
+ send_to_tracer_nif(p, &p->common, p->common.id, tnif, TRACE_FUN_T_PROCS,
+ what, pid, mfa, am_true);
}
}
void save_calls(Process *p, Export *e)
{
- struct saved_calls *scb = ERTS_PROC_GET_SAVED_CALLS_BUF(p);
- if (scb) {
- Export **ct = &scb->ct[0];
- int len = scb->len;
-
- ct[scb->cur] = e;
- if (++scb->cur >= len)
- scb->cur = 0;
- if (scb->n < len)
- scb->n++;
+ if ((ERTS_TRACE_FLAGS(p) & F_SENSITIVE) == 0) {
+ struct saved_calls *scb = ERTS_PROC_GET_SAVED_CALLS_BUF(p);
+ if (scb) {
+ Export **ct = &scb->ct[0];
+ int len = scb->len;
+
+ ct[scb->cur] = e;
+ if (++scb->cur >= len)
+ scb->cur = 0;
+ if (scb->n < len)
+ scb->n++;
+ }
}
}
@@ -2290,68 +1409,26 @@ void save_calls(Process *p, Export *e)
* are all small (atomic) integers.
*/
void
-trace_gc(Process *p, Eterm what)
+trace_gc(Process *p, Eterm what, Uint size)
{
- ErlHeapFragment *bp = NULL;
- ErlOffHeap *off_heap;
- ERTS_TRACER_REF_TYPE tracer_ref = ERTS_NULL_TRACER_REF; /* Initialized
- to eliminate
- compiler
- warning */
+ ErtsTracerNif *tnif = NULL;
Eterm* hp;
Eterm msg = NIL;
- Uint size;
-
-#define LOCAL_HEAP_SIZE \
- (ERTS_PROCESS_GC_INFO_MAX_SIZE) + \
- 5/*4-tuple */ + ERTS_TRACE_PATCH_TS_MAX_SIZE
- DeclareTmpHeap(local_heap,LOCAL_HEAP_SIZE,p);
-
- UseTmpHeap(LOCAL_HEAP_SIZE,p);
-
- if (is_internal_port(ERTS_TRACER_PROC(p))) {
- hp = local_heap;
-#ifdef DEBUG
- size = 0;
- (void) erts_process_gc_info(p, &size, NULL);
-
- size += 5/*4-tuple*/ + PATCH_TS_SIZE(p);
-#endif
- } else {
- ASSERT(is_internal_pid(ERTS_TRACER_PROC(p)));
-
- ERTS_GET_TRACER_REF(tracer_ref,
- ERTS_TRACER_PROC(p),
- ERTS_TRACE_FLAGS(p));
-
- size = 0;
- (void) erts_process_gc_info(p, &size, NULL);
-
- size += 5/*4-tuple*/ + PATCH_TS_SIZE(p);
-
- hp = ERTS_ALLOC_SYSMSG_HEAP(size, &bp, &off_heap, tracer_ref);
- }
-
- ASSERT(size <= LOCAL_HEAP_SIZE);
+ Uint sz = 0;
+ Eterm tup;
- msg = erts_process_gc_info(p, NULL, &hp);
+ if (is_tracer_enabled(p, ERTS_PROC_LOCK_MAIN, &p->common, &tnif, TRACE_FUN_E_GC, what)) {
- msg = TUPLE4(hp, am_trace, p->common.id, what, msg);
- hp += 5;
+ (void) erts_process_gc_info(p, &sz, NULL);
+ hp = HAlloc(p, sz + 3 + 2);
- erts_smp_mtx_lock(&smq_mtx);
+ msg = erts_process_gc_info(p, NULL, &hp);
+ tup = TUPLE2(hp, am_wordsize, make_small(size)); hp += 3;
+ msg = CONS(hp, tup, msg); hp += 2;
- if (is_internal_port(ERTS_TRACER_PROC(p))) {
- PATCH_TS(TFLGS_TS_TYPE(p), msg, hp, NULL, NULL);
- send_to_port(p, msg, &ERTS_TRACER_PROC(p), &ERTS_TRACE_FLAGS(p));
+ send_to_tracer_nif(p, &p->common, p->common.id, tnif, TRACE_FUN_T_GC,
+ what, msg, am_undefined, am_true);
}
- else {
- PATCH_TS(TFLGS_TS_TYPE(p), msg, hp, bp, tracer_ref);
- ERTS_ENQ_TRACE_MSG(p->common.id, tracer_ref, msg, bp);
- }
- erts_smp_mtx_unlock(&smq_mtx);
- UnUseTmpHeap(LOCAL_HEAP_SIZE,p);
-#undef LOCAL_HEAP_SIZE
}
void
@@ -2413,7 +1490,7 @@ monitor_long_schedule_proc(Process *p, BeamInstr *in_fp, BeamInstr *out_fp, Uint
{
ErtsMessage *mp = erts_alloc_message(0, NULL);
mp->data.heap_frag = bp;
- erts_queue_message(monitor_p, NULL, mp, msg, NIL);
+ erts_queue_message(monitor_p, 0, mp, msg, am_system);
}
#endif
}
@@ -2478,7 +1555,7 @@ monitor_long_schedule_port(Port *pp, ErtsPortTaskType type, Uint time)
{
ErtsMessage *mp = erts_alloc_message(0, NULL);
mp->data.heap_frag = bp;
- erts_queue_message(monitor_p, NULL, mp, msg, NIL);
+ erts_queue_message(monitor_p, 0, mp, msg, am_system);
}
#endif
}
@@ -2553,7 +1630,7 @@ monitor_long_gc(Process *p, Uint time) {
{
ErtsMessage *mp = erts_alloc_message(0, NULL);
mp->data.heap_frag = bp;
- erts_queue_message(monitor_p, NULL, mp, msg, NIL);
+ erts_queue_message(monitor_p, 0, mp, msg, am_system);
}
#endif
}
@@ -2628,7 +1705,7 @@ monitor_large_heap(Process *p) {
{
ErtsMessage *mp = erts_alloc_message(0, NULL);
mp->data.heap_frag = bp;
- erts_queue_message(monitor_p, NULL, mp, msg, NIL);
+ erts_queue_message(monitor_p, 0, mp, msg, am_system);
}
#endif
}
@@ -2660,7 +1737,7 @@ monitor_generic(Process *p, Eterm type, Eterm spec) {
{
ErtsMessage *mp = erts_alloc_message(0, NULL);
mp->data.heap_frag = bp;
- erts_queue_message(monitor_p, NULL, mp, msg, NIL);
+ erts_queue_message(monitor_p, 0, mp, msg, am_system);
}
#endif
@@ -2722,106 +1799,15 @@ profile_scheduler(Eterm scheduler_id, Eterm state) {
}
-void
-profile_scheduler_q(Eterm scheduler_id, Eterm state, Eterm no_schedulers, Uint Ms, Uint s, Uint us) {
- Eterm *hp, msg, timestamp;
-
-#ifndef ERTS_SMP
-#define LOCAL_HEAP_SIZE (4 + 7)
- DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
- UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-
- hp = local_heap;
-#else
- ErlHeapFragment *bp;
- Uint hsz;
-
- hsz = 4 + 7;
-
- bp = new_message_buffer(hsz);
- hp = bp->mem;
-#endif
-
- erts_smp_mtx_lock(&smq_mtx);
-
- timestamp = TUPLE3(hp, make_small(Ms), make_small(s), make_small(us)); hp += 4;
- msg = TUPLE6(hp, am_profile, am_scheduler, scheduler_id, state, no_schedulers, timestamp); hp += 7;
-#ifndef ERTS_SMP
- profile_send(NIL, msg);
- UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-#undef LOCAL_HEAP_SIZE
-#else
- enqueue_sys_msg_unlocked(SYS_MSG_TYPE_SYSPROF, NIL, NIL, msg, bp);
-#endif
- erts_smp_mtx_unlock(&smq_mtx);
-
-}
-
-
-/* Send {trace_ts, Pid, What, {Mod, Func, Arity}, Timestamp}
- * or {trace, Pid, What, {Mod, Func, Arity}}
- *
- * where 'What' is supposed to be 'in' or 'out'.
- *
- * Virtual scheduling do not fake scheduling for ports.
- */
-
-
-void trace_virtual_sched(Process *p, Eterm what)
-{
- trace_sched_aux(p, what, 1);
-}
-
/* Port profiling */
void
trace_port_open(Port *p, Eterm calling_pid, Eterm drv_name) {
- Eterm mess;
- Eterm* hp;
-
- if (is_internal_port(ERTS_TRACER_PROC(p))) {
-#define LOCAL_HEAP_SIZE (6+ERTS_TRACE_PATCH_TS_MAX_SIZE)
- DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
- UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-
- hp = local_heap;
-
- mess = TUPLE5(hp, am_trace, calling_pid, am_open, p->common.id, drv_name);
- hp += 6;
- erts_smp_mtx_lock(&smq_mtx);
- PATCH_TS(TFLGS_TS_TYPE(p), mess, hp, NULL, NULL);
- /* No fake schedule */
- send_to_port(NULL, mess, &ERTS_TRACER_PROC(p), &ERTS_TRACE_FLAGS(p));
- UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-#undef LOCAL_HEAP_SIZE
- erts_smp_mtx_unlock(&smq_mtx);
- } else {
- ErlHeapFragment *bp;
- ErlOffHeap *off_heap;
- size_t sz_data;
- ERTS_TRACER_REF_TYPE tracer_ref;
-
- ASSERT(is_internal_pid(ERTS_TRACER_PROC(p)));
-
- sz_data = 6 + PATCH_TS_SIZE(p);
-
- ERTS_GET_TRACER_REF(tracer_ref,
- ERTS_TRACER_PROC(p),
- ERTS_TRACE_FLAGS(p));
-
- hp = ERTS_ALLOC_SYSMSG_HEAP(sz_data, &bp, &off_heap, tracer_ref);
-
- mess = TUPLE5(hp, am_trace, calling_pid, am_open, p->common.id, drv_name);
- hp += 6;
-
- erts_smp_mtx_lock(&smq_mtx);
-
- PATCH_TS(TFLGS_TS_TYPE(p), mess, hp, bp, tracer_ref);
-
- ERTS_ENQ_TRACE_MSG(p->common.id, tracer_ref, mess, bp);
- erts_smp_mtx_unlock(&smq_mtx);
- }
-
+ ErtsTracerNif *tnif = NULL;
+ ERTS_SMP_CHK_NO_PROC_LOCKS;
+ if (is_tracer_enabled(NULL, 0, &p->common, &tnif, TRACE_FUN_E_PORTS, am_open))
+ send_to_tracer_nif(NULL, &p->common, p->common.id, tnif, TRACE_FUN_T_PORTS,
+ am_open, calling_pid, drv_name, am_true);
}
/* Sends trace message:
@@ -2833,52 +1819,211 @@ trace_port_open(Port *p, Eterm calling_pid, Eterm drv_name) {
*/
void
trace_port(Port *t_p, Eterm what, Eterm data) {
- Eterm mess;
- Eterm* hp;
+ ErtsTracerNif *tnif = NULL;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(t_p)
|| erts_thr_progress_is_blocking());
+ ERTS_SMP_CHK_NO_PROC_LOCKS;
+ if (is_tracer_enabled(NULL, 0, &t_p->common, &tnif, TRACE_FUN_E_PORTS, what))
+ send_to_tracer_nif(NULL, &t_p->common, t_p->common.id, tnif, TRACE_FUN_T_PORTS,
+ what, data, THE_NON_VALUE, am_true);
+}
- if (is_internal_port(ERTS_TRACER_PROC(t_p))) {
-#define LOCAL_HEAP_SIZE (5+ERTS_TRACE_PATCH_TS_MAX_SIZE)
- DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
- UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
- hp = local_heap;
- mess = TUPLE4(hp, am_trace, t_p->common.id, what, data);
- hp += 5;
- erts_smp_mtx_lock(&smq_mtx);
- PATCH_TS(TFLGS_TS_TYPE(t_p), mess, hp, NULL, NULL);
- /* No fake schedule */
- send_to_port(NULL,mess,&ERTS_TRACER_PROC(t_p),&ERTS_TRACE_FLAGS(t_p));
- UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-#undef LOCAL_HEAP_SIZE
- erts_smp_mtx_unlock(&smq_mtx);
+static Eterm
+trace_port_tmp_binary(char *bin, Sint sz, Binary **bptrp, Eterm **hp)
+{
+ if (sz <= ERL_ONHEAP_BIN_LIMIT) {
+ ErlHeapBin *hb = (ErlHeapBin *)*hp;
+ hb->thing_word = header_heap_bin(sz);
+ hb->size = sz;
+ sys_memcpy(hb->data, bin, sz);
+ *hp += heap_bin_size(sz);
+ return make_binary(hb);
} else {
- ErlHeapFragment *bp;
- ErlOffHeap *off_heap;
- size_t sz_data;
- ERTS_TRACER_REF_TYPE tracer_ref;
+ ProcBin* pb = (ProcBin *)*hp;
+ Binary *bptr = erts_bin_nrml_alloc(sz);
+ erts_refc_init(&bptr->refc, 1);
+ sys_memcpy(bptr->orig_bytes, bin, sz);
+ pb->thing_word = HEADER_PROC_BIN;
+ pb->size = sz;
+ pb->next = NULL;
+ pb->val = bptr;
+ pb->bytes = (byte*) bptr->orig_bytes;
+ pb->flags = 0;
+ *bptrp = bptr;
+ *hp += PROC_BIN_SIZE;
+ return make_binary(pb);
+ }
+}
+
+/* Sends trace message:
+ * {trace, PortPid, 'receive', {pid(), {command, iolist()}}}
+ * {trace, PortPid, 'receive', {pid(), {control, pid()}}}
+ * {trace, PortPid, 'receive', {pid(), exit}}
+ *
+ */
+void
+trace_port_receive(Port *t_p, Eterm caller, Eterm what, ...)
+{
+ ErtsTracerNif *tnif = NULL;
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(t_p)
+ || erts_thr_progress_is_blocking());
+ ERTS_SMP_CHK_NO_PROC_LOCKS;
+ if (is_tracer_enabled(NULL, 0, &t_p->common, &tnif, TRACE_FUN_E_RECEIVE, am_receive)) {
+ /* We can use a stack heap here, as the nif is called in the
+ context of a port */
+#define LOCAL_HEAP_SIZE (3 + 3 + heap_bin_size(ERL_ONHEAP_BIN_LIMIT) + 3)
+ DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
+
+ Eterm *hp, data, *orig_hp = NULL;
+ Binary *bptr = NULL;
+ va_list args;
+ UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
+ hp = local_heap;
+
+ if (what == am_close) {
+ data = what;
+ } else {
+ Eterm arg;
+ va_start(args, what);
+ if (what == am_command) {
+ char *bin = va_arg(args, char *);
+ Sint sz = va_arg(args, Sint);
+ va_end(args);
+ arg = trace_port_tmp_binary(bin, sz, &bptr, &hp);
+ } else if (what == am_call || what == am_control) {
+ unsigned int command = va_arg(args, unsigned int);
+ char *bin = va_arg(args, char *);
+ Sint sz = va_arg(args, Sint);
+ Eterm cmd;
+ va_end(args);
+ arg = trace_port_tmp_binary(bin, sz, &bptr, &hp);
+#if defined(ARCH_32)
+ if (!IS_USMALL(0, command)) {
+ *hp = make_pos_bignum_header(1);
+ BIG_DIGIT(hp, 0) = (Uint)command;
+ cmd = make_big(hp);
+ hp += 2;
+ } else
+#endif
+ {
+ cmd = make_small((Sint)command);
+ }
+ arg = TUPLE2(hp, cmd, arg);
+ hp += 3;
+ } else if (what == am_commandv) {
+ ErlIOVec *evp = va_arg(args, ErlIOVec*);
+ int i;
+ va_end(args);
+ if ((6 + evp->vsize * (2+PROC_BIN_SIZE+ERL_SUB_BIN_SIZE)) > LOCAL_HEAP_SIZE) {
+ hp = erts_alloc(ERTS_ALC_T_TMP,
+ (6 + evp->vsize * (2+PROC_BIN_SIZE+ERL_SUB_BIN_SIZE)) * sizeof(Eterm));
+ orig_hp = hp;
+ }
+ arg = NIL;
+ /* Convert each element in the ErlIOVec to a sub bin that points
+ to a procbin. We don't have to increment the proc bin refc as
+ the port task keeps the reference alive. */
+ for (i = evp->vsize-1; i >= 0; i--) {
+ if (evp->iov[i].iov_len) {
+ ProcBin* pb = (ProcBin*)hp;
+ ErlSubBin *sb;
+ ASSERT(evp->binv[i]);
+ pb->thing_word = HEADER_PROC_BIN;
+ pb->val = ErlDrvBinary2Binary(evp->binv[i]);
+ pb->size = pb->val->orig_size;
+ pb->next = NULL;
+ pb->bytes = (byte*) pb->val->orig_bytes;
+ pb->flags = 0;
+ hp += PROC_BIN_SIZE;
+
+ sb = (ErlSubBin*) hp;
+ sb->thing_word = HEADER_SUB_BIN;
+ sb->size = evp->iov[i].iov_len;
+ sb->offs = (byte*)(evp->iov[i].iov_base) - pb->bytes;
+ sb->orig = make_binary(pb);
+ sb->bitoffs = 0;
+ sb->bitsize = 0;
+ sb->is_writable = 0;
+ hp += ERL_SUB_BIN_SIZE;
+
+ arg = CONS(hp, make_binary(sb), arg);
+ hp += 2;
+ }
+ }
+ what = am_command;
+ } else {
+ arg = va_arg(args, Eterm);
+ va_end(args);
+ }
+ data = TUPLE2(hp, what, arg);
+ hp += 3;
+ }
+
+ data = TUPLE2(hp, caller, data);
+ hp += 3;
+ ASSERT(hp <= (local_heap + LOCAL_HEAP_SIZE) || orig_hp);
+ send_to_tracer_nif(NULL, &t_p->common, t_p->common.id, tnif,
+ TRACE_FUN_T_RECEIVE,
+ am_receive, data, THE_NON_VALUE, am_true);
+
+ if (bptr && erts_refc_dectest(&bptr->refc, 1) == 0)
+ erts_bin_free(bptr);
+
+ if (orig_hp)
+ erts_free(ERTS_ALC_T_TMP, orig_hp);
+
+ UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
+ }
+#undef LOCAL_HEAP_SIZE
+}
- ASSERT(is_internal_pid(ERTS_TRACER_PROC(t_p)));
+void
+trace_port_send(Port *t_p, Eterm receiver, Eterm msg, int exists)
+{
+ ErtsTracerNif *tnif = NULL;
+ Eterm op = exists ? am_send : am_send_to_non_existing_process;
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(t_p)
+ || erts_thr_progress_is_blocking());
+ ERTS_SMP_CHK_NO_PROC_LOCKS;
+ if (is_tracer_enabled(NULL, 0, &t_p->common, &tnif, TRACE_FUN_E_SEND, op))
+ send_to_tracer_nif(NULL, &t_p->common, t_p->common.id, tnif, TRACE_FUN_T_SEND,
+ op, msg, receiver, am_true);
+}
- sz_data = 5 + PATCH_TS_SIZE(t_p);
+void trace_port_send_binary(Port *t_p, Eterm to, Eterm what, char *bin, Sint sz)
+{
+ ErtsTracerNif *tnif = NULL;
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(t_p)
+ || erts_thr_progress_is_blocking());
+ ERTS_SMP_CHK_NO_PROC_LOCKS;
+ if (is_tracer_enabled(NULL, 0, &t_p->common, &tnif, TRACE_FUN_E_SEND, am_send)) {
+ Eterm msg;
+ Binary* bptr = NULL;
+#define LOCAL_HEAP_SIZE (3 + 3 + heap_bin_size(ERL_ONHEAP_BIN_LIMIT))
+ DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
- ERTS_GET_TRACER_REF(tracer_ref,
- ERTS_TRACER_PROC(t_p),
- ERTS_TRACE_FLAGS(t_p));
+ Eterm *hp;
- hp = ERTS_ALLOC_SYSMSG_HEAP(sz_data, &bp, &off_heap, tracer_ref);
+ ERTS_CT_ASSERT(heap_bin_size(ERL_ONHEAP_BIN_LIMIT) >= PROC_BIN_SIZE);
+ UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
+ hp = local_heap;
- mess = TUPLE4(hp, am_trace, t_p->common.id, what, data);
- hp += 5;
+ msg = trace_port_tmp_binary(bin, sz, &bptr, &hp);
- erts_smp_mtx_lock(&smq_mtx);
+ msg = TUPLE2(hp, what, msg);
+ hp += 3;
+ msg = TUPLE2(hp, t_p->common.id, msg);
+ hp += 3;
- PATCH_TS(TFLGS_TS_TYPE(t_p), mess, hp, bp, tracer_ref);
+ send_to_tracer_nif(NULL, &t_p->common, t_p->common.id, tnif, TRACE_FUN_T_SEND,
+ am_send, msg, to, am_true);
+ if (bptr && erts_refc_dectest(&bptr->refc, 1) == 0)
+ erts_bin_free(bptr);
- ERTS_ENQ_TRACE_MSG(t_p->common.id, tracer_ref, mess, bp);
- erts_smp_mtx_unlock(&smq_mtx);
+ UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
+#undef LOCAL_HEAP_SIZE
}
}
@@ -2892,83 +2037,19 @@ trace_port(Port *t_p, Eterm what, Eterm data) {
void
trace_sched_ports(Port *p, Eterm what) {
- trace_sched_ports_where(p,what, make_small(0));
+ trace_sched_ports_where(p, what, make_small(0));
}
-void
-trace_sched_ports_where(Port *p, Eterm what, Eterm where) {
- Eterm mess;
- Eterm* hp;
- int ws = 5;
- Eterm sched_id = am_undefined;
-
- if (is_internal_port(ERTS_TRACER_PROC(p))) {
-#define LOCAL_HEAP_SIZE (6+ERTS_TRACE_PATCH_TS_MAX_SIZE)
- DeclareTmpHeapNoproc(local_heap,LOCAL_HEAP_SIZE);
- UseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-
- hp = local_heap;
-
- if (IS_TRACED_FL(p, F_TRACE_SCHED_NO)) {
-#ifdef ERTS_SMP
- ErtsSchedulerData *esd = erts_get_scheduler_data();
- if (esd) sched_id = make_small(esd->no);
- else sched_id = am_undefined;
-#else
- sched_id = make_small(1);
-#endif
- mess = TUPLE5(hp, am_trace, p->common.id, what, sched_id, where);
- ws = 6;
- } else {
- mess = TUPLE4(hp, am_trace, p->common.id, what, where);
- ws = 5;
- }
- hp += ws;
-
- erts_smp_mtx_lock(&smq_mtx);
-
- PATCH_TS(TFLGS_TS_TYPE(p), mess, hp, NULL, NULL);
-
- /* No fake scheduling */
- send_to_port(NULL, mess, &ERTS_TRACER_PROC(p), &ERTS_TRACE_FLAGS(p));
- UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE);
-#undef LOCAL_HEAP_SIZE
- erts_smp_mtx_unlock(&smq_mtx);
- } else {
- ErlHeapFragment *bp;
- ErlOffHeap *off_heap;
- ERTS_TRACER_REF_TYPE tracer_ref;
-
- ASSERT(is_internal_pid(ERTS_TRACER_PROC(p)));
-
- if (IS_TRACED_FL(p, F_TRACE_SCHED_NO)) ws = 6; /* Make place for scheduler id */
-
- ERTS_GET_TRACER_REF(tracer_ref,
- ERTS_TRACER_PROC(p),
- ERTS_TRACE_FLAGS(p));
-
- hp = ERTS_ALLOC_SYSMSG_HEAP(ws+PATCH_TS_SIZE(p), &bp, &off_heap, tracer_ref);
-
- if (IS_TRACED_FL(p, F_TRACE_SCHED_NO)) {
-#ifdef ERTS_SMP
- ErtsSchedulerData *esd = erts_get_scheduler_data();
- if (esd) sched_id = make_small(esd->no);
- else sched_id = am_undefined;
-#else
- sched_id = make_small(1);
-#endif
- mess = TUPLE5(hp, am_trace, p->common.id, what, sched_id, where);
- } else {
- mess = TUPLE4(hp, am_trace, p->common.id, what, where);
- }
- hp += ws;
-
- erts_smp_mtx_lock(&smq_mtx);
-
- PATCH_TS(TFLGS_TS_TYPE(p), mess, hp, bp, tracer_ref);
- ERTS_ENQ_TRACE_MSG(p->common.id, tracer_ref, mess, bp);
- erts_smp_mtx_unlock(&smq_mtx);
- }
+void
+trace_sched_ports_where(Port *t_p, Eterm what, Eterm where) {
+ ErtsTracerNif *tnif = NULL;
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(t_p)
+ || erts_thr_progress_is_blocking());
+ ERTS_SMP_CHK_NO_PROC_LOCKS;
+ if (is_tracer_enabled(NULL, 0, &t_p->common, &tnif, TRACE_FUN_E_SCHED_PORT, what))
+ send_to_tracer_nif(NULL, &t_p->common, t_p->common.id,
+ tnif, TRACE_FUN_T_SCHED_PORT,
+ what, where, THE_NON_VALUE, am_true);
}
/* Port profiling */
@@ -3021,6 +2102,7 @@ profile_runnable_proc(Process *p, Eterm status){
Eterm *hp, msg;
Eterm where = am_undefined;
ErlHeapFragment *bp = NULL;
+ int use_current = 1;
#ifndef ERTS_SMP
#define LOCAL_HEAP_SIZE (4 + 6 + ERTS_TRACE_PATCH_TS_MAX_SIZE)
@@ -3033,12 +2115,19 @@ profile_runnable_proc(Process *p, Eterm status){
Uint hsz = 4 + 6 + patch_ts_size(erts_system_profile_ts_type)-1;
#endif
- if (!p->current) {
- p->current = find_function_from_pc(p->i);
+ if (ERTS_PROC_IS_EXITING(p)) {
+ use_current = 0;
+ /* could probably set 'where' to 'exiting' here,
+ * though it's not documented as such */
+ } else {
+ if (!p->current) {
+ p->current = find_function_from_pc(p->i);
+ }
+ use_current = p->current != NULL;
}
#ifdef ERTS_SMP
- if (!p->current) {
+ if (!use_current) {
hsz -= 4;
}
@@ -3046,7 +2135,7 @@ profile_runnable_proc(Process *p, Eterm status){
hp = bp->mem;
#endif
- if (p->current) {
+ if (use_current) {
where = TUPLE3(hp, p->current[0], p->current[1], make_small(p->current[2])); hp += 4;
} else {
where = make_small(0);
@@ -3076,28 +2165,6 @@ profile_runnable_proc(Process *p, Eterm status){
#ifdef ERTS_SMP
-void
-erts_check_my_tracer_proc(Process *p)
-{
- if (is_internal_pid(ERTS_TRACER_PROC(p))) {
- Process *tracer = erts_pid2proc(p,
- ERTS_PROC_LOCK_MAIN,
- ERTS_TRACER_PROC(p),
- ERTS_PROC_LOCK_STATUS);
- int invalid_tracer = (!tracer
- || !(ERTS_TRACE_FLAGS(tracer) & F_TRACER));
- if (tracer)
- erts_smp_proc_unlock(tracer, ERTS_PROC_LOCK_STATUS);
- if (invalid_tracer) {
- erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL_MINOR);
- ERTS_TRACE_FLAGS(p) &= ~TRACEE_FLAGS;
- ERTS_TRACER_PROC(p) = NIL;
- erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL_MINOR);
- }
- }
-}
-
-
typedef struct ErtsSysMsgQ_ ErtsSysMsgQ;
struct ErtsSysMsgQ_ {
ErtsSysMsgQ *next;
@@ -3175,12 +2242,6 @@ static void
print_msg_type(ErtsSysMsgQ *smqp)
{
switch (smqp->type) {
- case SYS_MSG_TYPE_TRACE:
- erts_fprintf(stderr, "TRACE ");
- break;
- case SYS_MSG_TYPE_SEQTRACE:
- erts_fprintf(stderr, "SEQTRACE ");
- break;
case SYS_MSG_TYPE_SYSMON:
erts_fprintf(stderr, "SYSMON ");
break;
@@ -3191,8 +2252,8 @@ print_msg_type(ErtsSysMsgQ *smqp)
erts_fprintf(stderr, "ERRLGR ");
break;
case SYS_MSG_TYPE_PROC_MSG:
- erts_fprintf(stderr, "PROC_MSG ");
- break;
+ erts_fprintf(stderr, "PROC_MSG ");
+ break;
default:
erts_fprintf(stderr, "??? ");
break;
@@ -3204,17 +2265,6 @@ static void
sys_msg_disp_failure(ErtsSysMsgQ *smqp, Eterm receiver)
{
switch (smqp->type) {
- case SYS_MSG_TYPE_TRACE:
- /* Invalid tracer_proc's are removed when processes
- are scheduled in. */
- break;
- case SYS_MSG_TYPE_SEQTRACE:
- /* Reset seq_tracer if it hasn't changed */
- erts_smp_rwmtx_rwlock(&sys_trace_rwmtx);
- if (system_seq_tracer == receiver)
- system_seq_tracer = am_false;
- erts_smp_rwmtx_rwunlock(&sys_trace_rwmtx);
- break;
case SYS_MSG_TYPE_SYSMON:
if (receiver == NIL
&& !erts_system_monitor_long_gc
@@ -3275,7 +2325,7 @@ sys_msg_disp_failure(ErtsSysMsgQ *smqp, Eterm receiver)
break;
}
case SYS_MSG_TYPE_PROC_MSG:
- break;
+ break;
default:
ASSERT(0);
}
@@ -3393,13 +2443,9 @@ sys_msg_dispatcher_func(void *unused)
print_msg_type(smqp);
#endif
switch (smqp->type) {
- case SYS_MSG_TYPE_TRACE:
- case SYS_MSG_TYPE_PROC_MSG:
- receiver = smqp->to;
- break;
- case SYS_MSG_TYPE_SEQTRACE:
- receiver = erts_get_system_seq_tracer();
- break;
+ case SYS_MSG_TYPE_PROC_MSG:
+ receiver = smqp->to;
+ break;
case SYS_MSG_TYPE_SYSMON:
receiver = erts_get_system_monitor();
if (smqp->from == receiver) {
@@ -3434,16 +2480,8 @@ sys_msg_dispatcher_func(void *unused)
if (is_internal_pid(receiver)) {
proc = erts_pid2proc(NULL, 0, receiver, proc_locks);
- if (!proc
- || (smqp->type == SYS_MSG_TYPE_TRACE
- && !(ERTS_TRACE_FLAGS(proc) & F_TRACER))) {
+ if (!proc) {
/* Bad tracer */
-#ifdef DEBUG_PRINTOUTS
- if (smqp->type == SYS_MSG_TYPE_TRACE && proc)
- erts_fprintf(stderr,
- "<tracer alive but missing "
- "F_TRACER flag> ");
-#endif
goto failure;
}
else {
@@ -3451,7 +2489,7 @@ sys_msg_dispatcher_func(void *unused)
queue_proc_msg:
mp = erts_alloc_message(0, NULL);
mp->data.heap_frag = smqp->bp;
- erts_queue_message(proc,&proc_locks,mp,smqp->msg,NIL);
+ erts_queue_message(proc,proc_locks,mp,smqp->msg,am_system);
#ifdef DEBUG_PRINTOUTS
erts_fprintf(stderr, "delivered\n");
#endif
@@ -3517,12 +2555,6 @@ erts_foreach_sys_msg_in_q(void (*func)(Eterm,
for (sm = sys_message_queue; sm; sm = sm->next) {
Eterm to;
switch (sm->type) {
- case SYS_MSG_TYPE_TRACE:
- to = sm->to;
- break;
- case SYS_MSG_TYPE_SEQTRACE:
- to = erts_get_system_seq_tracer();
- break;
case SYS_MSG_TYPE_SYSMON:
to = erts_get_system_monitor();
break;
@@ -3560,3 +2592,589 @@ init_sys_msg_dispatcher(void)
}
#endif
+
+#include "erl_nif.h"
+
+typedef struct {
+ char *name;
+ Uint arity;
+ ErlNifFunc *cb;
+} ErtsTracerType;
+
+struct ErtsTracerNif_ {
+ HashBucket hb;
+ Eterm module;
+ struct erl_module_nif* nif_mod;
+ ErtsTracerType tracers[NIF_TRACER_TYPES];
+};
+
+static void init_tracer_template(ErtsTracerNif *tnif) {
+
+ /* default tracer functions */
+ tnif->tracers[TRACE_FUN_DEFAULT].name = "trace";
+ tnif->tracers[TRACE_FUN_DEFAULT].arity = 6;
+ tnif->tracers[TRACE_FUN_DEFAULT].cb = NULL;
+
+ tnif->tracers[TRACE_FUN_ENABLED].name = "enabled";
+ tnif->tracers[TRACE_FUN_ENABLED].arity = 3;
+ tnif->tracers[TRACE_FUN_ENABLED].cb = NULL;
+
+ /* specific tracer functions */
+ tnif->tracers[TRACE_FUN_T_SEND].name = "trace_send";
+ tnif->tracers[TRACE_FUN_T_SEND].arity = 6;
+ tnif->tracers[TRACE_FUN_T_SEND].cb = NULL;
+
+ tnif->tracers[TRACE_FUN_T_RECEIVE].name = "trace_receive";
+ tnif->tracers[TRACE_FUN_T_RECEIVE].arity = 6;
+ tnif->tracers[TRACE_FUN_T_RECEIVE].cb = NULL;
+
+ tnif->tracers[TRACE_FUN_T_CALL].name = "trace_call";
+ tnif->tracers[TRACE_FUN_T_CALL].arity = 6;
+ tnif->tracers[TRACE_FUN_T_CALL].cb = NULL;
+
+ tnif->tracers[TRACE_FUN_T_SCHED_PROC].name = "trace_running_procs";
+ tnif->tracers[TRACE_FUN_T_SCHED_PROC].arity = 6;
+ tnif->tracers[TRACE_FUN_T_SCHED_PROC].cb = NULL;
+
+ tnif->tracers[TRACE_FUN_T_SCHED_PORT].name = "trace_running_ports";
+ tnif->tracers[TRACE_FUN_T_SCHED_PORT].arity = 6;
+ tnif->tracers[TRACE_FUN_T_SCHED_PORT].cb = NULL;
+
+ tnif->tracers[TRACE_FUN_T_GC].name = "trace_garbage_collection";
+ tnif->tracers[TRACE_FUN_T_GC].arity = 6;
+ tnif->tracers[TRACE_FUN_T_GC].cb = NULL;
+
+ tnif->tracers[TRACE_FUN_T_PROCS].name = "trace_procs";
+ tnif->tracers[TRACE_FUN_T_PROCS].arity = 6;
+ tnif->tracers[TRACE_FUN_T_PROCS].cb = NULL;
+
+ tnif->tracers[TRACE_FUN_T_PORTS].name = "trace_ports";
+ tnif->tracers[TRACE_FUN_T_PORTS].arity = 6;
+ tnif->tracers[TRACE_FUN_T_PORTS].cb = NULL;
+
+ /* specific enabled functions */
+ tnif->tracers[TRACE_FUN_E_SEND].name = "enabled_send";
+ tnif->tracers[TRACE_FUN_E_SEND].arity = 3;
+ tnif->tracers[TRACE_FUN_E_SEND].cb = NULL;
+
+ tnif->tracers[TRACE_FUN_E_RECEIVE].name = "enabled_receive";
+ tnif->tracers[TRACE_FUN_E_RECEIVE].arity = 3;
+ tnif->tracers[TRACE_FUN_E_RECEIVE].cb = NULL;
+
+ tnif->tracers[TRACE_FUN_E_CALL].name = "enabled_call";
+ tnif->tracers[TRACE_FUN_E_CALL].arity = 3;
+ tnif->tracers[TRACE_FUN_E_CALL].cb = NULL;
+
+ tnif->tracers[TRACE_FUN_E_SCHED_PROC].name = "enabled_running_procs";
+ tnif->tracers[TRACE_FUN_E_SCHED_PROC].arity = 3;
+ tnif->tracers[TRACE_FUN_E_SCHED_PROC].cb = NULL;
+
+ tnif->tracers[TRACE_FUN_E_SCHED_PORT].name = "enabled_running_ports";
+ tnif->tracers[TRACE_FUN_E_SCHED_PORT].arity = 3;
+ tnif->tracers[TRACE_FUN_E_SCHED_PORT].cb = NULL;
+
+ tnif->tracers[TRACE_FUN_E_GC].name = "enabled_garbage_collection";
+ tnif->tracers[TRACE_FUN_E_GC].arity = 3;
+ tnif->tracers[TRACE_FUN_E_GC].cb = NULL;
+
+ tnif->tracers[TRACE_FUN_E_PROCS].name = "enabled_procs";
+ tnif->tracers[TRACE_FUN_E_PROCS].arity = 3;
+ tnif->tracers[TRACE_FUN_E_PROCS].cb = NULL;
+
+ tnif->tracers[TRACE_FUN_E_PORTS].name = "enabled_ports";
+ tnif->tracers[TRACE_FUN_E_PORTS].arity = 3;
+ tnif->tracers[TRACE_FUN_E_PORTS].cb = NULL;
+}
+
+static Hash *tracer_hash = NULL;
+static erts_smp_rwmtx_t tracer_mtx;
+
+static ErtsTracerNif *
+load_tracer_nif(const ErtsTracer tracer)
+{
+ Module* mod = erts_get_module(ERTS_TRACER_MODULE(tracer),
+ erts_active_code_ix());
+ struct erl_module_instance *instance;
+ ErlNifFunc *funcs;
+ int num_of_funcs;
+ ErtsTracerNif tnif_tmpl, *tnif;
+ ErtsTracerType *tracers;
+ int i,j;
+
+ if (!mod || !mod->curr.nif) {
+ return NULL;
+ }
+
+ instance = &mod->curr;
+
+ init_tracer_template(&tnif_tmpl);
+ tnif_tmpl.nif_mod = instance->nif;
+ tnif_tmpl.module = ERTS_TRACER_MODULE(tracer);
+ tracers = tnif_tmpl.tracers;
+
+ num_of_funcs = erts_nif_get_funcs(instance->nif, &funcs);
+
+ for(i = 0; i < num_of_funcs; i++) {
+ for (j = 0; j < NIF_TRACER_TYPES; j++) {
+ if (strcmp(tracers[j].name, funcs[i].name) == 0 && tracers[j].arity == funcs[i].arity) {
+ tracers[j].cb = &(funcs[i]);
+ break;
+ }
+ }
+ }
+
+ if (tracers[TRACE_FUN_DEFAULT].cb == NULL || tracers[TRACE_FUN_ENABLED].cb == NULL ) {
+ return NULL;
+ }
+
+ erts_smp_rwmtx_rwlock(&tracer_mtx);
+ tnif = hash_put(tracer_hash, &tnif_tmpl);
+ erts_smp_rwmtx_rwunlock(&tracer_mtx);
+
+ return tnif;
+}
+
+static ERTS_INLINE ErtsTracerNif *
+lookup_tracer_nif(const ErtsTracer tracer)
+{
+ ErtsTracerNif tnif_tmpl;
+ ErtsTracerNif *tnif;
+ tnif_tmpl.module = ERTS_TRACER_MODULE(tracer);
+ erts_smp_rwmtx_rlock(&tracer_mtx);
+ if ((tnif = hash_get(tracer_hash, &tnif_tmpl)) == NULL) {
+ erts_smp_rwmtx_runlock(&tracer_mtx);
+ tnif = load_tracer_nif(tracer);
+ ASSERT(!tnif || tnif->nif_mod);
+ return tnif;
+ }
+ erts_smp_rwmtx_runlock(&tracer_mtx);
+ ASSERT(tnif->nif_mod);
+ return tnif;
+}
+
+/* This function converts an Erlang tracer term to ErtsTracer.
+ It returns THE_NON_VALUE if an invalid tracer term was given.
+ Accepted input is:
+ pid() || port() || {prefix, pid()} || {prefix, port()} ||
+ {prefix, atom(), term()} || {atom(), term()}
+ */
+ErtsTracer
+erts_term_to_tracer(Eterm prefix, Eterm t)
+{
+ ErtsTracer tracer = erts_tracer_nil;
+ ASSERT(is_atom(prefix) || prefix == THE_NON_VALUE);
+ if (!is_nil(t)) {
+ Eterm module = am_erl_tracer, state = THE_NON_VALUE;
+ Eterm hp[2];
+ if (is_tuple(t)) {
+ Eterm *tp = tuple_val(t);
+ if (prefix != THE_NON_VALUE) {
+ if (arityval(tp[0]) == 2 && tp[1] == prefix)
+ t = tp[2];
+ else if (arityval(tp[0]) == 3 && tp[1] == prefix && is_atom(tp[2])) {
+ module = tp[2];
+ state = tp[3];
+ }
+ } else {
+ if (arityval(tp[0]) == 2 && is_atom(tp[2])) {
+ module = tp[1];
+ state = tp[2];
+ }
+ }
+ }
+ if (state == THE_NON_VALUE && (is_internal_pid(t) || is_internal_port(t)))
+ state = t;
+ if (state == THE_NON_VALUE)
+ return THE_NON_VALUE;
+ erts_tracer_update(&tracer, CONS(hp, module, state));
+ }
+ if (!lookup_tracer_nif(tracer)) {
+ ASSERT(ERTS_TRACER_MODULE(tracer) != am_erl_tracer);
+ ERTS_TRACER_CLEAR(&tracer);
+ return THE_NON_VALUE;
+ }
+ return tracer;
+}
+
+Eterm
+erts_tracer_to_term(Process *p, ErtsTracer tracer)
+{
+ if (ERTS_TRACER_IS_NIL(tracer))
+ return am_false;
+ if (ERTS_TRACER_MODULE(tracer) == am_erl_tracer)
+ /* Have to manage these specifically in order to be
+ backwards compatible */
+ return ERTS_TRACER_STATE(tracer);
+ else {
+ Eterm *hp = HAlloc(p, 3);
+ return TUPLE2(hp, ERTS_TRACER_MODULE(tracer),
+ copy_object(ERTS_TRACER_STATE(tracer), p));
+ }
+}
+
+
+static ERTS_INLINE int
+send_to_tracer_nif_raw(Process *c_p, Process *tracee,
+ const ErtsTracer tracer, Uint tracee_flags,
+ Eterm t_p_id, ErtsTracerNif *tnif,
+ enum ErtsTracerOpt topt,
+ Eterm tag, Eterm msg, Eterm extra, Eterm pam_result)
+{
+ if (tnif || (tnif = lookup_tracer_nif(tracer)) != NULL) {
+#define MAP_SIZE 3
+ Eterm argv[6], local_heap[3+MAP_SIZE /* values */ + (MAP_SIZE+1 /* keys */)];
+ flatmap_t *map = (flatmap_t*)(local_heap+(MAP_SIZE+1));
+ Eterm *map_values = flatmap_get_values(map);
+
+ topt = (tnif->tracers[topt].cb) ? topt : TRACE_FUN_DEFAULT;
+ ASSERT(topt < NIF_TRACER_TYPES);
+
+ argv[0] = tag;
+ argv[1] = ERTS_TRACER_STATE(tracer);
+ argv[2] = t_p_id;
+ argv[3] = msg;
+ argv[4] = extra == THE_NON_VALUE ? am_undefined : extra;
+ argv[5] = make_flatmap(map);
+
+ map->thing_word = MAP_HEADER_FLATMAP;
+ map->size = MAP_SIZE;
+ map->keys = TUPLE3(local_heap, am_match_spec_result, am_scheduler_id, am_timestamp);
+
+ *map_values++ = pam_result;
+ if (tracee_flags & F_TRACE_SCHED_NO)
+ *map_values++ = make_small(erts_get_scheduler_id());
+ else
+ *map_values++ = am_undefined;
+ if (tracee_flags & F_NOW_TS)
+#ifdef HAVE_ERTS_NOW_CPU
+ if (erts_cpu_timestamp)
+ *map_values++ = am_cpu_timestamp;
+ else
+#endif
+ *map_values++ = am_timestamp;
+ else if (tracee_flags & F_STRICT_MON_TS)
+ *map_values++ = am_strict_monotonic;
+ else if (tracee_flags & F_MON_TS)
+ *map_values++ = am_monotonic;
+ else
+ *map_values++ = am_undefined;
+
+#undef MAP_SIZE
+ erts_nif_call_function(c_p, tracee ? tracee : c_p,
+ tnif->nif_mod,
+ tnif->tracers[topt].cb,
+ tnif->tracers[topt].arity,
+ argv);
+ }
+ return 1;
+}
+
+static ERTS_INLINE int
+send_to_tracer_nif(Process *c_p, ErtsPTabElementCommon *t_p,
+ Eterm t_p_id, ErtsTracerNif *tnif, enum ErtsTracerOpt topt,
+ Eterm tag, Eterm msg, Eterm extra, Eterm pam_result)
+{
+#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)
+ if (c_p) {
+ /* We have to hold the main lock of the currently executing process */
+ erts_proc_lc_chk_have_proc_locks(c_p, ERTS_PROC_LOCK_MAIN);
+ }
+ if (is_internal_pid(t_p->id)) {
+ /* We have to have at least one lock */
+ ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks((Process*)t_p) & ERTS_PROC_LOCKS_ALL);
+ } else {
+ ASSERT(is_internal_port(t_p->id));
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked((Port*)t_p));
+ }
+#endif
+
+ return send_to_tracer_nif_raw(c_p,
+ is_internal_pid(t_p->id) ? (Process*)t_p : NULL,
+ t_p->tracer, t_p->trace_flags,
+ t_p_id, tnif, topt, tag, msg, extra,
+ pam_result);
+}
+
+static ERTS_INLINE Eterm
+call_enabled_tracer(Process *c_p, const ErtsTracer tracer,
+ ErtsTracerNif **tnif_ret,
+ enum ErtsTracerOpt topt,
+ Eterm tag, Eterm t_p_id) {
+ ErtsTracerNif *tnif = lookup_tracer_nif(tracer);
+ if (tnif) {
+ Eterm argv[] = {tag, ERTS_TRACER_STATE(tracer), t_p_id};
+ topt = (tnif->tracers[topt].cb) ? topt : TRACE_FUN_ENABLED;
+ ASSERT(topt < NIF_TRACER_TYPES);
+ ASSERT(tnif->tracers[topt].cb != NULL);
+ if (tnif_ret) *tnif_ret = tnif;
+ return erts_nif_call_function(c_p, NULL, tnif->nif_mod,
+ tnif->tracers[topt].cb,
+ tnif->tracers[topt].arity,
+ argv);
+ }
+ return am_remove;
+}
+
+static int
+is_tracer_enabled(Process* c_p, ErtsProcLocks c_p_locks,
+ ErtsPTabElementCommon *t_p,
+ ErtsTracerNif **tnif_ret,
+ enum ErtsTracerOpt topt, Eterm tag) {
+ Eterm nif_result;
+
+#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)
+ if (c_p)
+ ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks(c_p) == c_p_locks
+ || erts_thr_progress_is_blocking());
+ if (is_internal_pid(t_p->id)) {
+ /* We have to have at least one lock */
+ ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks((Process*)t_p) & ERTS_PROC_LOCKS_ALL
+ || erts_thr_progress_is_blocking());
+ } else {
+ ASSERT(is_internal_port(t_p->id));
+ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked((Port*)t_p)
+ || erts_thr_progress_is_blocking());
+ }
+#endif
+
+ nif_result = call_enabled_tracer(c_p, t_p->tracer, tnif_ret, topt, tag, t_p->id);
+ switch (nif_result) {
+ case am_discard: return 0;
+ case am_trace: return 1;
+ case THE_NON_VALUE:
+ case am_remove: break;
+ default:
+ /* only am_remove should be returned, but if
+ something else is returned we fall-through
+ and remove the tracer. */
+ ASSERT(0);
+ }
+
+ /* Only remove tracer on self() and ports */
+ if (is_internal_port(t_p->id) || (c_p && c_p->common.id == t_p->id)) {
+ ErtsProcLocks c_p_xlocks = 0;
+ if (is_internal_pid(t_p->id)) {
+ ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks(c_p) & ERTS_PROC_LOCK_MAIN);
+ if (c_p_locks != ERTS_PROC_LOCKS_ALL) {
+ c_p_xlocks = ~c_p_locks & ERTS_PROC_LOCKS_ALL;
+ if (erts_smp_proc_trylock(c_p, c_p_xlocks) == EBUSY) {
+ erts_smp_proc_unlock(c_p, c_p_locks & ~ERTS_PROC_LOCK_MAIN);
+ erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
+ }
+ }
+ }
+ erts_tracer_replace(t_p, erts_tracer_nil);
+ t_p->trace_flags &= ~TRACEE_FLAGS;
+
+ if (c_p_xlocks)
+ erts_smp_proc_unlock(c_p, c_p_xlocks);
+ }
+
+ return 0;
+}
+
+int erts_is_tracer_proc_enabled(Process* c_p, ErtsProcLocks c_p_locks,
+ ErtsPTabElementCommon *t_p, Eterm type)
+{
+ return is_tracer_enabled(c_p, c_p_locks, t_p, NULL, TRACE_FUN_ENABLED, am_trace_status);
+}
+
+int erts_is_tracer_enabled(Process *c_p, const ErtsTracer tracer)
+{
+ ErtsTracerNif *tnif = lookup_tracer_nif(tracer);
+ if (tnif) {
+ Eterm nif_result = call_enabled_tracer(c_p, tracer, &tnif,
+ TRACE_FUN_ENABLED, am_trace_status,
+ c_p->common.id);
+ switch (nif_result) {
+ case am_discard:
+ case am_trace: return 1;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+void erts_tracer_replace(ErtsPTabElementCommon *t_p, const ErtsTracer tracer)
+{
+#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)
+ if (is_internal_pid(t_p->id) && !erts_thr_progress_is_blocking()) {
+ erts_proc_lc_chk_have_proc_locks((Process*)t_p, ERTS_PROC_LOCKS_ALL);
+ } else if (is_internal_port(t_p->id)) {
+ ERTS_LC_ASSERT(erts_lc_is_port_locked((Port*)t_p)
+ || erts_thr_progress_is_blocking());
+ }
+#endif
+ if (ERTS_TRACER_COMPARE(t_p->tracer, tracer))
+ return;
+
+ erts_tracer_update(&t_p->tracer, tracer);
+}
+
+static void free_tracer(void *p)
+{
+ ErtsTracer tracer = (ErtsTracer)p;
+
+ if (is_immed(ERTS_TRACER_STATE(tracer))) {
+ erts_free(ERTS_ALC_T_HEAP_FRAG, ptr_val(tracer));
+ } else {
+ ErlHeapFragment *hf = (void*)((char*)(ptr_val(tracer)) - offsetof(ErlHeapFragment, mem));
+ free_message_buffer(hf);
+ }
+}
+
+/* un-define erts_tracer_update before implementation */
+#ifdef erts_tracer_update
+#undef erts_tracer_update
+#endif
+
+/*
+ * ErtsTracer is either NIL, 'true' or [Mod | State]
+ *
+ * - If State is immediate then the memory for
+ * the cons cell is just two words + sizeof(ErtsThrPrgrLaterOp) large.
+ * - If State is a complex term then the cons cell
+ * is allocated in an ErlHeapFragment where the cons
+ * ptr points to the mem field. So in order to get the
+ * ptr to the fragment you do this:
+ * (char*)(ptr_val(tracer)) - offsetof(ErlHeapFragment, mem)
+ * Normally you shouldn't have to care about this though
+ * as erts_tracer_update takes care of it for you.
+ *
+ * When ErtsTracer is stored in the stack as part of a
+ * return trace, the cons cell is stored on the heap of
+ * the process.
+ *
+ * The cons cell is not always stored on the heap as:
+ * 1) for port/meta tracing there is no heap
+ * 2) we would need the main lock in order to
+ * read the tracer which is undesirable.
+ *
+ * One way to optimize this (memory wise) is to keep an refc and only bump
+ * the refc when *tracer is NIL.
+ */
+void
+erts_tracer_update(ErtsTracer *tracer, const ErtsTracer new_tracer)
+{
+ ErlHeapFragment *hf;
+
+ if (is_not_nil(*tracer)) {
+ Uint offs = 2;
+ UWord size = 2 * sizeof(Eterm) + sizeof(ErtsThrPrgrLaterOp);
+ ASSERT(is_list(*tracer));
+ if (is_not_immed(ERTS_TRACER_STATE(*tracer))) {
+ hf = (void*)(((char*)(ptr_val(*tracer)) - offsetof(ErlHeapFragment, mem)));
+ offs = hf->used_size;
+ size = hf->alloc_size * sizeof(Eterm) + sizeof(ErlHeapFragment);
+ ASSERT(offs == size_object(*tracer));
+ }
+ /* We schedule the free:ing of the tracer until after a thread progress
+ has been made so that we know that no schedulers have any references
+ to it. Because we do this, it is possible to release all locks of a
+ process/port and still use the ErtsTracer of that port/process
+ without having to worry if it is free'd.
+ */
+ erts_schedule_thr_prgr_later_cleanup_op(
+ free_tracer, (void*)(*tracer),
+ (ErtsThrPrgrLaterOp*)(ptr_val(*tracer) + offs),
+ size);
+ }
+
+ if (is_nil(new_tracer)) {
+ *tracer = new_tracer;
+ } else if (is_immed(ERTS_TRACER_STATE(new_tracer))) {
+ /* If tracer state is an immediate we only allocate a 2 Eterm heap.
+ Not sure if it is worth it, we save 4 words (sizeof(ErlHeapFragment))
+ per tracer. */
+ Eterm *hp = erts_alloc(ERTS_ALC_T_HEAP_FRAG,
+ 2*sizeof(Eterm) + sizeof(ErtsThrPrgrLaterOp));
+ *tracer = CONS(hp, ERTS_TRACER_MODULE(new_tracer),
+ ERTS_TRACER_STATE(new_tracer));
+ } else {
+ Eterm *hp, tracer_state = ERTS_TRACER_STATE(new_tracer),
+ tracer_module = ERTS_TRACER_MODULE(new_tracer);
+ Uint sz = size_object(tracer_state);
+ hf = new_message_buffer(sz + 2 /* cons cell */ + (sizeof(ErtsThrPrgrLaterOp)+sizeof(Eterm)-1)/sizeof(Eterm));
+ hp = hf->mem + 2;
+ hf->used_size -= (sizeof(ErtsThrPrgrLaterOp)+sizeof(Eterm)-1)/sizeof(Eterm);
+ *tracer = copy_struct(tracer_state, sz, &hp, &hf->off_heap);
+ *tracer = CONS(hf->mem, tracer_module, *tracer);
+ ASSERT((void*)(((char*)(ptr_val(*tracer)) - offsetof(ErlHeapFragment, mem))) == hf);
+ }
+}
+
+static void init_tracer_nif()
+{
+ erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER;
+ rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_EXTREMELY_FREQUENT_READ;
+ rwmtx_opt.lived = ERTS_SMP_RWMTX_LONG_LIVED;
+ erts_smp_rwmtx_init_opt(&tracer_mtx, &rwmtx_opt, "tracer_mtx");
+
+ erts_tracer_nif_clear();
+
+}
+
+int erts_tracer_nif_clear()
+{
+
+ erts_smp_rwmtx_rlock(&tracer_mtx);
+ if (!tracer_hash || tracer_hash->nobjs) {
+
+ HashFunctions hf;
+ hf.hash = tracer_hash_fun;
+ hf.cmp = tracer_cmp_fun;
+ hf.alloc = tracer_alloc_fun;
+ hf.free = tracer_free_fun;
+ hf.meta_alloc = (HMALLOC_FUN) erts_alloc;
+ hf.meta_free = (HMFREE_FUN) erts_free;
+ hf.meta_print = (HMPRINT_FUN) erts_print;
+
+ erts_smp_rwmtx_runlock(&tracer_mtx);
+ erts_smp_rwmtx_rwlock(&tracer_mtx);
+
+ if (tracer_hash)
+ hash_delete(tracer_hash);
+
+ tracer_hash = hash_new(ERTS_ALC_T_TRACER_NIF, "tracer_hash", 10, hf);
+
+ erts_smp_rwmtx_rwunlock(&tracer_mtx);
+ return 1;
+ }
+
+ erts_smp_rwmtx_runlock(&tracer_mtx);
+ return 0;
+}
+
+static int tracer_cmp_fun(void* a, void* b)
+{
+ return ((ErtsTracerNif*)a)->module != ((ErtsTracerNif*)b)->module;
+}
+
+static HashValue tracer_hash_fun(void* obj)
+{
+ return make_internal_hash(((ErtsTracerNif*)obj)->module);
+}
+
+static void *tracer_alloc_fun(void* tmpl)
+{
+ ErtsTracerNif *obj = erts_alloc(ERTS_ALC_T_TRACER_NIF,
+ sizeof(ErtsTracerNif) +
+ sizeof(ErtsThrPrgrLaterOp));
+ memcpy(obj, tmpl, sizeof(*obj));
+ return obj;
+}
+
+static void tracer_free_fun_cb(void* obj)
+{
+ erts_free(ERTS_ALC_T_TRACER_NIF, obj);
+}
+
+static void tracer_free_fun(void* obj)
+{
+ ErtsTracerNif *tnif = obj;
+ erts_schedule_thr_prgr_later_op(
+ tracer_free_fun_cb, obj,
+ (ErtsThrPrgrLaterOp*)(tnif + 1));
+
+}
diff --git a/erts/emulator/beam/erl_trace.h b/erts/emulator/beam/erl_trace.h
index a0058264d7..de4beadb7e 100644
--- a/erts/emulator/beam/erl_trace.h
+++ b/erts/emulator/beam/erl_trace.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2012-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2012-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.
@@ -46,6 +46,8 @@
#define ERTS_SEQTFLGS2TSTYPE(SEQTFLGS) \
((int) (((SEQTFLGS) >> ERTS_SEQ_TRACE_FLAGS_TS_TYPE_SHIFT) \
& ERTS_TRACE_TS_TYPE_MASK))
+#define ERTS_SEQTFLGS2TFLGS(SEQTFLGS) \
+ (ERTS_SEQTFLGS2TSTYPE(SEQTFLGS) << ERTS_TRACE_FLAGS_TS_TYPE_SHIFT)
#endif /* ERL_TRACE_H__FLAGS__ */
@@ -54,6 +56,15 @@
struct binary;
+typedef struct
+{
+ int on;
+ struct binary* match_spec;
+} ErtsTracingEvent;
+
+extern ErtsTracingEvent erts_send_tracing[];
+extern ErtsTracingEvent erts_receive_tracing[];
+
/* erl_bif_trace.c */
Eterm erl_seq_trace_info(Process *p, Eterm arg1);
void erts_system_monitor_clear(Process *c_p);
@@ -62,15 +73,19 @@ void erts_system_profile_clear(Process *c_p);
/* erl_trace.c */
void erts_init_trace(void);
void erts_trace_check_exiting(Eterm exiting);
-Eterm erts_set_system_seq_tracer(Process *c_p,
- ErtsProcLocks c_p_locks,
- Eterm new);
-Eterm erts_get_system_seq_tracer(void);
-void erts_change_default_tracing(int setflags, Uint *flagsp, Eterm *tracerp);
-void erts_get_default_tracing(Uint *flagsp, Eterm *tracerp);
+ErtsTracer erts_set_system_seq_tracer(Process *c_p,
+ ErtsProcLocks c_p_locks,
+ ErtsTracer new);
+ErtsTracer erts_get_system_seq_tracer(void);
+void erts_change_default_proc_tracing(int setflags, Uint flagsp,
+ const ErtsTracer tracerp);
+void erts_get_default_proc_tracing(Uint *flagsp, ErtsTracer *tracerp);
+void erts_change_default_port_tracing(int setflags, Uint flagsp,
+ const ErtsTracer tracerp);
+void erts_get_default_port_tracing(Uint *flagsp, ErtsTracer *tracerp);
void erts_set_system_monitor(Eterm monitor);
Eterm erts_get_system_monitor(void);
-int erts_is_tracer_proc_valid(Process* p);
+int erts_is_tracer_valid(Process* p);
#ifdef ERTS_SMP
void erts_check_my_tracer_proc(Process *);
@@ -81,28 +96,32 @@ void erts_foreach_sys_msg_in_q(void (*func)(Eterm,
Eterm,
ErlHeapFragment *));
void erts_queue_error_logger_message(Eterm, Eterm, ErlHeapFragment *);
+void erts_send_sys_msg_proc(Eterm, Eterm, Eterm, ErlHeapFragment *);
#endif
-void erts_send_sys_msg_proc(Eterm, Eterm, Eterm, ErlHeapFragment *);
void trace_send(Process*, Eterm, Eterm);
-void trace_receive(Process*, Eterm);
-Uint32 erts_call_trace(Process *p, BeamInstr mfa[], struct binary *match_spec, Eterm* args,
- int local, Eterm *tracer_pid);
-void erts_trace_return(Process* p, BeamInstr* fi, Eterm retval, Eterm *tracer_pid);
+void trace_receive(Process*, Eterm, Eterm, ErtsTracingEvent*);
+Uint32 erts_call_trace(Process *p, BeamInstr mfa[], struct binary *match_spec,
+ Eterm* args, int local, ErtsTracer *tracer);
+void erts_trace_return(Process* p, BeamInstr* fi, Eterm retval,
+ ErtsTracer *tracer);
void erts_trace_exception(Process* p, BeamInstr mfa[], Eterm class, Eterm value,
- Eterm *tracer);
+ ErtsTracer *tracer);
void erts_trace_return_to(Process *p, BeamInstr *pc);
-void trace_sched(Process*, Eterm);
-void trace_proc(Process*, Process*, Eterm, Eterm);
-void trace_proc_spawn(Process*, Eterm pid, Eterm mod, Eterm func, Eterm args);
+void trace_sched(Process*, ErtsProcLocks, Eterm);
+void trace_proc(Process*, ErtsProcLocks, Process*, Eterm, Eterm);
+void trace_proc_spawn(Process*, Eterm what, Eterm pid, Eterm mod, Eterm func, Eterm args);
void save_calls(Process *p, Export *);
-void trace_gc(Process *p, Eterm what);
+void trace_gc(Process *p, Eterm what, Uint size);
/* port tracing */
-void trace_virtual_sched(Process*, Eterm);
+void trace_virtual_sched(Process*, ErtsProcLocks, Eterm);
void trace_sched_ports(Port *pp, Eterm);
void trace_sched_ports_where(Port *pp, Eterm, Eterm);
void trace_port(Port *, Eterm what, Eterm data);
void trace_port_open(Port *, Eterm calling_pid, Eterm drv_name);
+void trace_port_receive(Port *, Eterm calling_pid, Eterm tag, ...);
+void trace_port_send(Port *, Eterm to, Eterm msg, int exists);
+void trace_port_send_binary(Port *, Eterm to, Eterm what, char *bin, Sint sz);
/* system_profile */
void erts_set_system_profile(Eterm profile);
@@ -121,7 +140,7 @@ void monitor_large_heap(Process *p);
void monitor_generic(Process *p, Eterm type, Eterm spec);
Uint erts_trace_flag2bit(Eterm flag);
int erts_trace_flags(Eterm List,
- Uint *pMask, Eterm *pTracer, int *pCpuTimestamp);
+ Uint *pMask, ErtsTracer *pTracer, int *pCpuTimestamp);
Eterm erts_bif_trace(int bif_index, Process* p, Eterm* args, BeamInstr *I);
#ifdef ERTS_SMP
@@ -161,15 +180,53 @@ int erts_set_trace_pattern(Process*p, Eterm* mfa, int specified,
struct binary* match_prog_set,
struct binary *meta_match_prog_set,
int on, struct trace_pattern_flags,
- Eterm meta_tracer_pid, int is_blocking);
+ ErtsTracer meta_tracer, int is_blocking);
void
erts_get_default_trace_pattern(int *trace_pattern_is_on,
struct binary **match_spec,
struct binary **meta_match_spec,
struct trace_pattern_flags *trace_pattern_flags,
- Eterm *meta_tracer_pid);
+ ErtsTracer *meta_tracer);
int erts_is_default_trace_enabled(void);
void erts_bif_trace_init(void);
int erts_finish_breakpointing(void);
+/* Nif tracer functions */
+int erts_is_tracer_proc_enabled(Process *c_p, ErtsProcLocks c_p_locks,
+ ErtsPTabElementCommon *t_p, Eterm type);
+int erts_is_tracer_enabled(Process *c_p, const ErtsTracer tracer);
+Eterm erts_tracer_to_term(Process *p, ErtsTracer tracer);
+ErtsTracer erts_term_to_tracer(Eterm prefix, Eterm term);
+void erts_tracer_replace(ErtsPTabElementCommon *t_p,
+ const ErtsTracer new_tracer);
+void erts_tracer_update(ErtsTracer *tracer, const ErtsTracer new_tracer);
+int erts_tracer_nif_clear(void);
+
+#define erts_tracer_update(t,n) do { if (*(t) != (n)) erts_tracer_update(t,n); } while(0)
+#define ERTS_TRACER_CLEAR(t) erts_tracer_update(t, erts_tracer_nil)
+
+static const ErtsTracer
+ERTS_DECLARE_DUMMY(erts_tracer_true) = am_true;
+
+static const ErtsTracer
+ERTS_DECLARE_DUMMY(erts_tracer_nil) = NIL;
+
+#define ERTS_TRACER_COMPARE(t1, t2) \
+ (EQ((t1), (t2)))
+
+#define ERTS_TRACER_IS_NIL(t1) ERTS_TRACER_COMPARE(t1, erts_tracer_nil)
+
+#define IS_TRACER_VALID(tracer) \
+ (ERTS_TRACER_COMPARE(tracer,erts_tracer_true) \
+ || ERTS_TRACER_IS_NIL(tracer) \
+ || (is_list(tracer) && is_atom(CAR(list_val(tracer)))))
+
+#define ERTS_TRACER_FROM_ETERM(termp) \
+ ((ErtsTracer*)(termp))
+
+#define ERTS_TRACER_PROC_IS_ENABLED(PROC) \
+ (!ERTS_TRACER_IS_NIL(ERTS_TRACER(PROC)) \
+ && erts_is_tracer_proc_enabled(PROC, ERTS_PROC_LOCK_MAIN, \
+ &(PROC)->common, am_trace_status))
+
#endif /* ERL_TRACE_H__ */
diff --git a/erts/emulator/beam/erl_unicode.c b/erts/emulator/beam/erl_unicode.c
index 36d85b0a22..3c3536c021 100644
--- a/erts/emulator/beam/erl_unicode.c
+++ b/erts/emulator/beam/erl_unicode.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/emulator/beam/erl_unicode.h b/erts/emulator/beam/erl_unicode.h
index 4c25d89b7c..e01eaa787e 100644
--- a/erts/emulator/beam/erl_unicode.h
+++ b/erts/emulator/beam/erl_unicode.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/emulator/beam/erl_unicode_normalize.h b/erts/emulator/beam/erl_unicode_normalize.h
index 16c62db50e..21e2a52544 100644
--- a/erts/emulator/beam/erl_unicode_normalize.h
+++ b/erts/emulator/beam/erl_unicode_normalize.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2010. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/beam/erl_utils.h b/erts/emulator/beam/erl_utils.h
index 640969daf0..81800752f0 100644
--- a/erts/emulator/beam/erl_utils.h
+++ b/erts/emulator/beam/erl_utils.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2012-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2012-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.
diff --git a/erts/emulator/beam/erl_vm.h b/erts/emulator/beam/erl_vm.h
index 98f27a1725..f3c54de214 100644
--- a/erts/emulator/beam/erl_vm.h
+++ b/erts/emulator/beam/erl_vm.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -165,7 +165,6 @@ extern int erts_atom_table_size;/* Atom table size */
extern int erts_pd_initial_size;/* Initial Process dictionary table size */
#define ORIG_CREATION 0
-#define INTERNAL_CREATION 255
/* macros for extracting bytes from uint16's */
diff --git a/erts/emulator/beam/erl_zlib.c b/erts/emulator/beam/erl_zlib.c
index e44e86c39c..944ff2e35f 100644
--- a/erts/emulator/beam/erl_zlib.c
+++ b/erts/emulator/beam/erl_zlib.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2009-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.
diff --git a/erts/emulator/beam/erl_zlib.h b/erts/emulator/beam/erl_zlib.h
index 2ca1e3735e..c83c6f291f 100644
--- a/erts/emulator/beam/erl_zlib.h
+++ b/erts/emulator/beam/erl_zlib.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2009-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.
diff --git a/erts/emulator/beam/erlang_dtrace.d b/erts/emulator/beam/erlang_dtrace.d
index c682f76e3a..237889e0f5 100644
--- a/erts/emulator/beam/erlang_dtrace.d
+++ b/erts/emulator/beam/erlang_dtrace.d
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Dustin Sallings, Michal Ptaszek, Scott Lystig Fritchie 2011-2012.
+ * Copyright Dustin Sallings, Michal Ptaszek, Scott Lystig Fritchie 2011-2016.
* All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -700,6 +700,35 @@ provider erlang {
*/
probe efile_drv__return(int, int, char *, int, int, int);
+
+/*
+ * The set of probes called by the erlang tracer nif backend. In order
+ * to receive events on these you both have to enable tracing in erlang
+ * using the trace bifs and also from dtrace/systemtap.
+ */
+
+
+ /**
+ * A trace message of type `event` was triggered by process `p`.
+ *
+ *
+ * @param p the PID (string form) of the process
+ * @param event the event that was triggered (i.e. call or spawn)
+ * @param state the state of the tracer nif as a string
+ * @param arg1 first argument to the trace event
+ * @param arg2 second argument to the trace event
+ */
+ probe trace(char *p, char *event, char *state, char *arg1, char *arg2);
+
+ /**
+ * A sequence trace message of type `label` was triggered.
+ *
+ * @param state the state of the tracer nif as a string
+ * @param label the seq trace label
+ * @param seq_info the seq trace info tuple as a string
+ */
+ probe trace_seq(char *state, char *label, char *seq_info);
+
/*
* NOTE:
* For formatting int64_t arguments within a D script, see:
diff --git a/erts/emulator/beam/erlang_lttng.c b/erts/emulator/beam/erlang_lttng.c
new file mode 100644
index 0000000000..fce40eedc1
--- /dev/null
+++ b/erts/emulator/beam/erlang_lttng.c
@@ -0,0 +1,32 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1996-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%
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef USE_LTTNG
+#define TRACEPOINT_CREATE_PROBES
+/*
+ * The header containing our TRACEPOINT_EVENTs.
+ */
+#define TRACEPOINT_DEFINE
+#include "erlang_lttng.h"
+#endif /* USE_LTTNG */
diff --git a/erts/emulator/beam/erlang_lttng.h b/erts/emulator/beam/erlang_lttng.h
new file mode 100644
index 0000000000..12f68e477b
--- /dev/null
+++ b/erts/emulator/beam/erlang_lttng.h
@@ -0,0 +1,424 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1996-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%
+ */
+
+#ifdef USE_LTTNG
+#undef TRACEPOINT_PROVIDER
+#define TRACEPOINT_PROVIDER com_ericsson_otp
+
+#undef TRACEPOINT_INCLUDE
+#define TRACEPOINT_INCLUDE "erlang_lttng.h"
+
+#if !defined(__ERLANG_LTTNG_H__) || defined(TRACEPOINT_HEADER_MULTI_READ)
+#define __ERLANG_LTTNG_H__
+
+#include <lttng/tracepoint.h>
+
+/* Schedulers */
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ scheduler_poll,
+ TP_ARGS(
+ int, id,
+ int, runnable
+ ),
+ TP_FIELDS(
+ ctf_integer(int, scheduler, id)
+ ctf_integer(int, runnable, runnable)
+ )
+)
+
+#ifndef LTTNG_CARRIER_STATS
+#define LTTNG_CARRIER_STATS
+typedef struct {
+ unsigned long no;
+ unsigned long size;
+} lttng_stat_values_t;
+
+typedef struct {
+ lttng_stat_values_t carriers;
+ lttng_stat_values_t blocks;
+} lttng_carrier_stats_t;
+#endif
+
+
+/* Port and Driver Scheduling */
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ driver_start,
+ TP_ARGS(
+ char*, pid,
+ char*, driver,
+ char*, port
+ ),
+ TP_FIELDS(
+ ctf_string(pid, pid)
+ ctf_string(driver, driver)
+ ctf_string(port, port)
+ )
+)
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ driver_init,
+ TP_ARGS(
+ char*, driver,
+ int, major,
+ int, minor,
+ int, flags
+ ),
+ TP_FIELDS(
+ ctf_string(driver, driver)
+ ctf_integer(int, major, major)
+ ctf_integer(int, minor, minor)
+ ctf_integer(int, flags, flags)
+ )
+)
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ driver_outputv,
+ TP_ARGS(
+ char*, pid,
+ char*, port,
+ char*, driver,
+ size_t, bytes
+ ),
+ TP_FIELDS(
+ ctf_string(pid, pid)
+ ctf_string(port, port)
+ ctf_string(driver, driver)
+ ctf_integer(size_t, bytes, bytes)
+ )
+)
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ driver_output,
+ TP_ARGS(
+ char*, pid,
+ char*, port,
+ char*, driver,
+ size_t, bytes
+ ),
+ TP_FIELDS(
+ ctf_string(pid, pid)
+ ctf_string(port, port)
+ ctf_string(driver, driver)
+ ctf_integer(size_t, bytes, bytes)
+ )
+)
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ driver_ready_input,
+ TP_ARGS(
+ char*, pid,
+ char*, port,
+ char*, driver
+ ),
+ TP_FIELDS(
+ ctf_string(pid, pid)
+ ctf_string(port, port)
+ ctf_string(driver, driver)
+ )
+)
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ driver_ready_output,
+ TP_ARGS(
+ char*, pid,
+ char*, port,
+ char*, driver
+ ),
+ TP_FIELDS(
+ ctf_string(pid, pid)
+ ctf_string(port, port)
+ ctf_string(driver, driver)
+ )
+)
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ driver_event,
+ TP_ARGS(
+ char*, pid,
+ char*, port,
+ char*, driver
+ ),
+ TP_FIELDS(
+ ctf_string(pid, pid)
+ ctf_string(port, port)
+ ctf_string(driver, driver)
+ )
+)
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ driver_timeout,
+ TP_ARGS(
+ char*, pid,
+ char*, port,
+ char*, driver
+ ),
+ TP_FIELDS(
+ ctf_string(pid, pid)
+ ctf_string(port, port)
+ ctf_string(driver, driver)
+ )
+)
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ driver_stop_select,
+ TP_ARGS(
+ char*, driver
+ ),
+ TP_FIELDS(
+ ctf_string(driver, driver)
+ )
+)
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ driver_flush,
+ TP_ARGS(
+ char*, pid,
+ char*, port,
+ char*, driver
+ ),
+ TP_FIELDS(
+ ctf_string(pid, pid)
+ ctf_string(port, port)
+ ctf_string(driver, driver)
+ )
+)
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ driver_stop,
+ TP_ARGS(
+ char*, pid,
+ char*, port,
+ char*, driver
+ ),
+ TP_FIELDS(
+ ctf_string(pid, pid)
+ ctf_string(port, port)
+ ctf_string(driver, driver)
+ )
+)
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ driver_process_exit,
+ TP_ARGS(
+ char*, pid,
+ char*, port,
+ char*, driver
+ ),
+ TP_FIELDS(
+ ctf_string(pid, pid)
+ ctf_string(port, port)
+ ctf_string(driver, driver)
+ )
+)
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ driver_ready_async,
+ TP_ARGS(
+ char*, pid,
+ char*, port,
+ char*, driver
+ ),
+ TP_FIELDS(
+ ctf_string(pid, pid)
+ ctf_string(port, port)
+ ctf_string(driver, driver)
+ )
+)
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ driver_finish,
+ TP_ARGS(
+ char*, driver
+ ),
+ TP_FIELDS(
+ ctf_string(driver, driver)
+ )
+)
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ driver_call,
+ TP_ARGS(
+ char*, pid,
+ char*, port,
+ char*, driver,
+ unsigned int, command,
+ size_t, bytes
+ ),
+ TP_FIELDS(
+ ctf_string(pid, pid)
+ ctf_string(port, port)
+ ctf_string(driver, driver)
+ ctf_integer(unsigned int, command, command)
+ ctf_integer(size_t, bytes, bytes)
+ )
+)
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ driver_control,
+ TP_ARGS(
+ char*, pid,
+ char*, port,
+ char*, driver,
+ unsigned int, command,
+ size_t, bytes
+ ),
+ TP_FIELDS(
+ ctf_string(pid, pid)
+ ctf_string(port, port)
+ ctf_string(driver, driver)
+ ctf_integer(unsigned int, command, command)
+ ctf_integer(size_t, bytes, bytes)
+ )
+)
+
+/* Async pool */
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ aio_pool_get,
+ TP_ARGS(
+ char*, port,
+ int, length
+ ),
+ TP_FIELDS(
+ ctf_string(port, port)
+ ctf_integer(int, length, length)
+ )
+)
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ aio_pool_put,
+ TP_ARGS(
+ char*, port,
+ int, length
+ ),
+ TP_FIELDS(
+ ctf_string(port, port)
+ ctf_integer(int, length, length)
+ )
+)
+
+
+/* Memory Allocator */
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ carrier_create,
+ TP_ARGS(
+ const char*, type,
+ int, instance,
+ unsigned long, size,
+ lttng_carrier_stats_t *, mbcs,
+ lttng_carrier_stats_t *, sbcs
+ ),
+ TP_FIELDS(
+ ctf_string(type, type)
+ ctf_integer(int, instance, instance)
+ ctf_integer(unsigned long, size, size)
+ ctf_integer(unsigned long, mbc_carriers, mbcs->carriers.no)
+ ctf_integer(unsigned long, mbc_carriers_size, mbcs->carriers.size)
+ ctf_integer(unsigned long, mbc_blocks, mbcs->blocks.no)
+ ctf_integer(unsigned long, mbc_blocks_size, mbcs->blocks.size)
+ ctf_integer(unsigned long, sbc_carriers, sbcs->carriers.no)
+ ctf_integer(unsigned long, sbc_carriers_size, sbcs->carriers.size)
+ ctf_integer(unsigned long, sbc_blocks, sbcs->blocks.no)
+ ctf_integer(unsigned long, sbc_blocks_size, sbcs->blocks.size)
+ )
+)
+
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ carrier_destroy,
+ TP_ARGS(
+ const char*, type,
+ int, instance,
+ unsigned long, size,
+ lttng_carrier_stats_t *, mbcs,
+ lttng_carrier_stats_t *, sbcs
+ ),
+ TP_FIELDS(
+ ctf_string(type, type)
+ ctf_integer(int, instance, instance)
+ ctf_integer(unsigned long, size, size)
+ ctf_integer(unsigned long, mbc_carriers, mbcs->carriers.no)
+ ctf_integer(unsigned long, mbc_carriers_size, mbcs->carriers.size)
+ ctf_integer(unsigned long, mbc_blocks, mbcs->blocks.no)
+ ctf_integer(unsigned long, mbc_blocks_size, mbcs->blocks.size)
+ ctf_integer(unsigned long, sbc_carriers, sbcs->carriers.no)
+ ctf_integer(unsigned long, sbc_carriers_size, sbcs->carriers.size)
+ ctf_integer(unsigned long, sbc_blocks, sbcs->blocks.no)
+ ctf_integer(unsigned long, sbc_blocks_size, sbcs->blocks.size)
+ )
+)
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ carrier_pool_put,
+ TP_ARGS(
+ const char*, name,
+ int, instance,
+ unsigned long, size
+ ),
+ TP_FIELDS(
+ ctf_string(type, name)
+ ctf_integer(int, instance, instance)
+ ctf_integer(unsigned long, size, size)
+ )
+)
+
+TRACEPOINT_EVENT(
+ com_ericsson_otp,
+ carrier_pool_get,
+ TP_ARGS(
+ const char*, name,
+ int, instance,
+ unsigned long, size
+ ),
+ TP_FIELDS(
+ ctf_string(type, name)
+ ctf_integer(int, instance, instance)
+ ctf_integer(unsigned long, size, size)
+ )
+)
+
+#endif /* __ERLANG_LTTNG_H__ */
+#include <lttng/tracepoint-event.h>
+#endif /* USE_LTTNG */
diff --git a/erts/emulator/beam/error.h b/erts/emulator/beam/error.h
index cba8672c68..6c33b12dd0 100644
--- a/erts/emulator/beam/error.h
+++ b/erts/emulator/beam/error.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2010. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/beam/export.c b/erts/emulator/beam/export.c
index 581efe6eec..02c24557c1 100644
--- a/erts/emulator/beam/export.c
+++ b/erts/emulator/beam/export.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/beam/export.h b/erts/emulator/beam/export.h
index a8bc9d2f66..8c81cbd410 100644
--- a/erts/emulator/beam/export.h
+++ b/erts/emulator/beam/export.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c
index aac1490f0c..3c002d43a7 100644
--- a/erts/emulator/beam/external.c
+++ b/erts/emulator/beam/external.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -51,7 +51,18 @@
#define MAX_STRING_LEN 0xffff
-#define is_valid_creation(Cre) ((unsigned)(Cre) < MAX_CREATION || (Cre) == INTERNAL_CREATION)
+/* MAX value for the creation field in pid, port and reference
+ for the local node and for the current external format.
+
+ Larger creation values than this are allowed in external pid, port and refs
+ encoded with NEW_PID_EXT, NEW_PORT_EXT and NEWER_REFERENCE_EXT.
+ The point here is to prepare for future upgrade to 32-bit creation.
+ OTP-19 (erts-8.0) can handle big creation values from other (newer) nodes,
+ but do not use big creation values for the local node yet,
+ as we still may have to communicate with older nodes.
+*/
+#define ERTS_MAX_LOCAL_CREATION (3)
+#define is_valid_creation(Cre) ((unsigned)(Cre) <= ERTS_MAX_LOCAL_CREATION)
#undef ERTS_DEBUG_USE_DIST_SEP
#ifdef DEBUG
@@ -97,7 +108,7 @@ static byte* enc_pid(ErtsAtomCacheMap *, Eterm, byte*, Uint32);
struct B2TContext_t;
static byte* dec_term(ErtsDistExternal*, ErtsHeapFactory*, byte*, Eterm*, struct B2TContext_t*);
static byte* dec_atom(ErtsDistExternal *, byte*, Eterm*);
-static byte* dec_pid(ErtsDistExternal *, ErtsHeapFactory*, byte*, Eterm*);
+static byte* dec_pid(ErtsDistExternal *, ErtsHeapFactory*, byte*, Eterm*, byte tag);
static Sint decoded_size(byte *ep, byte* endp, int internal_tags, struct B2TContext_t*);
static BIF_RETTYPE term_to_binary_trap_1(BIF_ALIST_1);
@@ -967,19 +978,24 @@ erts_decode_dist_ext(ErtsHeapFactory* factory,
return THE_NON_VALUE;
}
-Eterm erts_decode_ext(ErtsHeapFactory* factory, byte **ext)
+Eterm erts_decode_ext(ErtsHeapFactory* factory, byte **ext, Uint32 flags)
{
+ ErtsDistExternal ede, *edep;
Eterm obj;
byte *ep = *ext;
if (*ep++ != VERSION_MAGIC) {
erts_factory_undo(factory);
return THE_NON_VALUE;
}
- ep = dec_term(NULL, factory, ep, &obj, NULL);
+ if (flags) {
+ ASSERT(flags == ERTS_DIST_EXT_BTT_SAFE);
+ ede.flags = flags; /* a dummy struct just for the flags */
+ edep = &ede;
+ } else {
+ edep = NULL;
+ }
+ ep = dec_term(edep, factory, ep, &obj, NULL);
if (!ep) {
-#ifdef DEBUG
- bin_write(ERTS_PRINT_STDERR,NULL,*ext,500);
-#endif
return THE_NON_VALUE;
}
*ext = ep;
@@ -2147,12 +2163,13 @@ static byte*
enc_pid(ErtsAtomCacheMap *acmp, Eterm pid, byte* ep, Uint32 dflags)
{
Uint on, os;
+ Eterm sysname = ((is_internal_pid(pid) && (dflags & DFLAG_INTERNAL_TAGS))
+ ? am_Empty : pid_node_name(pid));
+ Uint32 creation = pid_creation(pid);
+ byte* tagp = ep++;
- *ep++ = PID_EXT;
/* insert atom here containing host and sysname */
- ep = enc_atom(acmp, pid_node_name(pid), ep, dflags);
-
- /* two bytes for each number and serial */
+ ep = enc_atom(acmp, sysname, ep, dflags);
on = pid_number(pid);
os = pid_serial(pid);
@@ -2161,8 +2178,15 @@ enc_pid(ErtsAtomCacheMap *acmp, Eterm pid, byte* ep, Uint32 dflags)
ep += 4;
put_int32(os, ep);
ep += 4;
- *ep++ = (is_internal_pid(pid) && (dflags & DFLAG_INTERNAL_TAGS)) ?
- INTERNAL_CREATION : pid_creation(pid);
+ if (creation <= ERTS_MAX_LOCAL_CREATION) {
+ *tagp = PID_EXT;
+ *ep++ = creation;
+ } else {
+ ASSERT(is_external_pid(pid));
+ *tagp = NEW_PID_EXT;
+ put_int32(creation, ep);
+ ep += 4;
+ }
return ep;
}
@@ -2242,27 +2266,27 @@ dec_atom(ErtsDistExternal *edep, byte* ep, Eterm* objp)
return ep;
}
-static ERTS_INLINE ErlNode* dec_get_node(Eterm sysname, Uint creation)
+static ERTS_INLINE ErlNode* dec_get_node(Eterm sysname, Uint32 creation)
{
- switch (creation) {
- case INTERNAL_CREATION:
+ if (sysname == am_Empty) /* && DFLAG_INTERNAL_TAGS */
return erts_this_node;
- case ORIG_CREATION:
- if (sysname == erts_this_node->sysname) {
- creation = erts_this_node->creation;
- }
- }
+
+ if (sysname == erts_this_node->sysname
+ && (creation == erts_this_node->creation || creation == ORIG_CREATION))
+ return erts_this_node;
+
return erts_find_or_insert_node(sysname,creation);
}
static byte*
-dec_pid(ErtsDistExternal *edep, ErtsHeapFactory* factory, byte* ep, Eterm* objp)
+dec_pid(ErtsDistExternal *edep, ErtsHeapFactory* factory, byte* ep,
+ Eterm* objp, byte tag)
{
Eterm sysname;
Uint data;
Uint num;
Uint ser;
- Uint cre;
+ Uint32 cre;
ErlNode *node;
*objp = NIL; /* In case we fail, don't leave a hole in the heap */
@@ -2278,12 +2302,19 @@ dec_pid(ErtsDistExternal *edep, ErtsHeapFactory* factory, byte* ep, Eterm* objp)
ep += 4;
if (ser > ERTS_MAX_PID_SERIAL)
return NULL;
- cre = get_int8(ep);
- ep += 1;
- if (!is_valid_creation(cre)) {
- return NULL;
+ if (tag == PID_EXT) {
+ cre = get_int8(ep);
+ ep += 1;
+ if (!is_valid_creation(cre)) {
+ return NULL;
+ }
+ } else {
+ ASSERT(tag == NEW_PID_EXT);
+ cre = get_int32(ep);
+ ep += 4;
}
+
data = make_pid_data(ser, num);
/*
@@ -2523,16 +2554,26 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep,
case REF_DEF:
case EXTERNAL_REF_DEF: {
Uint32 *ref_num;
+ Eterm sysname = (((dflags & DFLAG_INTERNAL_TAGS) && is_internal_ref(obj))
+ ? am_Empty : ref_node_name(obj));
+ Uint32 creation = ref_creation(obj);
+ byte* tagp = ep++;
ASSERT(dflags & DFLAG_EXTENDED_REFERENCES);
- *ep++ = NEW_REFERENCE_EXT;
i = ref_no_of_numbers(obj);
put_int16(i, ep);
ep += 2;
- ep = enc_atom(acmp,ref_node_name(obj),ep,dflags);
- *ep++ = ((dflags & DFLAG_INTERNAL_TAGS) && is_internal_ref(obj)) ?
- INTERNAL_CREATION : ref_creation(obj);
+ ep = enc_atom(acmp, sysname, ep, dflags);
+ if (creation <= ERTS_MAX_LOCAL_CREATION) {
+ *tagp = NEW_REFERENCE_EXT;
+ *ep++ = creation;
+ } else {
+ ASSERT(is_external_ref(obj));
+ *tagp = NEWER_REFERENCE_EXT;
+ put_int32(creation, ep);
+ ep += 4;
+ }
ref_num = ref_numbers(obj);
for (j = 0; j < i; j++) {
put_int32(ref_num[j], ep);
@@ -2541,17 +2582,27 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep,
break;
}
case PORT_DEF:
- case EXTERNAL_PORT_DEF:
+ case EXTERNAL_PORT_DEF: {
+ Eterm sysname = (((dflags & DFLAG_INTERNAL_TAGS) && is_internal_port(obj))
+ ? am_Empty : port_node_name(obj));
+ Uint32 creation = port_creation(obj);
+ byte* tagp = ep++;
- *ep++ = PORT_EXT;
- ep = enc_atom(acmp,port_node_name(obj),ep,dflags);
+ ep = enc_atom(acmp, sysname, ep, dflags);
j = port_number(obj);
put_int32(j, ep);
ep += 4;
- *ep++ = ((dflags & DFLAG_INTERNAL_TAGS) && is_internal_port(obj)) ?
- INTERNAL_CREATION : port_creation(obj);
+ if (creation <= ERTS_MAX_LOCAL_CREATION) {
+ *tagp = PORT_EXT;
+ *ep++ = creation;
+ } else {
+ ASSERT(is_external_port(obj));
+ *tagp = NEW_PORT_EXT;
+ put_int32(creation, ep);
+ ep += 4;
+ }
break;
-
+ }
case LIST_DEF:
{
int is_str;
@@ -3255,20 +3306,23 @@ dec_term_atom_common:
hp += FLOAT_SIZE_OBJECT;
break;
}
- case PID_EXT:
+ case PID_EXT:
+ case NEW_PID_EXT:
factory->hp = hp;
- ep = dec_pid(edep, factory, ep, objp);
+ ep = dec_pid(edep, factory, ep, objp, ep[-1]);
hp = factory->hp;
if (ep == NULL) {
goto error;
}
break;
- case PORT_EXT:
+ case PORT_EXT:
+ case NEW_PORT_EXT:
{
Eterm sysname;
ErlNode *node;
Uint num;
- Uint cre;
+ Uint32 cre;
+ byte tag = ep[-1];
if ((ep = dec_atom(edep, ep, &sysname)) == NULL) {
goto error;
@@ -3277,12 +3331,17 @@ dec_term_atom_common:
goto error;
}
ep += 4;
- cre = get_int8(ep);
- ep++;
- if (!is_valid_creation(cre)) {
- goto error;
- }
-
+ if (tag == PORT_EXT) {
+ cre = get_int8(ep);
+ ep++;
+ if (!is_valid_creation(cre)) {
+ goto error;
+ }
+ }
+ else {
+ cre = get_int32(ep);
+ ep += 4;
+ }
node = dec_get_node(sysname, cre);
if(node == erts_this_node) {
*objp = make_internal_port(num);
@@ -3307,7 +3366,7 @@ dec_term_atom_common:
Eterm sysname;
ErlNode *node;
int i;
- Uint cre;
+ Uint32 cre;
Uint32 *ref_num;
Uint32 r0;
Uint ref_words;
@@ -3331,9 +3390,6 @@ dec_term_atom_common:
ref_words = get_int16(ep);
ep += 2;
- if (ref_words > ERTS_MAX_REF_NUMBERS)
- goto error;
-
if ((ep = dec_atom(edep, ep, &sysname)) == NULL)
goto error;
@@ -3346,8 +3402,23 @@ dec_term_atom_common:
ep += 4;
if (r0 >= MAX_REFERENCE)
goto error;
+ goto ref_ext_common;
+
+ case NEWER_REFERENCE_EXT:
+ ref_words = get_int16(ep);
+ ep += 2;
+
+ if ((ep = dec_atom(edep, ep, &sysname)) == NULL)
+ goto error;
+
+ cre = get_int32(ep);
+ ep += 4;
+ r0 = get_int32(ep); /* allow full word */
+ ep += 4;
ref_ext_common:
+ if (ref_words > ERTS_MAX_REF_NUMBERS)
+ goto error;
node = dec_get_node(sysname, cre);
if(node == erts_this_node) {
@@ -3701,9 +3772,9 @@ dec_term_atom_common:
*objp = make_fun(funp);
/* Creator pid */
- if (*ep != PID_EXT
- || (ep = dec_pid(edep, factory, ++ep,
- &funp->creator))==NULL) {
+ if ((*ep != PID_EXT && *ep != NEW_PID_EXT)
+ || (ep = dec_pid(edep, factory, ep+1,
+ &funp->creator, *ep))==NULL) {
goto error;
}
@@ -3887,9 +3958,13 @@ error:
* Must unlink all off-heap objects that may have been
* linked into the process.
*/
- if (factory->hp < hp) { /* Sometimes we used hp and sometimes factory->hp */
- factory->hp = hp; /* the largest must be the freshest */
+ if (factory->mode != FACTORY_CLOSED) {
+ if (factory->hp < hp) { /* Sometimes we used hp and sometimes factory->hp */
+ factory->hp = hp; /* the largest must be the freshest */
+ }
}
+ else ASSERT(factory->hp == hp);
+
error_hamt:
erts_factory_undo(factory);
PSTACK_DESTROY(hamt_array);
@@ -4005,20 +4080,29 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj,
else
result += 1 + 4 + 1 + i; /* tag,size,sign,digits */
break;
+ case EXTERNAL_PID_DEF:
+ if (external_pid_creation(obj) > ERTS_MAX_LOCAL_CREATION)
+ result += 3;
+ /*fall through*/
case PID_DEF:
- case EXTERNAL_PID_DEF:
result += (1 + encode_size_struct2(acmp, pid_node_name(obj), dflags) +
4 + 4 + 1);
break;
+ case EXTERNAL_REF_DEF:
+ if (external_ref_creation(obj) > ERTS_MAX_LOCAL_CREATION)
+ result += 3;
+ /*fall through*/
case REF_DEF:
- case EXTERNAL_REF_DEF:
ASSERT(dflags & DFLAG_EXTENDED_REFERENCES);
i = ref_no_of_numbers(obj);
result += (1 + 2 + encode_size_struct2(acmp, ref_node_name(obj), dflags) +
1 + 4*i);
break;
- case PORT_DEF:
- case EXTERNAL_PORT_DEF:
+ case EXTERNAL_PORT_DEF:
+ if (external_port_creation(obj) > ERTS_MAX_LOCAL_CREATION)
+ result += 3;
+ /*fall through*/
+ case PORT_DEF:
result += (1 + encode_size_struct2(acmp, port_node_name(obj), dflags) +
4 + 1);
break;
@@ -4345,19 +4429,32 @@ init_done:
SKIP(1+atom_extra_skip);
atom_extra_skip = 0;
break;
- case PID_EXT:
+ case NEW_PID_EXT:
+ atom_extra_skip = 12;
+ goto case_PID;
+ case PID_EXT:
atom_extra_skip = 9;
+ case_PID:
/* In case it is an external pid */
heap_size += EXTERNAL_THING_HEAD_SIZE + 1;
terms++;
break;
- case PORT_EXT:
+ case NEW_PORT_EXT:
+ atom_extra_skip = 8;
+ goto case_PORT;
+ case PORT_EXT:
atom_extra_skip = 5;
+ case_PORT:
/* In case it is an external port */
heap_size += EXTERNAL_THING_HEAD_SIZE + 1;
terms++;
break;
- case NEW_REFERENCE_EXT:
+ case NEWER_REFERENCE_EXT:
+ atom_extra_skip = 4;
+ goto case_NEW_REFERENCE;
+ case NEW_REFERENCE_EXT:
+ atom_extra_skip = 1;
+ case_NEW_REFERENCE:
{
int id_words;
@@ -4368,7 +4465,7 @@ init_done:
goto error;
ep += 2;
- atom_extra_skip = 1 + 4*id_words;
+ atom_extra_skip += 4*id_words;
/* In case it is an external ref */
#if defined(ARCH_64)
heap_size += EXTERNAL_THING_HEAD_SIZE + id_words/2 + 1;
diff --git a/erts/emulator/beam/external.h b/erts/emulator/beam/external.h
index d12051c6b4..f00426cc16 100644
--- a/erts/emulator/beam/external.h
+++ b/erts/emulator/beam/external.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -18,8 +18,6 @@
* %CopyrightEnd%
*/
-/* Same order as the ordering of terms in erlang */
-
/* Since there are 255 different External tag values to choose from
There is no reason to not be extravagant.
Hence, the different tags for large/small tuple e.t.c
@@ -37,9 +35,12 @@
#define SMALL_ATOM_EXT 's'
#define REFERENCE_EXT 'e'
#define NEW_REFERENCE_EXT 'r'
+#define NEWER_REFERENCE_EXT 'Z'
#define PORT_EXT 'f'
+#define NEW_PORT_EXT 'Y'
#define NEW_FLOAT_EXT 'F'
#define PID_EXT 'g'
+#define NEW_PID_EXT 'X'
#define SMALL_TUPLE_EXT 'h'
#define LARGE_TUPLE_EXT 'i'
#define NIL_EXT 'j'
@@ -191,7 +192,7 @@ Eterm erts_decode_dist_ext(ErtsHeapFactory* factory, ErtsDistExternal *);
Sint erts_decode_ext_size(byte*, Uint);
Sint erts_decode_ext_size_ets(byte*, Uint);
-Eterm erts_decode_ext(ErtsHeapFactory*, byte**);
+Eterm erts_decode_ext(ErtsHeapFactory*, byte**, Uint32 flags);
Eterm erts_decode_ext_ets(ErtsHeapFactory*, byte*);
Eterm erts_term_to_binary(Process* p, Eterm Term, int level, Uint flags);
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index d7edf451be..550db95ba8 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -44,6 +44,8 @@
#include "erl_port.h"
#include "erl_gc.h"
+struct enif_func_t;
+
struct enif_environment_t /* ErlNifEnv */
{
struct erl_module_nif* mod_nif;
@@ -54,14 +56,21 @@ struct enif_environment_t /* ErlNifEnv */
int fpe_was_unmasked;
struct enif_tmp_obj_t* tmp_obj_list;
int exception_thrown; /* boolean */
+ Process *tracee;
};
extern void erts_pre_nif(struct enif_environment_t*, Process*,
- struct erl_module_nif*);
+ struct erl_module_nif*, Process* tracee);
extern void erts_post_nif(struct enif_environment_t* env);
extern Eterm erts_nif_taints(Process* p);
extern void erts_print_nif_taints(int to, void* to_arg);
void erts_unload_nif(struct erl_module_nif* nif);
extern void erl_nif_init(void);
+extern int erts_nif_get_funcs(struct erl_module_nif*,
+ struct enif_func_t **funcs);
+extern Eterm erts_nif_call_function(Process *p, Process *tracee,
+ struct erl_module_nif*,
+ struct enif_func_t *,
+ int argc, Eterm *argv);
/* Driver handle (wrapper for old plain handle) */
#define ERL_DE_OK 0
@@ -988,7 +997,7 @@ Eterm erl_is_function(Process* p, Eterm arg1, Eterm arg2);
#define ERTS_CPC_ALLOW_GC (1 << 0)
#define ERTS_CPC_COPY_LITERALS (1 << 1)
#define ERTS_CPC_ALL (ERTS_CPC_ALLOW_GC | ERTS_CPC_COPY_LITERALS)
-Eterm erts_check_process_code(Process *c_p, Eterm module, Uint flags, int *redsp);
+Eterm erts_check_process_code(Process *c_p, Eterm module, Uint flags, int *redsp, int fcalls);
typedef struct {
Eterm *ptr;
@@ -1474,9 +1483,19 @@ do { \
#define MatchSetGetSource(MPSP) erts_match_set_get_source(MPSP)
-extern Binary *erts_match_set_compile(Process *p, Eterm matchexpr);
+extern Binary *erts_match_set_compile(Process *p, Eterm matchexpr, Eterm MFA);
Eterm erts_match_set_lint(Process *p, Eterm matchexpr);
extern void erts_match_set_release_result(Process* p);
+ERTS_GLB_INLINE void erts_match_set_release_result_trace(Process* p, Eterm);
+
+#if ERTS_GLB_INLINE_INCL_FUNC_DEF
+ERTS_GLB_INLINE
+void erts_match_set_release_result_trace(Process* p, Eterm pam_result)
+{
+ if (is_not_immed(pam_result))
+ erts_match_set_release_result(p);
+}
+#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */
enum erts_pam_run_flags {
ERTS_PAM_TMP_RESULT=1,
@@ -1484,10 +1503,12 @@ enum erts_pam_run_flags {
ERTS_PAM_CONTIGUOUS_TUPLE=4,
ERTS_PAM_IGNORE_TRACE_SILENT=8
};
-extern Eterm erts_match_set_run(Process *p, Binary *mpsp,
- Eterm *args, int num_args,
- enum erts_pam_run_flags in_flags,
- Uint32 *return_flags);
+extern Eterm erts_match_set_run_trace(Process *p,
+ Process *self,
+ Binary *mpsp,
+ Eterm *args, int num_args,
+ enum erts_pam_run_flags in_flags,
+ Uint32 *return_flags);
extern Eterm erts_match_set_get_source(Binary *mpsp);
extern void erts_match_prog_foreach_offheap(Binary *b,
void (*)(ErlOffHeap *, void *),
@@ -1532,10 +1553,15 @@ ERTS_GLB_INLINE void dtrace_fun_decode(Process *process,
ERTS_GLB_INLINE void
dtrace_pid_str(Eterm pid, char *process_buf)
{
- erts_snprintf(process_buf, DTRACE_TERM_BUF_SIZE, "<%lu.%lu.%lu>",
- pid_channel_no(pid),
- pid_number(pid),
- pid_serial(pid));
+ if (is_pid(pid))
+ erts_snprintf(process_buf, DTRACE_TERM_BUF_SIZE, "<%lu.%lu.%lu>",
+ pid_channel_no(pid),
+ pid_number(pid),
+ pid_serial(pid));
+ else if (is_port(pid))
+ erts_snprintf(process_buf, DTRACE_TERM_BUF_SIZE, "#Port<%lu.%lu>",
+ port_channel_no(pid),
+ port_number(pid));
}
ERTS_GLB_INLINE void
@@ -1547,9 +1573,7 @@ dtrace_proc_str(Process *process, char *process_buf)
ERTS_GLB_INLINE void
dtrace_port_str(Port *port, char *port_buf)
{
- erts_snprintf(port_buf, DTRACE_TERM_BUF_SIZE, "#Port<%lu.%lu>",
- port_channel_no(port->common.id),
- port_number(port->common.id));
+ dtrace_pid_str(port->common.id, port_buf);
}
ERTS_GLB_INLINE void
diff --git a/erts/emulator/beam/hash.c b/erts/emulator/beam/hash.c
index 5a0b93f693..e255b961f1 100644
--- a/erts/emulator/beam/hash.c
+++ b/erts/emulator/beam/hash.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/beam/hash.h b/erts/emulator/beam/hash.h
index e94aaa0a84..9f773d8faa 100644
--- a/erts/emulator/beam/hash.h
+++ b/erts/emulator/beam/hash.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/beam/index.c b/erts/emulator/beam/index.c
index 5f6ea14732..26d6c04ea0 100644
--- a/erts/emulator/beam/index.c
+++ b/erts/emulator/beam/index.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2012. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/beam/index.h b/erts/emulator/beam/index.h
index 99b2bdfab0..218779c33b 100644
--- a/erts/emulator/beam/index.h
+++ b/erts/emulator/beam/index.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index 797e4cdadc..b9f6ab04c6 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -47,6 +47,7 @@
#define ERTS_WANT_EXTERNAL_TAGS
#include "external.h"
#include "dtrace-wrapper.h"
+#include "lttng-wrapper.h"
#include "erl_map.h"
#include "erl_bif_unique.h"
#include "erl_hl_timer.h"
@@ -87,7 +88,7 @@ int erts_port_parallelism = 0;
static erts_atomic64_t bytes_in;
static erts_atomic64_t bytes_out;
-static void deliver_result(Eterm sender, Eterm pid, Eterm res);
+static void deliver_result(Port *p, Eterm sender, Eterm pid, Eterm res);
static int init_driver(erts_driver_t *, ErlDrvEntry *, DE_Handle *);
static void terminate_port(Port *p);
static void pdl_init(void);
@@ -211,6 +212,7 @@ static ERTS_INLINE void
kill_port(Port *pp)
{
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp));
+ ERTS_TRACER_CLEAR(&ERTS_TRACER(pp));
erts_ptab_delete_element(&erts_port, &pp->common); /* Time of death */
erts_port_task_free_port(pp);
/* In non-smp case the port structure may have been deallocated now */
@@ -397,13 +399,13 @@ static Port *create_port(char *name,
prt->common.u.alive.reg = NULL;
ERTS_PTMR_INIT(prt);
erts_port_task_handle_init(&prt->timeout_task);
- prt->psd = NULL;
+ erts_smp_atomic_init_nob(&prt->psd, (erts_aint_t) NULL);
prt->async_open_port = NULL;
prt->drv_data = (SWord) 0;
prt->os_pid = -1;
/* Set default tracing */
- erts_get_default_tracing(&ERTS_TRACE_FLAGS(prt), &ERTS_TRACER_PROC(prt));
+ erts_get_default_port_tracing(&ERTS_TRACE_FLAGS(prt), &ERTS_TRACER(prt));
ERTS_CT_ASSERT(offsetof(Port,common) == 0);
@@ -708,7 +710,7 @@ erts_open_driver(erts_driver_t* driver, /* Pointer to driver. */
if (driver->start) {
ERTS_MSACC_PUSH_STATE_M();
if (IS_TRACED_FL(port, F_TRACE_SCHED_PORTS)) {
- trace_sched_ports_where(port, am_in, am_start);
+ trace_sched_ports_where(port, am_in, am_open);
}
port->caller = pid;
#ifdef USE_VM_PROBES
@@ -717,7 +719,19 @@ erts_open_driver(erts_driver_t* driver, /* Pointer to driver. */
DTRACE3(driver_start, process_str, driver->name, port_str);
}
#endif
+
ERTS_MSACC_SET_STATE_CACHED_M(ERTS_MSACC_STATE_PORT);
+
+#ifdef USE_LTTNG_VM_TRACEPOINTS
+ if (LTTNG_ENABLED(driver_start)) {
+ lttng_decl_portbuf(port_str);
+ lttng_decl_procbuf(proc_str);
+ lttng_pid_to_str(pid, proc_str);
+ lttng_port_to_str(port, port_str);
+ LTTNG3(driver_start, proc_str, driver->name, port_str);
+ }
+#endif
+
fpe_was_unmasked = erts_block_fpe();
drv_data = (*driver->start)(ERTS_Port2ErlDrvPort(port), name, opts);
if (((SWord) drv_data) == -1)
@@ -740,7 +754,7 @@ erts_open_driver(erts_driver_t* driver, /* Pointer to driver. */
ERTS_MSACC_POP_STATE_M();
port->caller = NIL;
if (IS_TRACED_FL(port, F_TRACE_SCHED_PORTS)) {
- trace_sched_ports_where(port, am_out, am_start);
+ trace_sched_ports_where(port, am_out, am_open);
}
#ifdef ERTS_SMP
if (port->xports)
@@ -1287,7 +1301,7 @@ try_imm_drv_call(ErtsTryImmDrvCallState *sp)
reds_left_in = CONTEXT_REDS/10;
else {
if (IS_TRACED_FL(c_p, F_TRACE_SCHED_PROCS))
- trace_virtual_sched(c_p, am_out);
+ trace_sched(c_p, ERTS_PROC_LOCK_MAIN, am_out);
/*
* No status lock held while sending runnable
* proc trace messages. It is however not needed
@@ -1371,7 +1385,7 @@ finalize_imm_drv_call(ErtsTryImmDrvCallState *sp)
}
if (IS_TRACED_FL(c_p, F_TRACE_SCHED_PROCS))
- trace_virtual_sched(c_p, am_in);
+ trace_sched(c_p, ERTS_PROC_LOCK_MAIN, am_in);
/*
* No status lock held while sending runnable
* proc trace messages. It is however not needed
@@ -1418,10 +1432,11 @@ finalize_force_imm_drv_call(ErtsTryImmDrvCallState *sp)
static ERTS_INLINE void
queue_port_sched_op_reply(Process *rp,
- ErtsProcLocks *rp_locksp,
+ ErtsProcLocks rp_locks,
ErtsHeapFactory* factory,
Uint32 *ref_num,
- Eterm msg)
+ Eterm msg,
+ Port* prt)
{
Eterm* hp = erts_produce_heap(factory, ERTS_QUEUE_PORT_SCHED_OP_REPLY_SIZE, 0);
Eterm ref;
@@ -1434,11 +1449,12 @@ queue_port_sched_op_reply(Process *rp,
erts_factory_trim_and_close(factory, &msg, 1);
- erts_queue_message(rp, rp_locksp, factory->message, msg, NIL);
+ erts_queue_message(rp, rp_locks, factory->message, msg,
+ prt ? prt->common.id : am_undefined);
}
static void
-port_sched_op_reply(Eterm to, Uint32 *ref_num, Eterm msg)
+port_sched_op_reply(Eterm to, Uint32 *ref_num, Eterm msg, Port* prt)
{
Process *rp = erts_proc_lookup_raw(to);
if (rp) {
@@ -1464,10 +1480,11 @@ port_sched_op_reply(Eterm to, Uint32 *ref_num, Eterm msg)
factory.off_heap));
queue_port_sched_op_reply(rp,
- &rp_locks,
+ rp_locks,
&factory,
ref_num,
- msg_copy);
+ msg_copy,
+ prt);
if (rp_locks)
erts_smp_proc_unlock(rp, rp_locks);
@@ -1522,9 +1539,8 @@ erts_schedule_proc2port_signal(Process *c_p,
ERTS_SMP_MSGQ_MV_INQ2PRIVQ(c_p);
c_p->msg.save = c_p->msg.last;
- erts_smp_proc_unlock(c_p,
- (ERTS_PROC_LOCK_MAIN
- | ERTS_PROC_LOCKS_MSG_RECEIVE));
+ erts_smp_proc_unlock(c_p, (ERTS_PROC_LOCKS_MSG_RECEIVE
+ | ERTS_PROC_LOCK_MAIN));
}
@@ -1542,8 +1558,19 @@ erts_schedule_proc2port_signal(Process *c_p,
erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN);
if (sched_res != 0) {
- if (refp)
+ if (refp) {
+ /*
+ * We need to restore the message queue save
+ * pointer to the beginning of the message queue
+ * since the caller now wont wait for a message
+ * containing the reference created above...
+ */
+ ASSERT(c_p);
+ erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE);
+ JOIN_MESSAGE(c_p);
+ erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE);
*refp = NIL;
+ }
return ERTS_PORT_OP_DROPPED;
}
return ERTS_PORT_OP_SCHEDULED;
@@ -1627,7 +1654,7 @@ port_badsig(Port *prt, erts_aint32_t state, int op,
state,
sigdp->flags & ERTS_P2P_SIG_DATA_FLG_BAD_OUTPUT);
if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY)
- port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg);
+ port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg, prt);
return ERTS_PORT_REDS_BADSIG;
} /* port_badsig */
/* bad_port_signal() will
@@ -1718,12 +1745,25 @@ call_driver_outputv(int bang_op,
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)
|| ERTS_IS_CRASH_DUMPING);
+
+ if (IS_TRACED_FL(prt, F_TRACE_RECEIVE))
+ trace_port_receive(prt, caller, am_commandv, evp);
+
#ifdef USE_VM_PROBES
if (DTRACE_ENABLED(driver_outputv)) {
DTRACE_FORMAT_COMMON_PID_AND_PORT(caller, prt);
DTRACE4(driver_outputv, process_str, port_str, prt->name, size);
}
#endif
+#ifdef USE_LTTNG_VM_TRACEPOINTS
+ if (LTTNG_ENABLED(driver_outputv)) {
+ lttng_decl_portbuf(port_str);
+ lttng_decl_procbuf(proc_str);
+ lttng_pid_to_str(caller, proc_str);
+ lttng_port_to_str(prt, port_str);
+ LTTNG4(driver_outputv, proc_str, port_str, prt->name, size);
+ }
+#endif
prt->caller = caller;
(*drv->outputv)((ErlDrvData) prt->drv_data, evp);
@@ -1749,7 +1789,6 @@ cleanup_scheduled_outputv(ErlIOVec *ev, ErlDrvBinary *cbinp)
driver_free_binary(ev->binv[i]);
if (cbinp)
driver_free_binary(cbinp);
- erts_free(ERTS_ALC_T_DRV_CMD_DATA, ev);
}
static int
@@ -1784,7 +1823,7 @@ port_sig_outputv(Port *prt, erts_aint32_t state, int op, ErtsProc2PortSigData *s
}
if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY)
- port_sched_op_reply(sigdp->caller, sigdp->ref, reply);
+ port_sched_op_reply(sigdp->caller, sigdp->ref, reply, prt);
cleanup_scheduled_outputv(sigdp->u.outputv.evp,
sigdp->u.outputv.cbinp);
@@ -1826,6 +1865,18 @@ call_driver_output(int bang_op,
DTRACE4(driver_output, process_str, port_str, prt->name, size);
}
#endif
+#ifdef USE_LTTNG_VM_TRACEPOINTS
+ if (LTTNG_ENABLED(driver_output)) {
+ lttng_decl_portbuf(port_str);
+ lttng_decl_procbuf(proc_str);
+ lttng_pid_to_str(caller, proc_str);
+ lttng_port_to_str(prt, port_str);
+ LTTNG4(driver_output, proc_str, port_str, prt->name, size);
+ }
+#endif
+
+ if (IS_TRACED_FL(prt, F_TRACE_RECEIVE))
+ trace_port_receive(prt, caller, am_command, bufp, size);
prt->caller = caller;
(*drv->output)((ErlDrvData) prt->drv_data, bufp, size);
@@ -1880,13 +1931,195 @@ port_sig_output(Port *prt, erts_aint32_t state, int op, ErtsProc2PortSigData *si
}
if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY)
- port_sched_op_reply(sigdp->caller, sigdp->ref, reply);
+ port_sched_op_reply(sigdp->caller, sigdp->ref, reply, prt);
cleanup_scheduled_output(sigdp->u.output.bufp);
return ERTS_PORT_REDS_CMD_OUTPUT;
}
+
+/*
+ * This erts_port_output will always create a port task.
+ * The call is treated as a port_command call, i.e. no
+ * badsig i generated if the input in invalid. However
+ * an error_logger message is generated.
+ */
+int
+erts_port_output_async(Port *prt, Eterm from, Eterm list)
+{
+
+ ErtsPortOpResult res;
+ ErtsProc2PortSigData *sigdp;
+ erts_driver_t *drv = prt->drv_ptr;
+ size_t size;
+ int task_flags;
+ ErtsProc2PortSigCallback port_sig_callback;
+ ErlDrvBinary *cbin = NULL;
+ ErlIOVec *evp = NULL;
+ char *buf = NULL;
+ ErtsPortTaskHandle *ns_pthp;
+
+ if (drv->outputv) {
+ ErlIOVec ev;
+ SysIOVec* ivp;
+ ErlDrvBinary** bvp;
+ int vsize;
+ Uint csize;
+ Uint pvsize;
+ Uint pcsize;
+ size_t iov_offset, binv_offset, alloc_size;
+ Uint blimit = 0;
+ char *ptr;
+ int i;
+
+ Eterm* bptr = NULL;
+ Uint offset;
+
+ if (is_binary(list)) {
+ /* We optimize for when we get a procbin without offset */
+ Eterm real_bin;
+ int bitoffs;
+ int bitsize;
+ ERTS_GET_REAL_BIN(list, real_bin, offset, bitoffs, bitsize);
+ bptr = binary_val(real_bin);
+ if (*bptr == HEADER_PROC_BIN && bitoffs == 0) {
+ size = binary_size(list);
+ vsize = 1;
+ } else
+ bptr = NULL;
+ }
+
+ if (!bptr) {
+ if (io_list_vec_len(list, &vsize, &csize, &pvsize, &pcsize, &size))
+ goto bad_value;
+
+ /* To pack or not to pack (small binaries) ...? */
+ if (vsize >= SMALL_WRITE_VEC) {
+ /* Do pack */
+ vsize = pvsize + 1;
+ csize = pcsize;
+ blimit = ERL_SMALL_IO_BIN_LIMIT;
+ }
+ cbin = driver_alloc_binary(csize);
+ if (!cbin)
+ erts_alloc_enomem(ERTS_ALC_T_DRV_BINARY, ERTS_SIZEOF_Binary(csize));
+ }
+
+
+ iov_offset = ERTS_ALC_DATA_ALIGN_SIZE(sizeof(ErlIOVec));
+ binv_offset = iov_offset;
+ binv_offset += ERTS_ALC_DATA_ALIGN_SIZE((vsize+1)*sizeof(SysIOVec));
+ alloc_size = binv_offset;
+ alloc_size += (vsize+1)*sizeof(ErlDrvBinary *);
+
+ sigdp = erts_port_task_alloc_p2p_sig_data_extra(alloc_size, (void**)&ptr);
+
+ evp = (ErlIOVec *) ptr;
+ ivp = evp->iov = (SysIOVec *) (ptr + iov_offset);
+ bvp = evp->binv = (ErlDrvBinary **) (ptr + binv_offset);
+
+ ivp[0].iov_base = NULL;
+ ivp[0].iov_len = 0;
+ bvp[0] = NULL;
+
+ if (bptr) {
+ ProcBin* pb = (ProcBin *) bptr;
+
+ ivp[1].iov_base = pb->bytes+offset;
+ ivp[1].iov_len = size;
+ bvp[1] = Binary2ErlDrvBinary(pb->val);
+
+ evp->vsize = 1;
+ } else {
+
+ evp->vsize = io_list_to_vec(list, ivp+1, bvp+1, cbin, blimit);
+ if (evp->vsize < 0) {
+ if (evp != &ev)
+ erts_free(ERTS_ALC_T_DRV_CMD_DATA, evp);
+ driver_free_binary(cbin);
+ goto bad_value;
+ }
+ }
+#if 0
+ /* This assertion may say something useful, but it can
+ be falsified during the emulator test suites. */
+ ASSERT(evp->vsize == vsize);
+#endif
+ evp->vsize++;
+ evp->size = size; /* total size */
+
+ /* Need to increase refc on all binaries */
+ for (i = 1; i < evp->vsize; i++)
+ if (bvp[i])
+ driver_binary_inc_refc(bvp[i]);
+
+ sigdp->flags = ERTS_P2P_SIG_TYPE_OUTPUTV;
+ sigdp->u.outputv.from = from;
+ sigdp->u.outputv.evp = evp;
+ sigdp->u.outputv.cbinp = cbin;
+ port_sig_callback = port_sig_outputv;
+ } else {
+ ErlDrvSizeT ERTS_DECLARE_DUMMY(r);
+
+ /*
+ * Apperently there exist code that write 1 byte to
+ * much in buffer. Where it resides I don't know, but
+ * we can live with one byte extra allocated...
+ */
+
+ if (erts_iolist_size(list, &size))
+ goto bad_value;
+
+ buf = erts_alloc(ERTS_ALC_T_DRV_CMD_DATA, size + 1);
+
+ r = erts_iolist_to_buf(list, buf, size);
+ ASSERT(ERTS_IOLIST_TO_BUF_SUCCEEDED(r));
+
+ sigdp = erts_port_task_alloc_p2p_sig_data();
+ sigdp->flags = ERTS_P2P_SIG_TYPE_OUTPUT;
+ sigdp->u.output.from = from;
+ sigdp->u.output.bufp = buf;
+ sigdp->u.output.size = size;
+ port_sig_callback = port_sig_output;
+ }
+ sigdp->flags = 0;
+ ns_pthp = NULL;
+ task_flags = 0;
+
+ res = erts_schedule_proc2port_signal(NULL,
+ prt,
+ ERTS_INVALID_PID,
+ NULL,
+ sigdp,
+ task_flags,
+ ns_pthp,
+ port_sig_callback);
+
+ if (res != ERTS_PORT_OP_SCHEDULED) {
+ if (drv->outputv)
+ cleanup_scheduled_outputv(evp, cbin);
+ else
+ cleanup_scheduled_output(buf);
+ return 1;
+ }
+ return 1;
+
+bad_value:
+
+ /*
+ * We call badsig directly here as this function is called with
+ * the main lock of the calling process still held.
+ * At the moment this operation is always not a bang_op, so
+ * only an error_logger message should be generated, no badsig.
+ */
+
+ badsig_received(0, prt, erts_atomic32_read_nob(&prt->state), 1);
+
+ return 0;
+
+}
+
ErtsPortOpResult
erts_port_output(Process *c_p,
int flags,
@@ -1896,7 +2129,7 @@ erts_port_output(Process *c_p,
Eterm *refp)
{
ErtsPortOpResult res;
- ErtsProc2PortSigData *sigdp;
+ ErtsProc2PortSigData *sigdp = NULL;
erts_driver_t *drv = prt->drv_ptr;
size_t size;
int try_call;
@@ -1949,7 +2182,6 @@ erts_port_output(Process *c_p,
DTRACE4(port_command, process_str, port_str, prt->name, "command");
}
#endif
-
if (drv->outputv) {
ErlIOVec ev;
SysIOVec iv[SMALL_WRITE_VEC];
@@ -1978,10 +2210,13 @@ erts_port_output(Process *c_p,
evp = &ev;
}
else {
- char *ptr = erts_alloc((try_call
- ? ERTS_ALC_T_TMP
- : ERTS_ALC_T_DRV_CMD_DATA), alloc_size);
-
+ char *ptr;
+ if (try_call) {
+ ptr = erts_alloc(ERTS_ALC_T_TMP, alloc_size);
+ } else {
+ sigdp = erts_port_task_alloc_p2p_sig_data_extra(
+ alloc_size, (void**)&ptr);
+ }
evp = (ErlIOVec *) ptr;
ivp = evp->iov = (SysIOVec *) (ptr + iov_offset);
bvp = evp->binv = (ErlDrvBinary **) (ptr + binv_offset);
@@ -2010,9 +2245,12 @@ erts_port_output(Process *c_p,
bvp[0] = NULL;
evp->vsize = io_list_to_vec(list, ivp+1, bvp+1, cbin, blimit);
if (evp->vsize < 0) {
- if (evp != &ev)
- erts_free(try_call ? ERTS_ALC_T_TMP : ERTS_ALC_T_DRV_CMD_DATA,
- evp);
+ if (evp != &ev) {
+ if (try_call)
+ erts_free(ERTS_ALC_T_TMP, evp);
+ else
+ erts_port_task_free_p2p_sig_data(sigdp);
+ }
driver_free_binary(cbin);
goto bad_value;
}
@@ -2064,8 +2302,10 @@ erts_port_output(Process *c_p,
/* Fall through... */
case ERTS_TRY_IMM_DRV_CALL_INVALID_PORT:
driver_free_binary(cbin);
- if (evp != &ev)
+ if (evp != &ev) {
+ ASSERT(!sigdp);
erts_free(ERTS_ALC_T_TMP, evp);
+ }
if (try_call_res != ERTS_TRY_IMM_DRV_CALL_OK)
return ERTS_PORT_OP_DROPPED;
if (c_p)
@@ -2076,8 +2316,10 @@ erts_port_output(Process *c_p,
if (async_nosuspend
&& (sched_flags & (busy_flgs|ERTS_PTS_FLG_EXIT))) {
driver_free_binary(cbin);
- if (evp != &ev)
+ if (evp != &ev) {
+ ASSERT(!sigdp);
erts_free(ERTS_ALC_T_TMP, evp);
+ }
return ((sched_flags & ERTS_PTS_FLG_EXIT)
? ERTS_PORT_OP_DROPPED
: ERTS_PORT_OP_BUSY);
@@ -2092,9 +2334,16 @@ erts_port_output(Process *c_p,
if (bvp[i])
driver_binary_inc_refc(bvp[i]);
- new_evp = erts_alloc(ERTS_ALC_T_DRV_CMD_DATA, alloc_size);
+ /* The port task and iovec is allocated in the
+ same structure as an optimization. This
+ is especially important in erts_port_output_async
+ of when !try_call */
+ ASSERT(sigdp == NULL);
+ sigdp = erts_port_task_alloc_p2p_sig_data_extra(
+ alloc_size, (void**)&new_evp);
if (evp != &ev) {
+ /* Copy from TMP alloc to port task */
sys_memcpy((void *) new_evp, (void *) evp, alloc_size);
new_evp->iov = (SysIOVec *) (((char *) new_evp)
+ iov_offset);
@@ -2142,7 +2391,6 @@ erts_port_output(Process *c_p,
evp = new_evp;
}
- sigdp = erts_port_task_alloc_p2p_sig_data();
sigdp->flags = ERTS_P2P_SIG_TYPE_OUTPUTV;
sigdp->u.outputv.from = from;
sigdp->u.outputv.evp = evp;
@@ -2351,7 +2599,10 @@ call_deliver_port_exit(int bang_op,
return ERTS_PORT_OP_DROPPED;
}
- if (!erts_deliver_port_exit(prt, from, reason, bang_op))
+ if (IS_TRACED_FL(prt, F_TRACE_RECEIVE))
+ trace_port_receive(prt, from, am_close);
+
+ if (!erts_deliver_port_exit(prt, from, reason, bang_op, broken_link))
return ERTS_PORT_OP_DROPPED;
#ifdef USE_VM_PROBES
@@ -2388,7 +2639,7 @@ port_sig_exit(Port *prt,
if (sigdp->u.exit.bp)
free_message_buffer(sigdp->u.exit.bp);
if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY)
- port_sched_op_reply(sigdp->caller, sigdp->ref, msg);
+ port_sched_op_reply(sigdp->caller, sigdp->ref, msg, prt);
return ERTS_PORT_REDS_EXIT;
}
@@ -2422,13 +2673,13 @@ erts_port_exit(Process *c_p,
ERTS_PORT_SFLGS_INVALID_LOOKUP,
0,
!refp,
- am_exit);
+ am_close);
switch (try_imm_drv_call(&try_call_state)) {
case ERTS_TRY_IMM_DRV_CALL_OK: {
res = call_deliver_port_exit(flags & ERTS_PORT_SIG_FLG_BANG_OP,
- from,
+ c_p ? c_p->common.id : from,
prt,
try_call_state.state,
reason,
@@ -2507,8 +2758,11 @@ set_port_connected(int bang_op,
return ERTS_PORT_OP_DROPPED;
}
+ if (IS_TRACED_FL(prt, F_TRACE_RECEIVE))
+ trace_port_receive(prt, from, am_connect, connect);
+
ERTS_PORT_SET_CONNECTED(prt, connect);
- deliver_result(prt->common.id, from, am_connected);
+ deliver_result(prt, prt->common.id, from, am_connected);
#ifdef USE_VM_PROBES
if(DTRACE_ENABLED(port_command)) {
@@ -2530,10 +2784,22 @@ set_port_connected(int bang_op,
erts_add_link(&ERTS_P_LINKS(rp), LINK_PID, prt->common.id);
erts_add_link(&ERTS_P_LINKS(prt), LINK_PID, connect);
+ if (IS_TRACED_FL(rp, F_TRACE_PROCS))
+ trace_proc(NULL, 0, rp, am_getting_linked, prt->common.id);
+
ERTS_PORT_SET_CONNECTED(prt, connect);
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
+ if (IS_TRACED_FL(prt, F_TRACE_PORTS))
+ trace_port(prt, am_getting_linked, connect);
+ if (IS_TRACED_FL(prt, F_TRACE_RECEIVE))
+ trace_port_receive(prt, from, am_connect, connect);
+ if (IS_TRACED_FL(prt, F_TRACE_SEND)) {
+ Eterm hp[3];
+ trace_port_send(prt, from, TUPLE2(hp, prt->common.id, am_connected), 1);
+ }
+
#ifdef USE_VM_PROBES
if (DTRACE_ENABLED(port_connect)) {
DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE);
@@ -2566,7 +2832,7 @@ port_sig_connect(Port *prt, erts_aint32_t state, int op, ErtsProc2PortSigData *s
msg = am_true;
}
if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY)
- port_sched_op_reply(sigdp->caller, sigdp->ref, msg);
+ port_sched_op_reply(sigdp->caller, sigdp->ref, msg, prt);
return ERTS_PORT_REDS_CONNECT;
}
@@ -2636,8 +2902,11 @@ static void
port_unlink(Port *prt, Eterm from)
{
ErtsLink *lnk = erts_remove_link(&ERTS_P_LINKS(prt), from);
- if (lnk)
+ if (lnk) {
+ if (IS_TRACED_FL(prt, F_TRACE_PORTS))
+ trace_port(prt, am_getting_unlinked, from);
erts_destroy_link(lnk);
+ }
}
static int
@@ -2646,7 +2915,7 @@ port_sig_unlink(Port *prt, erts_aint32_t state, int op, ErtsProc2PortSigData *si
if (op == ERTS_PROC2PORT_SIG_EXEC)
port_unlink(prt, sigdp->u.unlink.from);
if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY)
- port_sched_op_reply(sigdp->caller, sigdp->ref, am_true);
+ port_sched_op_reply(sigdp->caller, sigdp->ref, am_true, prt);
return ERTS_PORT_REDS_UNLINK;
}
@@ -2707,10 +2976,10 @@ port_link_failure(Eterm port_id, Eterm linker)
NIL,
NULL,
0);
- if (xres >= 0 && IS_TRACED_FL(rp, F_TRACE_PROCS)) {
+ if (xres >= 0) {
/* We didn't exit the process and it is traced */
if (IS_TRACED_FL(rp, F_TRACE_PROCS))
- trace_proc(NULL, rp, am_getting_unlinked, port_id);
+ trace_proc(NULL, 0, rp, am_getting_unlinked, port_id);
}
if (rp_locks)
erts_smp_proc_unlock(rp, rp_locks);
@@ -2721,10 +2990,15 @@ port_link_failure(Eterm port_id, Eterm linker)
static void
port_link(Port *prt, erts_aint32_t state, Eterm to)
{
- if (!(state & ERTS_PORT_SFLGS_INVALID_LOOKUP))
+ if (IS_TRACED_FL(prt, F_TRACE_PORTS))
+ trace_port(prt, am_getting_linked, to);
+ if (!(state & ERTS_PORT_SFLGS_INVALID_LOOKUP)) {
erts_add_link(&ERTS_P_LINKS(prt), LINK_PID, to);
- else
+ } else {
port_link_failure(prt->common.id, to);
+ if (IS_TRACED_FL(prt, F_TRACE_PORTS))
+ trace_port(prt, am_unlink, to);
+ }
}
static int
@@ -2732,10 +3006,11 @@ port_sig_link(Port *prt, erts_aint32_t state, int op, ErtsProc2PortSigData *sigd
{
if (op == ERTS_PROC2PORT_SIG_EXEC)
port_link(prt, state, sigdp->u.link.to);
- else
+ else {
port_link_failure(sigdp->u.link.port, sigdp->u.link.to);
+ }
if (sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY)
- port_sched_op_reply(sigdp->caller, sigdp->ref, am_true);
+ port_sched_op_reply(sigdp->caller, sigdp->ref, am_true, prt);
return ERTS_PORT_REDS_LINK;
}
@@ -2792,7 +3067,8 @@ init_ack_send_reply(Port *port, Eterm resp)
}
port_sched_op_reply(port->async_open_port->to,
port->async_open_port->ref,
- resp);
+ resp,
+ port);
erts_free(ERTS_ALC_T_PRTSD, port->async_open_port);
port->async_open_port = NULL;
@@ -3153,7 +3429,7 @@ static int read_linebuf(LineBufContext *bp)
}
static void
-deliver_result(Eterm sender, Eterm pid, Eterm res)
+deliver_result(Port *prt, Eterm sender, Eterm pid, Eterm res)
{
Process *rp;
ErtsProcLocks rp_locks = 0;
@@ -3161,12 +3437,22 @@ deliver_result(Eterm sender, Eterm pid, Eterm res)
ERTS_SMP_CHK_NO_PROC_LOCKS;
+ ASSERT(!prt || prt->common.id == sender);
+#ifdef ERTS_SMP
+ ASSERT(!prt || erts_lc_is_port_locked(prt));
+#endif
+
ASSERT(is_internal_port(sender) && is_internal_pid(pid));
rp = (scheduler
? erts_proc_lookup(pid)
: erts_pid2proc_opt(NULL, 0, pid, 0, ERTS_P2P_FLG_INC_REFC));
+ if (prt && IS_TRACED_FL(prt, F_TRACE_SEND)) {
+ Eterm hp[3];
+ trace_port_send(prt, pid, TUPLE2(hp, sender, res), !!rp);
+ }
+
if (rp) {
Eterm tuple;
ErtsMessage *mp;
@@ -3179,7 +3465,7 @@ deliver_result(Eterm sender, Eterm pid, Eterm res)
sz_res + 3, &hp, &ohp);
res = copy_struct(res, sz_res, &hp, ohp);
tuple = TUPLE2(hp, sender, res);
- erts_queue_message(rp, &rp_locks, mp, tuple, NIL);
+ erts_queue_message(rp, rp_locks, mp, tuple, sender);
if (rp_locks)
erts_smp_proc_unlock(rp, rp_locks);
@@ -3211,6 +3497,7 @@ static void deliver_read_message(Port* prt, erts_aint32_t state, Eterm to,
ErlOffHeap *ohp;
ErtsProcLocks rp_locks = 0;
int scheduler = erts_get_scheduler_id() != 0;
+ int trace_send = IS_TRACED_FL(prt, F_TRACE_SEND);
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
ERTS_SMP_CHK_NO_PROC_LOCKS;
@@ -3233,7 +3520,7 @@ static void deliver_read_message(Port* prt, erts_aint32_t state, Eterm to,
if (!rp)
return;
- mp = erts_alloc_message_heap(rp, &rp_locks, need, &hp, &ohp);
+ mp = erts_alloc_message_heap(trace_send ? NULL : rp, &rp_locks, need, &hp, &ohp);
listp = NIL;
if ((state & ERTS_PORT_SFLG_BINARY_IO) == 0) {
@@ -3275,7 +3562,11 @@ static void deliver_read_message(Port* prt, erts_aint32_t state, Eterm to,
tuple = TUPLE2(hp, prt->common.id, tuple);
hp += 3;
- erts_queue_message(rp, &rp_locks, mp, tuple, am_undefined);
+ if (trace_send)
+ trace_port_send(prt, to, tuple, 1);
+
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
+ erts_queue_message(rp, rp_locks, mp, tuple, prt->common.id);
if (rp_locks)
erts_smp_proc_unlock(rp, rp_locks);
if (!scheduler)
@@ -3354,6 +3645,7 @@ deliver_vec_message(Port* prt, /* Port */
ErtsProcLocks rp_locks = 0;
int scheduler = erts_get_scheduler_id() != 0;
erts_aint32_t state;
+ int trace_send = IS_TRACED_FL(prt, F_TRACE_SEND);
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
ERTS_SMP_CHK_NO_PROC_LOCKS;
@@ -3381,7 +3673,7 @@ deliver_vec_message(Port* prt, /* Port */
need += (hlen+csize)*2;
}
- mp = erts_alloc_message_heap(rp, &rp_locks, need, &hp, &ohp);
+ mp = erts_alloc_message_heap(trace_send ? NULL : rp, &rp_locks, need, &hp, &ohp);
listp = NIL;
iov += vsize;
@@ -3442,7 +3734,11 @@ deliver_vec_message(Port* prt, /* Port */
tuple = TUPLE2(hp, prt->common.id, tuple);
hp += 3;
- erts_queue_message(rp, &rp_locks, mp, tuple, am_undefined);
+ if (IS_TRACED_FL(prt, F_TRACE_SEND))
+ trace_port_send(prt, to, tuple, 1);
+
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
+ erts_queue_message(rp, rp_locks, mp, tuple, prt->common.id);
erts_smp_proc_unlock(rp, rp_locks);
if (!scheduler)
erts_proc_dec_refc(rp);
@@ -3489,6 +3785,17 @@ static void flush_port(Port *p)
DTRACE3(driver_flush, process_str, port_str, p->name);
}
#endif
+#ifdef USE_LTTNG_VM_TRACEPOINTS
+ if (LTTNG_ENABLED(driver_flush)) {
+ lttng_decl_portbuf(port_str);
+ lttng_decl_procbuf(proc_str);
+ lttng_pid_to_str(ERTS_PORT_GET_CONNECTED(p), proc_str);
+ lttng_port_to_str(p, port_str);
+ LTTNG3(driver_flush, proc_str, port_str, p->name);
+ }
+#endif
+
+
if (IS_TRACED_FL(p, F_TRACE_SCHED_PORTS)) {
trace_sched_ports_where(p, am_in, am_flush);
}
@@ -3520,6 +3827,7 @@ terminate_port(Port *prt)
Eterm connected_id = NIL /* Initialize to silence compiler */;
erts_driver_t *drv;
erts_aint32_t state;
+ ErtsPrtSD *psd;
ERTS_SMP_CHK_NO_PROC_LOCKS;
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
@@ -3551,6 +3859,16 @@ terminate_port(Port *prt)
DTRACE3(driver_stop, process_str, drv->name, port_str);
}
#endif
+#ifdef USE_LTTNG_VM_TRACEPOINTS
+ if (LTTNG_ENABLED(driver_stop)) {
+ lttng_decl_portbuf(port_str);
+ lttng_decl_procbuf(proc_str);
+ lttng_pid_to_str(connected_id, proc_str);
+ lttng_port_to_str(prt, port_str);
+ LTTNG3(driver_stop, proc_str, port_str, drv->name);
+ }
+#endif
+
(*drv->stop)((ErlDrvData)prt->drv_data);
erts_unblock_fpe(fpe_was_unmasked);
ERTS_MSACC_POP_STATE_M();
@@ -3560,6 +3878,11 @@ terminate_port(Port *prt)
ASSERT(!prt->xports);
#endif
}
+
+ if (is_internal_port(send_closed_port_id)
+ && IS_TRACED_FL(prt, F_TRACE_SEND))
+ trace_port_send(prt, connected_id, am_closed, 1);
+
if(drv->handle != NULL) {
erts_smp_rwmtx_rlock(&erts_driver_list_lock);
erts_ddll_decrement_port_count(drv->handle);
@@ -3573,8 +3896,9 @@ terminate_port(Port *prt)
erts_cleanup_port_data(prt);
- if (prt->psd)
- erts_free(ERTS_ALC_T_PRTSD, prt->psd);
+ psd = (ErtsPrtSD *) erts_smp_atomic_read_nob(&prt->psd);
+ if (psd)
+ erts_free(ERTS_ALC_T_PRTSD, psd);
ASSERT(prt->dist_entry == NULL);
@@ -3590,7 +3914,7 @@ terminate_port(Port *prt)
erts_flush_async_exit(erts_halt_code, "");
}
if (is_internal_port(send_closed_port_id))
- deliver_result(send_closed_port_id, connected_id, am_closed);
+ deliver_result(NULL, send_closed_port_id, connected_id, am_closed);
}
void
@@ -3623,7 +3947,7 @@ static void sweep_one_monitor(ErtsMonitor *mon, void *vpsc)
typedef struct {
- Eterm port;
+ Port *port;
Eterm reason;
} SweepContext;
@@ -3632,10 +3956,13 @@ static void sweep_one_link(ErtsLink *lnk, void *vpsc)
SweepContext *psc = vpsc;
DistEntry *dep;
Process *rp;
-
+ Eterm port_id = psc->port->common.id;
ASSERT(lnk->type == LINK_PID);
-
+
+ if (IS_TRACED_FL(psc->port, F_TRACE_PORTS))
+ trace_port(psc->port, am_unlink, lnk->pid);
+
if (is_external_pid(lnk->pid)) {
dep = external_pid_dist_entry(lnk->pid);
if(dep != erts_this_dist_entry) {
@@ -3648,9 +3975,9 @@ static void sweep_one_link(ErtsLink *lnk, void *vpsc)
case ERTS_DSIG_PREP_NOT_CONNECTED:
break;
case ERTS_DSIG_PREP_CONNECTED:
- erts_remove_dist_link(&dld, psc->port, lnk->pid, dep);
+ erts_remove_dist_link(&dld, port_id, lnk->pid, dep);
erts_destroy_dist_link(&dld);
- code = erts_dsig_send_exit(&dsd, psc->port, lnk->pid,
+ code = erts_dsig_send_exit(&dsd, port_id, lnk->pid,
psc->reason);
ASSERT(code == ERTS_DSIG_SEND_OK);
break;
@@ -3664,23 +3991,25 @@ static void sweep_one_link(ErtsLink *lnk, void *vpsc)
ASSERT(is_internal_pid(lnk->pid));
rp = erts_pid2proc(NULL, 0, lnk->pid, rp_locks);
if (rp) {
- ErtsLink *rlnk = erts_remove_link(&ERTS_P_LINKS(rp), psc->port);
+ ErtsLink *rlnk = erts_remove_link(&ERTS_P_LINKS(rp), port_id);
if (rlnk) {
int xres = erts_send_exit_signal(NULL,
- psc->port,
+ port_id,
rp,
&rp_locks,
psc->reason,
NIL,
NULL,
0);
- if (xres >= 0 && IS_TRACED_FL(rp, F_TRACE_PROCS)) {
+ if (xres >= 0) {
+ if (rp_locks & ERTS_PROC_LOCKS_XSIG_SEND) {
+ erts_smp_proc_unlock(rp, ERTS_PROC_LOCKS_XSIG_SEND);
+ rp_locks &= ~ERTS_PROC_LOCKS_XSIG_SEND;
+ }
/* We didn't exit the process and it is traced */
- if (IS_TRACED_FL(rp, F_TRACE_PROCS)) {
- trace_proc(NULL, rp, am_getting_unlinked,
- psc->port);
- }
+ if (IS_TRACED_FL(rp, F_TRACE_PROCS))
+ trace_proc(NULL, 0, rp, am_getting_unlinked, port_id);
}
erts_destroy_link(rlnk);
}
@@ -3702,7 +4031,8 @@ static void sweep_one_link(ErtsLink *lnk, void *vpsc)
*/
int
-erts_deliver_port_exit(Port *p, Eterm from, Eterm reason, int send_closed)
+erts_deliver_port_exit(Port *p, Eterm from, Eterm reason, int send_closed,
+ int drop_normal)
{
ErtsLink *lnk;
Eterm rreason;
@@ -3732,8 +4062,10 @@ erts_deliver_port_exit(Port *p, Eterm from, Eterm reason, int send_closed)
| ERTS_PORT_SFLG_CLOSING))
return 0;
- if (reason == am_normal && from != ERTS_PORT_GET_CONNECTED(p) && from != p->common.id)
+ if (reason == am_normal && from != ERTS_PORT_GET_CONNECTED(p)
+ && from != p->common.id && drop_normal) {
return 0;
+ }
set_state_flags = ERTS_PORT_SFLG_EXITING;
if (send_closed)
@@ -3744,9 +4076,8 @@ erts_deliver_port_exit(Port *p, Eterm from, Eterm reason, int send_closed)
state = erts_atomic32_read_bor_mb(&p->state, set_state_flags);
state |= set_state_flags;
- if (IS_TRACED_FL(p, F_TRACE_PORTS)) {
+ if (IS_TRACED_FL(p, F_TRACE_PORTS))
trace_port(p, am_closed, reason);
- }
erts_trace_check_exiting(p->common.id);
@@ -3756,7 +4087,7 @@ erts_deliver_port_exit(Port *p, Eterm from, Eterm reason, int send_closed)
(void) erts_unregister_name(NULL, 0, p, p->common.u.alive.reg->name);
{
- SweepContext sc = {p->common.id, rreason};
+ SweepContext sc = {p, rreason};
lnk = ERTS_P_LINKS(p);
ERTS_P_LINKS(p) = NULL;
erts_sweep_links(lnk, &sweep_one_link, &sc);
@@ -3878,9 +4209,22 @@ call_driver_control(Eterm caller,
command, size);
}
#endif
-
+
+ if (IS_TRACED_FL(prt, F_TRACE_RECEIVE))
+ trace_port_receive(prt, caller, am_control, command, bufp, size);
+
ERTS_MSACC_SET_STATE_CACHED_M(ERTS_MSACC_STATE_PORT);
+#ifdef USE_LTTNG_VM_TRACEPOINTS
+ if (LTTNG_ENABLED(driver_control)) {
+ lttng_decl_procbuf(proc_str);
+ lttng_decl_portbuf(port_str);
+ lttng_pid_to_str(caller, proc_str);
+ lttng_port_to_str(prt, port_str);
+ LTTNG5(driver_control, proc_str, port_str, prt->name, command, size);
+ }
+#endif
+
prt->caller = caller;
cres = prt->drv_ptr->control((ErlDrvData) prt->drv_data,
command,
@@ -3895,6 +4239,9 @@ call_driver_control(Eterm caller,
if (cres < 0)
return ERTS_PORT_OP_BADARG;
+ if (IS_TRACED_FL(prt, F_TRACE_SEND))
+ trace_port_send_binary(prt, caller, am_control, *resp_bufp, cres);
+
*from_size = (ErlDrvSizeT) cres;
return ERTS_PORT_OP_DONE;
@@ -4045,10 +4392,11 @@ port_sig_control(Port *prt,
&factory.hp,
factory.off_heap);
queue_port_sched_op_reply(rp,
- &rp_locks,
+ rp_locks,
&factory,
sigdp->ref,
- msg);
+ msg,
+ prt);
if (rp_locks)
erts_smp_proc_unlock(rp, rp_locks);
@@ -4059,7 +4407,7 @@ port_sig_control(Port *prt,
/* failure */
if (sigdp->caller != ERTS_INVALID_PID)
- port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg);
+ port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg, prt);
done:
@@ -4294,6 +4642,18 @@ call_driver_call(Eterm caller,
DTRACE5(driver_call, process_str, port_str, prt->name, command, size);
}
#endif
+#ifdef USE_LTTNG_VM_TRACEPOINTS
+ if (LTTNG_ENABLED(driver_call)) {
+ lttng_decl_procbuf(proc_str);
+ lttng_decl_portbuf(port_str);
+ lttng_pid_to_str(caller,proc_str);
+ lttng_port_to_str(prt, port_str);
+ LTTNG5(driver_call, proc_str, port_str, prt->name, command, size);
+ }
+#endif
+
+ if (IS_TRACED_FL(prt, F_TRACE_RECEIVE))
+ trace_port_receive(prt, caller, am_call, command, bufp, size);
ERTS_MSACC_SET_STATE_CACHED_M(ERTS_MSACC_STATE_PORT);
@@ -4313,6 +4673,9 @@ call_driver_call(Eterm caller,
|| ((byte) (*resp_bufp)[0]) != VERSION_MAGIC)
return ERTS_PORT_OP_BADARG;
+ if (IS_TRACED_FL(prt, F_TRACE_SEND))
+ trace_port_send_binary(prt, caller, am_call, *resp_bufp, cres);
+
*from_size = (ErlDrvSizeT) cres;
return ERTS_PORT_OP_DONE;
@@ -4373,7 +4736,7 @@ port_sig_call(Port *prt,
(void) erts_factory_message_create(&factory, rp, &rp_locks, hsz);
endp = (byte *) resp_bufp;
- msg = erts_decode_ext(&factory, &endp);
+ msg = erts_decode_ext(&factory, &endp, 0);
if (is_value(msg)) {
hp = erts_produce_heap(&factory,
3,
@@ -4381,10 +4744,11 @@ port_sig_call(Port *prt,
msg = TUPLE2(hp, am_ok, msg);
queue_port_sched_op_reply(rp,
- &rp_locks,
+ rp_locks,
&factory,
sigdp->ref,
- msg);
+ msg,
+ prt);
if (rp_locks)
erts_smp_proc_unlock(rp, rp_locks);
@@ -4396,7 +4760,7 @@ port_sig_call(Port *prt,
}
}
- port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg);
+ port_sched_op_reply(sigdp->caller, sigdp->ref, am_badarg, prt);
done:
@@ -4492,7 +4856,7 @@ erts_port_call(Process* c_p,
hsz += 3;
erts_factory_proc_prealloc_init(&factory, c_p, hsz);
endp = (byte *) resp_bufp;
- term = erts_decode_ext(&factory, &endp);
+ term = erts_decode_ext(&factory, &endp, 0);
if (term == THE_NON_VALUE)
return ERTS_PORT_OP_BADARG;
hp = erts_produce_heap(&factory,3,0);
@@ -4611,7 +4975,7 @@ port_sig_info(Port *prt,
{
ASSERT(sigdp->flags & ERTS_P2P_SIG_DATA_FLG_REPLY);
if (op != ERTS_PROC2PORT_SIG_EXEC)
- port_sched_op_reply(sigdp->caller, sigdp->ref, am_undefined);
+ port_sched_op_reply(sigdp->caller, sigdp->ref, am_undefined, prt);
else {
Eterm *hp, *hp_start;
Uint hsz;
@@ -4637,10 +5001,11 @@ port_sig_info(Port *prt,
mp->data.heap_frag = bp;
erts_factory_selfcontained_message_init(&factory, mp, hp);
queue_port_sched_op_reply(rp,
- &rp_locks,
+ rp_locks,
&factory,
sigdp->ref,
- value);
+ value,
+ prt);
}
if (rp_locks)
erts_smp_proc_unlock(rp, rp_locks);
@@ -4756,7 +5121,8 @@ reply_io_bytes(void *vreq)
eout = erts_bld_uint64(&hp, NULL, out);
msg = TUPLE4(hp, ref, make_small(sched_id), ein, eout);
- erts_queue_message(rp, &rp_locks, mp, msg, NIL);
+
+ erts_queue_message(rp, rp_locks, mp, msg, am_system);
if (req->sched_id == sched_id)
rp_locks &= ~ERTS_PROC_LOCK_MAIN;
@@ -5056,6 +5422,15 @@ int async_ready(Port *p, void* data)
DTRACE3(driver_ready_async, process_str, port_str, p->name);
}
#endif
+#ifdef USE_LTTNG_VM_TRACEPOINTS
+ if (LTTNG_ENABLED(driver_ready_async)) {
+ lttng_decl_portbuf(port_str);
+ lttng_decl_procbuf(proc_str);
+ lttng_pid_to_str(ERTS_PORT_GET_CONNECTED(p), proc_str);
+ lttng_port_to_str(p, port_str);
+ LTTNG3(driver_ready_async, proc_str, port_str, p->name);
+ }
+#endif
(*p->drv_ptr->ready_async)((ErlDrvData)p->drv_data, data);
need_free = 0;
ERTS_MSACC_POP_STATE_M();
@@ -5218,6 +5593,7 @@ void driver_report_exit(ErlDrvPort ix, int status)
ErtsProcLocks rp_locks = 0;
int scheduler = erts_get_scheduler_id() != 0;
Port* prt = erts_drvport2port(ix);
+ int trace_send = IS_TRACED_FL(prt, F_TRACE_SEND);
if (prt == ERTS_INVALID_ERL_DRV_PORT)
return;
@@ -5234,13 +5610,17 @@ void driver_report_exit(ErlDrvPort ix, int status)
if (!rp)
return;
- mp = erts_alloc_message_heap(rp, &rp_locks, 3+3, &hp, &ohp);
+ mp = erts_alloc_message_heap(trace_send ? NULL : rp, &rp_locks, 3+3, &hp, &ohp);
tuple = TUPLE2(hp, am_exit_status, make_small(status));
hp += 3;
tuple = TUPLE2(hp, prt->common.id, tuple);
- erts_queue_message(rp, &rp_locks, mp, tuple, am_undefined);
+ if (IS_TRACED_FL(prt, F_TRACE_SEND))
+ trace_port_send(prt, pid, tuple, 1);
+
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
+ erts_queue_message(rp, rp_locks, mp, tuple, prt->common.id);
erts_smp_proc_unlock(rp, rp_locks);
if (!scheduler)
@@ -5334,13 +5714,13 @@ cleanup_b2t_states(struct b2t_states__ *b2tsp)
*/
static int
-driver_deliver_term(Eterm to, ErlDrvTermData* data, int len)
+driver_deliver_term(Port *prt, Eterm to, ErlDrvTermData* data, int len)
{
#define HEAP_EXTRA 200
#define ERTS_DDT_FAIL do { res = -1; goto done; } while (0)
Uint need = 0;
int depth = 0;
- int res;
+ int res = 0;
ErlDrvTermData* ptr;
ErlDrvTermData* ptr_end;
DECLARE_ESTACK(stack);
@@ -5559,11 +5939,26 @@ driver_deliver_term(Eterm to, ErlDrvTermData* data, int len)
? erts_proc_lookup(to)
: erts_pid2proc_opt(NULL, 0, to, 0, ERTS_P2P_FLG_INC_REFC));
if (!rp) {
- res = 0;
- goto done;
- }
+ if (!prt || !IS_TRACED_FL(prt, F_TRACE_SEND))
+ goto done;
+ if (!erts_is_tracer_proc_enabled(NULL, 0, &prt->common, am_send))
+ goto done;
+
+ res = -2;
- (void) erts_factory_message_create(&factory, rp, &rp_locks, need);
+ /* We allocate a temporary heap to be used to create
+ the message that may be sent using tracing */
+ erts_factory_tmp_init(&factory, erts_alloc(ERTS_ALC_T_DRIVER, need*sizeof(Eterm)),
+ need, ERTS_ALC_T_DRIVER);
+
+ } else {
+ /* We force the creation of a heap fragment (rp == NULL) when send
+ tracing so that we don't have the main lock of the process while
+ tracing */
+ Process *trace_rp = prt && IS_TRACED_FL(prt, F_TRACE_SEND) ? NULL : rp;
+ (void) erts_factory_message_create(&factory, trace_rp, &rp_locks, need);
+ res = 1;
+ }
/*
* Interpret the instructions and build the term.
@@ -5826,22 +6221,45 @@ driver_deliver_term(Eterm to, ErlDrvTermData* data, int len)
ESTACK_PUSH(stack, mess);
}
- res = 1;
-
done:
if (res > 0) {
+ Eterm from = am_undefined;
mess = ESTACK_POP(stack); /* get resulting value */
erts_factory_trim_and_close(&factory, &mess, 1);
+
+ if (prt) {
+ if (IS_TRACED_FL(prt, F_TRACE_SEND)) {
+ trace_port_send(prt, to, mess, 1);
+ }
+ from = prt->common.id;
+ }
+
/* send message */
- erts_queue_message(rp, &rp_locks, factory.message, mess, am_undefined);
+ ERL_MESSAGE_TOKEN(factory.message) = am_undefined;
+ erts_queue_message(rp, rp_locks, factory.message, mess, from);
+ }
+ else if (res == -2) {
+ /* this clause only happens when we were requested to
+ generate a send trace, but the process to send to
+ did not exist any more */
+ mess = ESTACK_POP(stack); /* get resulting value */
+
+ trace_port_send(prt, to, mess, 0);
+
+ erts_factory_trim_and_close(&factory, &mess, 1);
+ erts_free(ERTS_ALC_T_DRIVER, factory.hp_start);
+ res = 0;
}
else {
if (b2t.ix > b2t.used)
b2t.used = b2t.ix;
for (b2t.ix = 0; b2t.ix < b2t.used; b2t.ix++)
erts_binary2term_abort(&b2t.state[b2t.ix]);
- erts_factory_undo(&factory);
+ if (factory.mode != FACTORY_CLOSED) {
+ ERL_MESSAGE_TERM(factory.message) = am_undefined;
+ erts_factory_undo(&factory);
+ }
}
if (rp) {
if (rp_locks)
@@ -5857,7 +6275,8 @@ driver_deliver_term(Eterm to, ErlDrvTermData* data, int len)
}
static ERTS_INLINE int
-deliver_term_check_port(ErlDrvTermData port_id, Eterm *connected_p)
+deliver_term_check_port(ErlDrvTermData port_id, Eterm *connected_p,
+ Port **trace_prt)
{
#ifdef ERTS_SMP
ErtsThrPrgrDelayHandle dhndl = erts_thr_progress_unmanaged_delay();
@@ -5885,8 +6304,11 @@ deliver_term_check_port(ErlDrvTermData port_id, Eterm *connected_p)
if (dhndl != ERTS_THR_PRGR_DHANDLE_MANAGED) {
erts_thr_progress_unmanaged_continue(dhndl);
ETHR_MEMBAR(ETHR_LoadLoad|ETHR_LoadStore);
- }
+ } else
#endif
+ {
+ *trace_prt = prt;
+ }
ERTS_SMP_LC_ASSERT(dhndl == ERTS_THR_PRGR_DHANDLE_MANAGED
? erts_lc_is_port_locked(prt)
: !erts_lc_is_port_locked(prt));
@@ -5897,10 +6319,11 @@ int erl_drv_output_term(ErlDrvTermData port_id, ErlDrvTermData* data, int len)
{
/* May be called from arbitrary thread */
Eterm connected;
- int res = deliver_term_check_port(port_id, &connected);
+ Port *prt = NULL;
+ int res = deliver_term_check_port(port_id, &connected, &prt);
if (res <= 0)
return res;
- return driver_deliver_term(connected, data, len);
+ return driver_deliver_term(prt, connected, data, len);
}
/*
@@ -5924,7 +6347,7 @@ driver_output_term(ErlDrvPort drvport, ErlDrvTermData* data, int len)
if (state & ERTS_PORT_SFLG_CLOSING)
return 0;
- return driver_deliver_term(ERTS_PORT_GET_CONNECTED(prt), data, len);
+ return driver_deliver_term(prt, ERTS_PORT_GET_CONNECTED(prt), data, len);
}
int erl_drv_send_term(ErlDrvTermData port_id,
@@ -5933,10 +6356,11 @@ int erl_drv_send_term(ErlDrvTermData port_id,
int len)
{
/* May be called from arbitrary thread */
- int res = deliver_term_check_port(port_id, NULL);
+ Port *prt = NULL;
+ int res = deliver_term_check_port(port_id, NULL, &prt);
if (res <= 0)
return res;
- return driver_deliver_term(to, data, len);
+ return driver_deliver_term(prt, to, data, len);
}
/*
@@ -5955,20 +6379,21 @@ driver_send_term(ErlDrvPort drvport,
* to make this access safe without using a less efficient
* internal data representation for ErlDrvPort.
*/
+ Port* prt = NULL;
ERTS_SMP_CHK_NO_PROC_LOCKS;
#ifdef ERTS_SMP
if (erts_thr_progress_is_managed_thread())
#endif
{
erts_aint32_t state;
- Port* prt = erts_drvport2port_state(drvport, &state);
+ prt = erts_drvport2port_state(drvport, &state);
if (prt == ERTS_INVALID_ERL_DRV_PORT)
return -1; /* invalid (dead) */
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt));
if (state & ERTS_PORT_SFLG_CLOSING)
return 0;
}
- return driver_deliver_term(to, data, len);
+ return driver_deliver_term(prt, to, data, len);
}
@@ -7102,6 +7527,15 @@ void erts_fire_port_monitor(Port *prt, Eterm ref)
DTRACE3(driver_process_exit, process_str, port_str, prt->name);
}
#endif
+#ifdef USE_LTTNG_VM_TRACEPOINTS
+ if (LTTNG_ENABLED(driver_process_exit)) {
+ lttng_decl_portbuf(port_str);
+ lttng_decl_procbuf(proc_str);
+ lttng_pid_to_str(ERTS_PORT_GET_CONNECTED(prt), proc_str);
+ lttng_port_to_str(prt, port_str);
+ LTTNG3(driver_process_exit, proc_str, port_str, prt->name);
+ }
+#endif
fpe_was_unmasked = erts_block_fpe();
(*callback)((ErlDrvData) (prt->drv_data), &drv_monitor);
erts_unblock_fpe(fpe_was_unmasked);
@@ -7135,7 +7569,7 @@ driver_failure_term(ErlDrvPort ix, Eterm term, int eof)
if (state & ERTS_PORT_SFLG_CLOSING) {
terminate_port(prt);
} else if (eof && (state & ERTS_PORT_SFLG_SOFT_EOF)) {
- deliver_result(prt->common.id, ERTS_PORT_GET_CONNECTED(prt), am_eof);
+ deliver_result(prt, prt->common.id, ERTS_PORT_GET_CONNECTED(prt), am_eof);
} else {
/* XXX UGLY WORK AROUND, Let erts_deliver_port_exit() terminate the port */
if (prt->port_data_lock)
@@ -7143,7 +7577,7 @@ driver_failure_term(ErlDrvPort ix, Eterm term, int eof)
prt->ioq.size = 0;
if (prt->port_data_lock)
driver_pdl_unlock(prt->port_data_lock);
- erts_deliver_port_exit(prt, prt->common.id, eof ? am_normal : term, 0);
+ erts_deliver_port_exit(prt, prt->common.id, eof ? am_normal : term, 0, 0);
}
return 0;
}
@@ -7579,6 +8013,8 @@ init_driver(erts_driver_t *drv, ErlDrvEntry *de, DE_Handle *handle)
int fpe_was_unmasked = erts_block_fpe();
DTRACE4(driver_init, drv->name, drv->version.major, drv->version.minor,
drv->flags);
+ LTTNG4(driver_init, drv->name, drv->version.major, drv->version.minor,
+ drv->flags);
res = (*de->init)();
erts_unblock_fpe(fpe_was_unmasked);
return res;
diff --git a/erts/emulator/beam/lttng-wrapper.h b/erts/emulator/beam/lttng-wrapper.h
new file mode 100644
index 0000000000..294872c365
--- /dev/null
+++ b/erts/emulator/beam/lttng-wrapper.h
@@ -0,0 +1,107 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1996-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%
+ */
+
+#ifndef __LTTNG_WRAPPER_H__
+#define __LTTNG_WRAPPER_H__
+
+#ifdef USE_LTTNG
+
+#include "erlang_lttng.h"
+#define USE_LTTNG_VM_TRACEPOINTS
+
+#define LTTNG_BUFFER_SZ (256)
+#define LTTNG_PROC_BUFFER_SZ (16)
+#define LTTNG_PORT_BUFFER_SZ (20)
+#define LTTNG_MFA_BUFFER_SZ (256)
+
+#define lttng_decl_procbuf(Name) \
+ char Name[LTTNG_PROC_BUFFER_SZ]
+
+#define lttng_decl_portbuf(Name) \
+ char Name[LTTNG_PORT_BUFFER_SZ]
+
+#define lttng_decl_mfabuf(Name) \
+ char Name[LTTNG_MFA_BUFFER_SZ]
+
+#define lttng_decl_carrier_stats(Name) \
+ lttng_carrier_stats_t Name##_STATSTRUCT, *Name = &Name##_STATSTRUCT
+
+#define lttng_pid_to_str(pid, name) \
+ erts_snprintf(name, LTTNG_PROC_BUFFER_SZ, "%T", (pid))
+
+#define lttng_portid_to_str(pid, name) \
+ erts_snprintf(name, LTTNG_PORT_BUFFER_SZ, "%T", (pid))
+
+#define lttng_proc_to_str(p, name) \
+ lttng_pid_to_str(((p) ? (p)->common.id : ERTS_INVALID_PID), name)
+
+#define lttng_port_to_str(p, name) \
+ lttng_portid_to_str(((p) ? (p)->common.id : ERTS_INVALID_PORT), name)
+
+#define lttng_mfa_to_str(m,f,a, Name) \
+ erts_snprintf(Name, LTTNG_MFA_BUFFER_SZ, "%T:%T/%lu", (Eterm)(m), (Eterm)(f), (Uint)(a))
+
+#define lttng_proc_to_mfa_str(p, Name) \
+ do { \
+ if (ERTS_PROC_IS_EXITING((p))) { \
+ strcpy(Name, "<exiting>"); \
+ } else { \
+ BeamInstr *_fptr = find_function_from_pc((p)->i); \
+ if (_fptr) { \
+ lttng_mfa_to_str(_fptr[0],_fptr[1],_fptr[2], Name); \
+ } else { \
+ strcpy(Name, "<unknown>"); \
+ } \
+ } \
+ } while(0)
+
+/* ErtsRunQueue->ErtsSchedulerData->Uint */
+#define lttng_rq_to_id(RQ) \
+ (RQ)->scheduler->no
+
+#define LTTNG_ENABLED(Name) \
+ tracepoint_enabled(com_ericsson_otp, Name)
+
+/* include a special LTTNG_DO for do_tracepoint ? */
+#define LTTNG1(Name, Arg1) \
+ tracepoint(com_ericsson_otp, Name, (Arg1))
+
+#define LTTNG2(Name, Arg1, Arg2) \
+ tracepoint(com_ericsson_otp, Name, (Arg1), (Arg2))
+
+#define LTTNG3(Name, Arg1, Arg2, Arg3) \
+ tracepoint(com_ericsson_otp, Name, (Arg1), (Arg2), (Arg3))
+
+#define LTTNG4(Name, Arg1, Arg2, Arg3, Arg4) \
+ tracepoint(com_ericsson_otp, Name, (Arg1), (Arg2), (Arg3), (Arg4))
+
+#define LTTNG5(Name, Arg1, Arg2, Arg3, Arg4, Arg5) \
+ tracepoint(com_ericsson_otp, Name, (Arg1), (Arg2), (Arg3), (Arg4), (Arg5))
+
+#else /* USE_LTTNG */
+
+#define LTTNG1(Name, Arg1) do {} while(0)
+#define LTTNG2(Name, Arg1, Arg2) do {} while(0)
+#define LTTNG3(Name, Arg1, Arg2, Arg3) do {} while(0)
+#define LTTNG4(Name, Arg1, Arg2, Arg3, Arg4) do {} while(0)
+#define LTTNG5(Name, Arg1, Arg2, Arg3, Arg4, Arg5) do {} while(0)
+
+#endif /* USE_LTTNG */
+#endif /* __LTTNG_WRAPPER_H__ */
diff --git a/erts/emulator/beam/module.c b/erts/emulator/beam/module.c
index f5c7b177d3..3eb11f1693 100644
--- a/erts/emulator/beam/module.c
+++ b/erts/emulator/beam/module.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/beam/module.h b/erts/emulator/beam/module.h
index b7468b0926..4e12731d85 100644
--- a/erts/emulator/beam/module.h
+++ b/erts/emulator/beam/module.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab
index 9e53b4bfcc..879daaca0a 100644
--- a/erts/emulator/beam/ops.tab
+++ b/erts/emulator/beam/ops.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2013. All Rights Reserved.
+# Copyright Ericsson AB 1997-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.
@@ -181,11 +181,6 @@ i_jump_on_val_zero y f I
i_jump_on_val x f I I
i_jump_on_val y f I I
-jump Target | label Lbl | same_label(Target, Lbl) => label Lbl
-
-is_ne_exact L1 S1 S2 | jump Fail | label L2 | same_label(L1, L2) => \
- is_eq_exact Fail S1 S2 | label L2
-
%macro: get_list GetList -pack
get_list x x x
get_list x x y
@@ -234,6 +229,9 @@ i_get_tuple_element y P y
%macro: i_get_tuple_element2 GetTupleElement2 -pack
i_get_tuple_element2 x P x
+%macro: i_get_tuple_element2y GetTupleElement2Y -pack
+i_get_tuple_element2y x P y y
+
%macro: i_get_tuple_element3 GetTupleElement3 -pack
i_get_tuple_element3 x P x
@@ -256,7 +254,14 @@ case_end x
badmatch x
if_end
-raise s s
+
+# Operands for raise/2 are almost always in x(2) and x(1).
+# Optimize for that case.
+raise x==2 x==1 => i_raise
+raise Trace=y Value=y => move Trace x=2 | move Value x=1 | i_raise
+raise Trace Value => move Trace x=3 | move Value x=1 | move x=3 x=2 | i_raise
+
+i_raise
# Internal now, but could be useful to make known to the compiler.
badarg j
@@ -303,7 +308,7 @@ move_window5 x x x x x y
# Swap registers.
move R1=x Tmp=x | move R2=xy R1 | move Tmp R2 => swap_temp R1 R2 Tmp
-swap_temp R1 R2 Tmp | line Loc | apply Live | is_killed(Tmp, Live) => \
+swap_temp R1 R2 Tmp | line Loc | apply Live | is_killed_apply(Tmp, Live) => \
swap R1 R2 | line Loc | apply Live
swap_temp R1 R2 Tmp | line Loc | call Live Addr | is_killed(Tmp, Live) => \
@@ -527,9 +532,9 @@ i_put_tuple x I
i_put_tuple y I
#
-# The instruction "put_list Const [] Dst" will not be generated by
-# the current BEAM compiler. But until R15A, play it safe by handling
-# that instruction with the following transformation.
+# The instruction "put_list Const [] Dst" were generated in rare
+# circumstances up to and including OTP 18. Starting with OTP 19,
+# AFAIK, it should never be generated.
#
put_list Const=c n Dst => move Const x | put_list x n Dst
@@ -647,6 +652,9 @@ get_tuple_element Reg=x P1 D1=x | get_tuple_element Reg=x P2 D2=x | \
get_tuple_element Reg=x P1 D1=x | get_tuple_element Reg=x P2 D2=x | \
succ(P1, P2) | succ(D1, D2) => i_get_tuple_element2 Reg P1 D1
+get_tuple_element Reg=x P1 D1=y | get_tuple_element Reg=x P2 D2=y | \
+ succ(P1, P2) => i_get_tuple_element2y Reg P1 D1 D2
+
get_tuple_element Reg P Dst => i_get_tuple_element Reg P Dst
is_integer Fail=f i =>
@@ -1355,9 +1363,7 @@ bs_put_utf8 Fail u Src=s => i_bs_put_utf8 Fail Src
i_bs_put_utf8 j s
-bs_put_utf16 Fail Flags=u Src=s => i_bs_put_utf16 Fail Flags Src
-
-i_bs_put_utf16 j I s
+bs_put_utf16 j I s
bs_put_utf32 Fail=j Flags=u Src=s => \
i_bs_validate_unicode Fail Src | bs_put_integer Fail i=32 u=1 Flags Src
@@ -1539,7 +1545,6 @@ gen_minus p Live Reg=d Int=i Dst | negation_is_small(Int) => \
# GCing arithmetic instructions.
#
-gen_plus Fail Live Y=y X=x Dst => i_plus Fail Live X Y Dst
gen_plus Fail Live S1 S2 Dst => i_plus Fail Live S1 S2 Dst
gen_minus Fail Live S1 S2 Dst => i_minus Fail Live S1 S2 Dst
diff --git a/erts/emulator/beam/packet_parser.c b/erts/emulator/beam/packet_parser.c
index a737a86f14..f14910bc72 100644
--- a/erts/emulator/beam/packet_parser.c
+++ b/erts/emulator/beam/packet_parser.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/emulator/beam/packet_parser.h b/erts/emulator/beam/packet_parser.h
index 717d905fad..358d650804 100644
--- a/erts/emulator/beam/packet_parser.h
+++ b/erts/emulator/beam/packet_parser.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/emulator/beam/register.c b/erts/emulator/beam/register.c
index ebc35b0c4d..77f79fcea4 100644
--- a/erts/emulator/beam/register.c
+++ b/erts/emulator/beam/register.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -226,7 +226,8 @@ int erts_register_name(Process *c_p, Eterm name, Eterm id)
rp = (RegProc*) hash_put(&process_reg, (void*) &r);
if (proc && rp->p == proc) {
if (IS_TRACED_FL(proc, F_TRACE_PROCS)) {
- trace_proc(c_p, proc, am_register, name);
+ trace_proc(proc, ERTS_PROC_LOCK_MAIN,
+ proc, am_register, name);
}
proc->common.u.alive.reg = rp;
}
@@ -470,8 +471,8 @@ int erts_unregister_name(Process *c_p,
int res = 0;
RegProc r, *rp;
Port *port = c_prt;
+ ErtsProcLocks current_c_p_locks = 0;
#ifdef ERTS_SMP
- ErtsProcLocks current_c_p_locks;
/*
* SMP note: If 'c_prt != NULL' and 'c_prt->reg->name == name',
@@ -537,8 +538,12 @@ int erts_unregister_name(Process *c_p,
ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(port));
rp->pt->common.u.alive.reg = NULL;
-
+
if (IS_TRACED_FL(port, F_TRACE_PORTS)) {
+ if (current_c_p_locks) {
+ erts_smp_proc_unlock(c_p, current_c_p_locks);
+ current_c_p_locks = 0;
+ }
trace_port(port, am_unregister, r.name);
}
@@ -555,7 +560,8 @@ int erts_unregister_name(Process *c_p,
#endif
rp->p->common.u.alive.reg = NULL;
if (IS_TRACED_FL(rp->p, F_TRACE_PROCS)) {
- trace_proc(c_p, rp->p, am_unregister, r.name);
+ trace_proc(rp->p, (c_p == rp->p) ? c_p_locks : ERTS_PROC_LOCK_MAIN,
+ rp->p, am_unregister, r.name);
}
#ifdef ERTS_SMP
if (rp->p != c_p) {
diff --git a/erts/emulator/beam/register.h b/erts/emulator/beam/register.h
index 144536f34b..88ab7b7bf1 100644
--- a/erts/emulator/beam/register.h
+++ b/erts/emulator/beam/register.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2012. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/beam/safe_hash.c b/erts/emulator/beam/safe_hash.c
index 3f039c8dfd..30b26a7296 100644
--- a/erts/emulator/beam/safe_hash.c
+++ b/erts/emulator/beam/safe_hash.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/emulator/beam/safe_hash.h b/erts/emulator/beam/safe_hash.h
index a11370813c..6910b33004 100644
--- a/erts/emulator/beam/safe_hash.h
+++ b/erts/emulator/beam/safe_hash.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h
index 03b9088adc..dda3ba565c 100644
--- a/erts/emulator/beam/sys.h
+++ b/erts/emulator/beam/sys.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -92,6 +92,9 @@
#define ErtsInArea(ptr,start,nbytes) \
((UWord)((char*)(ptr) - (char*)(start)) < (nbytes))
+#define ErtsContainerStruct(ptr, type, member) \
+ (type *)((char *)(1 ? (ptr) : &((type *)0)->member) - offsetof(type, member))
+
#if defined (__WIN32__)
# include "erl_win_sys.h"
#else
@@ -138,10 +141,10 @@ typedef ERTS_SYS_FD_TYPE ErtsSysFdType;
#endif
#if ERTS_AT_LEAST_GCC_VSN__(2, 96, 0)
-#ifndef __llvm__
-# define ERTS_WRITE_UNLIKELY(X) X __attribute__ ((section ("ERTS_LOW_WRITE") ))
-#else
+#if (defined(__APPLE__) && defined(__MACH__)) || defined(__DARWIN__)
# define ERTS_WRITE_UNLIKELY(X) X __attribute__ ((section ("__DATA,ERTS_LOW_WRITE") ))
+#else
+# define ERTS_WRITE_UNLIKELY(X) X __attribute__ ((section ("ERTS_LOW_WRITE") ))
#endif
#else
# define ERTS_WRITE_UNLIKELY(X) X
@@ -644,6 +647,15 @@ typedef struct preload {
unsigned char* code; /* Code pointer */
} Preload;
+/*
+ * ErtsTracer is either NIL, 'true' or [Mod | State]
+ *
+ * If set to NIL, it means no tracer.
+ * If set to 'true' it means the current process' tracer.
+ * If set to [Mod | State], there is a tracer.
+ * See erts_tracer_update for more details
+ */
+typedef Eterm ErtsTracer;
/*
* This structure contains options to all built in drivers.
diff --git a/erts/emulator/beam/time.c b/erts/emulator/beam/time.c
index 0ce4f443f3..6f15082130 100644
--- a/erts/emulator/beam/time.c
+++ b/erts/emulator/beam/time.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index 66fcfcf6ce..cedc88e5fe 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -71,41 +71,6 @@
#define HAVE_MALLOPT 0
#endif
-/* profile_scheduler mini message queue */
-
-typedef struct {
- Uint scheduler_id;
- Uint no_schedulers;
- Uint Ms;
- Uint s;
- Uint us;
- Eterm state;
-} profile_sched_msg;
-
-typedef struct {
- profile_sched_msg msg[2];
- Uint n;
-} profile_sched_msg_q;
-
-#ifdef ERTS_SMP
-
-#if 0 /* Unused */
-static void
-dispatch_profile_msg_q(profile_sched_msg_q *psmq)
-{
- int i = 0;
- profile_sched_msg *msg = NULL;
- ASSERT(psmq != NULL);
- for (i = 0; i < psmq->n; i++) {
- msg = &(psmq->msg[i]);
- profile_scheduler_q(make_small(msg->scheduler_id), msg->state, am_undefined, msg->Ms, msg->s, msg->us);
- }
-}
-#endif
-
-#endif
-
-
Eterm*
erts_heap_alloc(Process* p, Uint need, Uint xtra)
{
@@ -2298,7 +2263,7 @@ static void do_send_logger_message(Eterm *hp, ErlOffHeap *ohp, ErlHeapFragment *
{
ErtsMessage *mp = erts_alloc_message(0, NULL);
mp->data.heap_frag = bp;
- erts_queue_message(p, NULL /* only used for smp build */, mp, message, NIL);
+ erts_queue_message(p, 0, mp, message, am_system);
}
#endif
}
diff --git a/erts/emulator/beam/version.h b/erts/emulator/beam/version.h
index 004725eaf5..0fa775fe8c 100644
--- a/erts/emulator/beam/version.h
+++ b/erts/emulator/beam/version.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c
index 3088dfd572..3adb8db661 100644
--- a/erts/emulator/drivers/common/efile_drv.c
+++ b/erts/emulator/drivers/common/efile_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -2900,12 +2900,12 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count)
d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1
+ FILENAME_BYTELEN(buf + 9*4) + FILENAME_CHARSIZE);
- d->info.mode = get_int32(buf + 0 * 4);
- d->info.uid = get_int32(buf + 1 * 4);
- d->info.gid = get_int32(buf + 2 * 4);
- d->info.accessTime = (time_t)((Sint64)get_int64(buf + 3 * 4));
- d->info.modifyTime = (time_t)((Sint64)get_int64(buf + 5 * 4));
- d->info.cTime = (time_t)((Sint64)get_int64(buf + 7 * 4));
+ d->info.mode = get_int32(buf + 0 * 4);
+ d->info.uid = get_int32(buf + 1 * 4);
+ d->info.gid = get_int32(buf + 2 * 4);
+ d->info.accessTime = get_int64(buf + 3 * 4);
+ d->info.modifyTime = get_int64(buf + 5 * 4);
+ d->info.cTime = get_int64(buf + 7 * 4);
FILENAME_COPY(d->b, buf + 9*4);
#ifdef USE_VM_PROBES
diff --git a/erts/emulator/drivers/common/erl_efile.h b/erts/emulator/drivers/common/erl_efile.h
index be5a891486..b7f063b4f2 100644
--- a/erts/emulator/drivers/common/erl_efile.h
+++ b/erts/emulator/drivers/common/erl_efile.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
@@ -105,9 +105,9 @@ typedef struct _Efile_info {
Uint32 inode; /* Inode number. */
Uint32 uid; /* User id of owner. */
Uint32 gid; /* Group id of owner. */
- time_t accessTime; /* Last time the file was accessed. */
- time_t modifyTime; /* Last time the file was modified. */
- time_t cTime; /* Creation time (Windows) or last
+ Sint64 accessTime; /* Last time the file was accessed. */
+ Sint64 modifyTime; /* Last time the file was modified. */
+ Sint64 cTime; /* Creation time (Windows) or last
* inode change (Unix).
*/
} Efile_info;
diff --git a/erts/emulator/drivers/common/gzio.h b/erts/emulator/drivers/common/gzio.h
index a6fe2fb6f5..ee0ebe7bd8 100644
--- a/erts/emulator/drivers/common/gzio.h
+++ b/erts/emulator/drivers/common/gzio.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/drivers/common/gzio_zutil.h b/erts/emulator/drivers/common/gzio_zutil.h
index 9eefb86637..b229ae4efd 100644
--- a/erts/emulator/drivers/common/gzio_zutil.h
+++ b/erts/emulator/drivers/common/gzio_zutil.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009. All Rights Reserved.
+ * Copyright Ericsson AB 2009-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.
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index b219669ce5..e87d141ddb 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2015. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/drivers/common/ram_file_drv.c b/erts/emulator/drivers/common/ram_file_drv.c
index 9cb44d0b7e..bcdfe6a186 100644
--- a/erts/emulator/drivers/common/ram_file_drv.c
+++ b/erts/emulator/drivers/common/ram_file_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2011. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/drivers/common/zlib_drv.c b/erts/emulator/drivers/common/zlib_drv.c
index 364048174c..440ba956d8 100644
--- a/erts/emulator/drivers/common/zlib_drv.c
+++ b/erts/emulator/drivers/common/zlib_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/drivers/unix/bin_drv.c b/erts/emulator/drivers/unix/bin_drv.c
index 21fb398907..4b633bb0cf 100644
--- a/erts/emulator/drivers/unix/bin_drv.c
+++ b/erts/emulator/drivers/unix/bin_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/drivers/unix/multi_drv.c b/erts/emulator/drivers/unix/multi_drv.c
index 7f8c2d9a0d..eddc57d4d4 100644
--- a/erts/emulator/drivers/unix/multi_drv.c
+++ b/erts/emulator/drivers/unix/multi_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/drivers/unix/sig_drv.c b/erts/emulator/drivers/unix/sig_drv.c
index e6f2ecc494..68ad6b9156 100644
--- a/erts/emulator/drivers/unix/sig_drv.c
+++ b/erts/emulator/drivers/unix/sig_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c
index abfc52d3bc..e425b99f16 100644
--- a/erts/emulator/drivers/unix/ttsl_drv.c
+++ b/erts/emulator/drivers/unix/ttsl_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -264,14 +264,12 @@ static int ttysl_init(void)
DEBUGLOG(("ttysl_init: Debuglog = %s(0x%ld)\n",dl,(long) debuglog));
}
#endif
- DEBUGLOG(("ttysl_init: ttysl_port = %d\n", ttysl_port));
return 0;
}
static ErlDrvData ttysl_start(ErlDrvPort port, char* buf)
{
#ifndef HAVE_TERMCAP
- DEBUGLOG(("ttysl_start: failure - no TERMCAP configured!\n"));
return ERL_DRV_ERROR_GENERAL;
#else
char *s, *t, *l;
@@ -825,12 +823,13 @@ static void ttysl_to_tty(ErlDrvData ttysl_data, ErlDrvEvent fd) {
if (sz == 0) {
driver_select(ttysl_port,(ErlDrvEvent)(long)ttysl_fd,
ERL_DRV_WRITE,0);
- if (ttysl_terminate)
+ if (ttysl_terminate) {
/* flush has been called, which means we should terminate
when queue is empty. This will not send any exit
message */
DEBUGLOG(("ttysl_to_tty: ttysl_terminate normal\n"));
driver_failure_atom(ttysl_port, "normal");
+ }
break;
}
}
diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c
index ac9b681d03..bfe0807df8 100644
--- a/erts/emulator/drivers/unix/unix_efile.c
+++ b/erts/emulator/drivers/unix/unix_efile.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
@@ -537,9 +537,9 @@ efile_fileinfo(Efile_error* errInfo, Efile_info* pInfo,
else
pInfo->type = FT_OTHER;
- pInfo->accessTime = statbuf.st_atime;
- pInfo->modifyTime = statbuf.st_mtime;
- pInfo->cTime = statbuf.st_ctime;
+ pInfo->accessTime = (Sint64)statbuf.st_atime;
+ pInfo->modifyTime = (Sint64)statbuf.st_mtime;
+ pInfo->cTime = (Sint64)statbuf.st_ctime;
pInfo->mode = statbuf.st_mode;
pInfo->links = statbuf.st_nlink;
@@ -578,8 +578,8 @@ efile_write_info(Efile_error *errInfo, Efile_info *pInfo, char *name)
}
}
- tval.actime = pInfo->accessTime;
- tval.modtime = pInfo->modifyTime;
+ tval.actime = (time_t)pInfo->accessTime;
+ tval.modtime = (time_t)pInfo->modifyTime;
return check_error(utime(name, &tval), errInfo);
}
@@ -638,12 +638,21 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */
do {
w = writev(fd, &iov[cnt], b);
} while (w < 0 && errno == EINTR);
+ if (w < 0 && errno == EINVAL) {
+ goto single_write;
+ }
} else
+ single_write:
/* Degenerated io vector - use regular write */
#endif
{
do {
- w = write(fd, iov[cnt].iov_base, iov[cnt].iov_len);
+ size_t iov_len = iov[cnt].iov_len;
+ size_t limit = 1024*1024*1024; /* 1GB */
+ if (iov_len > limit) {
+ iov_len = limit;
+ }
+ w = write(fd, iov[cnt].iov_base, iov_len);
} while (w < 0 && errno == EINTR);
ASSERT(w <= iov[cnt].iov_len ||
(w == -1 && errno != EINTR));
diff --git a/erts/emulator/drivers/vxworks/vxworks_resolv.c b/erts/emulator/drivers/vxworks/vxworks_resolv.c
index a7de53c692..c2cdf4a90b 100644
--- a/erts/emulator/drivers/vxworks/vxworks_resolv.c
+++ b/erts/emulator/drivers/vxworks/vxworks_resolv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/drivers/win32/registry_drv.c b/erts/emulator/drivers/win32/registry_drv.c
index 4e396aa8d9..a03a030df8 100644
--- a/erts/emulator/drivers/win32/registry_drv.c
+++ b/erts/emulator/drivers/win32/registry_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/drivers/win32/ttsl_drv.c b/erts/emulator/drivers/win32/ttsl_drv.c
index 4bd766a8a8..99e7fb25a4 100644
--- a/erts/emulator/drivers/win32/ttsl_drv.c
+++ b/erts/emulator/drivers/win32/ttsl_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/drivers/win32/win_con.c b/erts/emulator/drivers/win32/win_con.c
index 7fe708dc7b..0bcccfe405 100644
--- a/erts/emulator/drivers/win32/win_con.c
+++ b/erts/emulator/drivers/win32/win_con.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2012. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/drivers/win32/win_con.h b/erts/emulator/drivers/win32/win_con.h
index 3f4e89a195..7a642cd7ed 100644
--- a/erts/emulator/drivers/win32/win_con.h
+++ b/erts/emulator/drivers/win32/win_con.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2007-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2007-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.
diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c
index d95f29f49d..2d366b5833 100644
--- a/erts/emulator/drivers/win32/win_efile.c
+++ b/erts/emulator/drivers/win32/win_efile.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/hipe/TODO b/erts/emulator/hipe/TODO
index dd9760ea1c..0c28616a30 100644
--- a/erts/emulator/hipe/TODO
+++ b/erts/emulator/hipe/TODO
@@ -1,7 +1,7 @@
%CopyrightBegin%
- Copyright Ericsson AB 2004-2009. All Rights Reserved.
+ Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/elf64ppc.x b/erts/emulator/hipe/elf64ppc.x
index 3cd4010cb3..46d2632970 100644
--- a/erts/emulator/hipe/elf64ppc.x
+++ b/erts/emulator/hipe/elf64ppc.x
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/hipe/hipe_amd64.c b/erts/emulator/hipe/hipe_amd64.c
index 1bb336637d..62739d2a78 100644
--- a/erts/emulator/hipe/hipe_amd64.c
+++ b/erts/emulator/hipe/hipe_amd64.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
@@ -83,21 +83,6 @@ int hipe_patch_call(void *callAddress, void *destAddress, void *trampoline)
return 0;
}
-/*
- * Memory allocator for executable code.
- *
- * This is required on AMD64 because some Linux kernels
- * (including 2.6.10-rc1 and newer www.kernel.org ones)
- * default to non-executable memory mappings, causing
- * ordinary malloc() memory to be non-executable.
- *
- * Implementing this properly also allows us to ensure that
- * executable code ends up in the low 2GB of the address space,
- * as required by HiPE/AMD64's small code model.
- */
-static unsigned int code_bytes;
-static char *code_next;
-
#if 0 /* change to non-zero to get allocation statistics at exit() */
static unsigned int total_mapped, nr_joins, nr_splits, total_alloc, nr_allocs, nr_large, total_lost;
static unsigned int atexit_done;
@@ -121,101 +106,20 @@ static void atexit_alloc_code_stats(void)
#define ALLOC_CODE_STATS(X) do{}while(0)
#endif
-/* FreeBSD 6.1 breakage */
-#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
-#define MAP_ANONYMOUS MAP_ANON
-#endif
-
-static int morecore(unsigned int alloc_bytes)
-{
- unsigned int map_bytes;
- char *map_hint, *map_start;
-
- /* Page-align the amount to allocate. */
- map_bytes = (alloc_bytes + 4095) & ~4095;
-
- /* Round up small allocations. */
- if (map_bytes < 1024*1024)
- map_bytes = 1024*1024;
- else
- ALLOC_CODE_STATS(++nr_large);
-
- /* Create a new memory mapping, ensuring it is executable
- and in the low 2GB of the address space. Also attempt
- to make it adjacent to the previous mapping. */
- map_hint = code_next + code_bytes;
-#if !defined(MAP_32BIT)
- /* FreeBSD doesn't have MAP_32BIT, and it doesn't respect
- a plain map_hint (returns high mappings even though the
- hint refers to a free area), so we have to use both map_hint
- and MAP_FIXED to get addresses below the 2GB boundary.
- This is even worse than the Linux/ppc64 case.
- Similarly, Solaris 10 doesn't have MAP_32BIT,
- and it doesn't respect a plain map_hint. */
- if (!map_hint) /* first call */
- map_hint = (char*)(512*1024*1024); /* 0.5GB */
-#endif
- if ((unsigned long)map_hint & 4095)
- abort();
- map_start = mmap(map_hint, map_bytes,
- PROT_EXEC|PROT_READ|PROT_WRITE,
- MAP_PRIVATE|MAP_ANONYMOUS
-#if defined(MAP_32BIT)
- |MAP_32BIT
-#elif defined(__FreeBSD__) || defined(__sun__)
- |MAP_FIXED
-#endif
- ,
- -1, 0);
- ALLOC_CODE_STATS(fprintf(stderr, "%s: mmap(%p,%u,...) == %p\r\n", __FUNCTION__, map_hint, map_bytes, map_start));
-#if !defined(MAP_32BIT)
- if (map_start != MAP_FAILED &&
- (((unsigned long)map_start + (map_bytes-1)) & ~0x7FFFFFFFUL)) {
- fprintf(stderr, "mmap with hint %p returned code memory %p\r\n", map_hint, map_start);
- abort();
- }
-#endif
- if (map_start == MAP_FAILED)
- return -1;
-
- ALLOC_CODE_STATS(total_mapped += map_bytes);
-
- /* Merge adjacent mappings, so the trailing portion of the previous
- mapping isn't lost. In practice this is quite successful. */
- if (map_start == map_hint) {
- ALLOC_CODE_STATS(++nr_joins);
- code_bytes += map_bytes;
-#if !defined(MAP_32BIT)
- if (!code_next) /* first call */
- code_next = map_start;
-#endif
- } else {
- ALLOC_CODE_STATS(++nr_splits);
- ALLOC_CODE_STATS(total_lost += code_bytes);
- code_next = map_start;
- code_bytes = map_bytes;
- }
-
- ALLOC_CODE_STATS(atexit_alloc_code_stats());
-
- return 0;
-}
-
+/*
+ * Memory allocator for executable code.
+ *
+ * We use a dedicated allocator for executable code (from OTP 19.0)
+ * to make sure the memory we get is executable (PROT_EXEC)
+ * and to ensure that executable code ends up in the low 2GB
+ * of the address space, as required by HiPE/AMD64's small code model.
+ */
static void *alloc_code(unsigned int alloc_bytes)
{
- void *res;
-
- /* Align function entries. */
- alloc_bytes = (alloc_bytes + 3) & ~3;
-
- if (code_bytes < alloc_bytes && morecore(alloc_bytes) != 0)
- return NULL;
ALLOC_CODE_STATS(++nr_allocs);
ALLOC_CODE_STATS(total_alloc += alloc_bytes);
- res = code_next;
- code_next += alloc_bytes;
- code_bytes -= alloc_bytes;
- return res;
+
+ return erts_alloc(ERTS_ALC_T_HIPE_EXEC, alloc_bytes);
}
void *hipe_alloc_code(Uint nrbytes, Eterm callees, Eterm *trampolines, Process *p)
diff --git a/erts/emulator/hipe/hipe_amd64.h b/erts/emulator/hipe/hipe_amd64.h
index 09b55a1243..750a26fcb9 100644
--- a/erts/emulator/hipe/hipe_amd64.h
+++ b/erts/emulator/hipe/hipe_amd64.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_amd64.tab b/erts/emulator/hipe/hipe_amd64.tab
index 70287034a0..e5ff31b985 100644
--- a/erts/emulator/hipe/hipe_amd64.tab
+++ b/erts/emulator/hipe/hipe_amd64.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2011. All Rights Reserved.
+# Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_amd64_asm.m4 b/erts/emulator/hipe/hipe_amd64_asm.m4
index ecb25ec5c8..2c0fbbee2d 100644
--- a/erts/emulator/hipe/hipe_amd64_asm.m4
+++ b/erts/emulator/hipe/hipe_amd64_asm.m4
@@ -2,7 +2,7 @@ changecom(`/*', `*/')dnl
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_amd64_bifs.m4 b/erts/emulator/hipe/hipe_amd64_bifs.m4
index 602e71c195..9cf3bf74fd 100644
--- a/erts/emulator/hipe/hipe_amd64_bifs.m4
+++ b/erts/emulator/hipe/hipe_amd64_bifs.m4
@@ -2,7 +2,7 @@ changecom(`/*', `*/')dnl
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_amd64_gc.h b/erts/emulator/hipe/hipe_amd64_gc.h
index e7a156c910..6b95d54904 100644
--- a/erts/emulator/hipe/hipe_amd64_gc.h
+++ b/erts/emulator/hipe/hipe_amd64_gc.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_amd64_glue.S b/erts/emulator/hipe/hipe_amd64_glue.S
index 6fb93bce53..b37ed3c68a 100644
--- a/erts/emulator/hipe/hipe_amd64_glue.S
+++ b/erts/emulator/hipe/hipe_amd64_glue.S
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_amd64_glue.h b/erts/emulator/hipe/hipe_amd64_glue.h
index e54b8b3a3f..089658f4b5 100644
--- a/erts/emulator/hipe/hipe_amd64_glue.h
+++ b/erts/emulator/hipe/hipe_amd64_glue.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_amd64_primops.h b/erts/emulator/hipe/hipe_amd64_primops.h
index 23d8202e46..94c39a9433 100644
--- a/erts/emulator/hipe/hipe_amd64_primops.h
+++ b/erts/emulator/hipe/hipe_amd64_primops.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/hipe/hipe_arch.h b/erts/emulator/hipe/hipe_arch.h
index 21dabc7cb6..6f959815bb 100644
--- a/erts/emulator/hipe/hipe_arch.h
+++ b/erts/emulator/hipe/hipe_arch.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/hipe/hipe_arm.c b/erts/emulator/hipe/hipe_arm.c
index 01512e9aa1..f8ef468341 100644
--- a/erts/emulator/hipe/hipe_arm.c
+++ b/erts/emulator/hipe/hipe_arm.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/hipe/hipe_arm.h b/erts/emulator/hipe/hipe_arm.h
index a0e07cd6ce..b5fe6317c9 100644
--- a/erts/emulator/hipe/hipe_arm.h
+++ b/erts/emulator/hipe/hipe_arm.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/hipe/hipe_arm.tab b/erts/emulator/hipe/hipe_arm.tab
index bcac2cd79d..152319edbd 100644
--- a/erts/emulator/hipe/hipe_arm.tab
+++ b/erts/emulator/hipe/hipe_arm.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2005-2011. All Rights Reserved.
+# Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/hipe/hipe_arm_asm.m4 b/erts/emulator/hipe/hipe_arm_asm.m4
index 8ce8600f97..ae9ec752bb 100644
--- a/erts/emulator/hipe/hipe_arm_asm.m4
+++ b/erts/emulator/hipe/hipe_arm_asm.m4
@@ -2,7 +2,7 @@ changecom(`/*', `*/')dnl
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/hipe/hipe_arm_bifs.m4 b/erts/emulator/hipe/hipe_arm_bifs.m4
index 3efe961964..d9c9952dbf 100644
--- a/erts/emulator/hipe/hipe_arm_bifs.m4
+++ b/erts/emulator/hipe/hipe_arm_bifs.m4
@@ -2,7 +2,7 @@ changecom(`/*', `*/')dnl
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/hipe/hipe_arm_gc.h b/erts/emulator/hipe/hipe_arm_gc.h
index dfffd6c630..e8eb900978 100644
--- a/erts/emulator/hipe/hipe_arm_gc.h
+++ b/erts/emulator/hipe/hipe_arm_gc.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/hipe/hipe_arm_glue.S b/erts/emulator/hipe/hipe_arm_glue.S
index e4ce9b75ef..49ffa8b1d8 100644
--- a/erts/emulator/hipe/hipe_arm_glue.S
+++ b/erts/emulator/hipe/hipe_arm_glue.S
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/hipe/hipe_arm_glue.h b/erts/emulator/hipe/hipe_arm_glue.h
index 39bc27ec5f..dffc5aef03 100644
--- a/erts/emulator/hipe/hipe_arm_glue.h
+++ b/erts/emulator/hipe/hipe_arm_glue.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/hipe/hipe_arm_primops.h b/erts/emulator/hipe/hipe_arm_primops.h
index 0e8f84dfb9..c080b67699 100644
--- a/erts/emulator/hipe/hipe_arm_primops.h
+++ b/erts/emulator/hipe/hipe_arm_primops.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c
index 70354aa9af..4063cbf306 100644
--- a/erts/emulator/hipe/hipe_bif0.c
+++ b/erts/emulator/hipe/hipe_bif0.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
@@ -533,13 +533,13 @@ BIF_RETTYPE hipe_bifs_merge_term_1(BIF_ALIST_1)
BIF_RET(val);
}
-struct mfa {
+struct mfa_t {
Eterm mod;
Eterm fun;
Uint ari;
};
-static int term_to_mfa(Eterm term, struct mfa *mfa)
+static int term_to_mfa(Eterm term, struct mfa_t *mfa)
{
Eterm mod, fun, a;
Uint ari;
@@ -597,7 +597,7 @@ static Uint *hipe_find_emu_address(Eterm mod, Eterm name, unsigned int arity)
Uint *hipe_bifs_find_pc_from_mfa(Eterm term)
{
- struct mfa mfa;
+ struct mfa_t mfa;
if (!term_to_mfa(term, &mfa))
return NULL;
@@ -617,7 +617,7 @@ BIF_RETTYPE hipe_bifs_set_native_address_3(BIF_ALIST_3)
Eterm *pc;
void *address;
int is_closure;
- struct mfa mfa;
+ struct mfa_t mfa;
switch (BIF_ARG_3) {
case am_false:
@@ -1225,7 +1225,7 @@ void hipe_mfa_set_trampoline(Eterm m, Eterm f, unsigned int arity, void *trampol
BIF_RETTYPE hipe_bifs_set_funinfo_native_address_3(BIF_ALIST_3)
{
- struct mfa mfa;
+ struct mfa_t mfa;
void *address;
int is_exported;
@@ -1247,7 +1247,7 @@ BIF_RETTYPE hipe_bifs_set_funinfo_native_address_3(BIF_ALIST_3)
BIF_RETTYPE hipe_bifs_invalidate_funinfo_native_addresses_1(BIF_ALIST_1)
{
Eterm lst;
- struct mfa mfa;
+ struct mfa_t mfa;
struct hipe_mfa_info *p;
hipe_mfa_info_table_rwlock();
@@ -1416,7 +1416,7 @@ BIF_RETTYPE hipe_find_na_or_make_stub(BIF_ALIST_3)
BIF_RETTYPE hipe_bifs_find_na_or_make_stub_2(BIF_ALIST_2)
{
- struct mfa mfa;
+ struct mfa_t mfa;
void *address;
int is_remote;
@@ -1518,9 +1518,9 @@ struct ref {
*/
BIF_RETTYPE hipe_bifs_add_ref_2(BIF_ALIST_2)
{
- struct mfa callee;
+ struct mfa_t callee;
Eterm *tuple;
- struct mfa caller;
+ struct mfa_t caller;
void *address;
void *trampoline;
unsigned int flags;
@@ -1597,7 +1597,7 @@ BIF_RETTYPE hipe_bifs_add_ref_2(BIF_ALIST_2)
*/
BIF_RETTYPE hipe_bifs_mark_referred_from_1(BIF_ALIST_1) /* get_refs_from */
{
- struct mfa mfa;
+ struct mfa_t mfa;
const struct hipe_mfa_info *p;
struct ref *ref;
@@ -1649,7 +1649,7 @@ static void hipe_purge_all_refs(void)
BIF_RETTYPE hipe_bifs_remove_refs_from_1(BIF_ALIST_1)
{
- struct mfa mfa;
+ struct mfa_t mfa;
struct hipe_mfa_info *caller_mfa, *callee_mfa;
struct hipe_mfa_info_list *refers_to, *tmp_refers_to;
struct ref **prev, *ref;
@@ -1703,7 +1703,7 @@ BIF_RETTYPE hipe_bifs_remove_refs_from_1(BIF_ALIST_1)
*/
BIF_RETTYPE hipe_bifs_redirect_referred_from_1(BIF_ALIST_1)
{
- struct mfa mfa;
+ struct mfa_t mfa;
struct hipe_mfa_info *p;
struct ref **prev, *ref;
int is_remote, res;
diff --git a/erts/emulator/hipe/hipe_bif0.h b/erts/emulator/hipe/hipe_bif0.h
index 5527c6c3ed..c9a8216368 100644
--- a/erts/emulator/hipe/hipe_bif0.h
+++ b/erts/emulator/hipe/hipe_bif0.h
@@ -2,7 +2,7 @@
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_bif0.tab b/erts/emulator/hipe/hipe_bif0.tab
index 5ce254314a..99237aae05 100644
--- a/erts/emulator/hipe/hipe_bif0.tab
+++ b/erts/emulator/hipe/hipe_bif0.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2001-2011. All Rights Reserved.
+# Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_bif1.c b/erts/emulator/hipe/hipe_bif1.c
index a2682992a4..08adbd474e 100644
--- a/erts/emulator/hipe/hipe_bif1.c
+++ b/erts/emulator/hipe/hipe_bif1.c
@@ -2,7 +2,7 @@
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_bif1.h b/erts/emulator/hipe/hipe_bif1.h
index 80cdeb4a82..e12bb1a1f3 100644
--- a/erts/emulator/hipe/hipe_bif1.h
+++ b/erts/emulator/hipe/hipe_bif1.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_bif1.tab b/erts/emulator/hipe/hipe_bif1.tab
index 6c4e05afdb..c5b452f199 100644
--- a/erts/emulator/hipe/hipe_bif1.tab
+++ b/erts/emulator/hipe/hipe_bif1.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+# Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_bif2.c b/erts/emulator/hipe/hipe_bif2.c
index 2328e69886..dfd34e31d4 100644
--- a/erts/emulator/hipe/hipe_bif2.c
+++ b/erts/emulator/hipe/hipe_bif2.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_bif2.tab b/erts/emulator/hipe/hipe_bif2.tab
index a29e1fbdbb..bbcb577be0 100644
--- a/erts/emulator/hipe/hipe_bif2.tab
+++ b/erts/emulator/hipe/hipe_bif2.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2001-2012. All Rights Reserved.
+# Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_bif64.c b/erts/emulator/hipe/hipe_bif64.c
index b97cf2b7ee..a1a3c81bfe 100644
--- a/erts/emulator/hipe/hipe_bif64.c
+++ b/erts/emulator/hipe/hipe_bif64.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_bif64.h b/erts/emulator/hipe/hipe_bif64.h
index 856b4003dc..a97ce311d3 100644
--- a/erts/emulator/hipe/hipe_bif64.h
+++ b/erts/emulator/hipe/hipe_bif64.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_bif64.tab b/erts/emulator/hipe/hipe_bif64.tab
index 3062ab5848..eefca379a0 100644
--- a/erts/emulator/hipe/hipe_bif64.tab
+++ b/erts/emulator/hipe/hipe_bif64.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2011. All Rights Reserved.
+# Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_bif_list.m4 b/erts/emulator/hipe/hipe_bif_list.m4
index 7240280345..29095a5389 100644
--- a/erts/emulator/hipe/hipe_bif_list.m4
+++ b/erts/emulator/hipe/hipe_bif_list.m4
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_debug.c b/erts/emulator/hipe/hipe_debug.c
index a48578c468..ace489452f 100644
--- a/erts/emulator/hipe/hipe_debug.c
+++ b/erts/emulator/hipe/hipe_debug.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
@@ -195,7 +195,7 @@ void hipe_print_pcb(Process *p)
U("rcount ", rcount);
U("id ", common.id);
U("reds ", reds);
- U("tracer_pr..", common.tracer_proc);
+ U("tracer ", common.tracer);
U("trace_fla..", common.trace_flags);
U("group_lea..", group_leader);
U("flags ", flags);
diff --git a/erts/emulator/hipe/hipe_debug.h b/erts/emulator/hipe/hipe_debug.h
index bf10d5a2a8..c510eac949 100644
--- a/erts/emulator/hipe/hipe_debug.h
+++ b/erts/emulator/hipe/hipe_debug.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_gbif_list.h b/erts/emulator/hipe/hipe_gbif_list.h
index dc93741a1d..424b001298 100644
--- a/erts/emulator/hipe/hipe_gbif_list.h
+++ b/erts/emulator/hipe/hipe_gbif_list.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_gc.c b/erts/emulator/hipe/hipe_gc.c
index 2e19bf88bf..d0619a0609 100644
--- a/erts/emulator/hipe/hipe_gc.c
+++ b/erts/emulator/hipe/hipe_gc.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_gc.h b/erts/emulator/hipe/hipe_gc.h
index e373324cdd..5b5eb29175 100644
--- a/erts/emulator/hipe/hipe_gc.h
+++ b/erts/emulator/hipe/hipe_gc.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_mkliterals.c b/erts/emulator/hipe/hipe_mkliterals.c
index dfa5313739..0d3493ec6c 100644
--- a/erts/emulator/hipe/hipe_mkliterals.c
+++ b/erts/emulator/hipe/hipe_mkliterals.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_mode_switch.c b/erts/emulator/hipe/hipe_mode_switch.c
index 804c458b6c..9ad44b25ac 100644
--- a/erts/emulator/hipe/hipe_mode_switch.c
+++ b/erts/emulator/hipe/hipe_mode_switch.c
@@ -2,7 +2,7 @@
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
@@ -218,15 +218,37 @@ static __inline__ void hipe_pop_beam_trap_frame(Process *p)
Process *hipe_mode_switch(Process *p, unsigned cmd, Eterm reg[])
{
unsigned result;
-#if NR_ARG_REGS > 5
- /* When NR_ARG_REGS > 5, we need to protect the process' input
- reduction count (which BEAM stores in def_arg_reg[5]) from
- being clobbered by the arch glue code. */
Eterm reds_in = p->def_arg_reg[5];
-#endif
-#if NR_ARG_REGS > 4
- Eterm o_reds = p->def_arg_reg[4];
-#endif
+ /*
+ * Process is in the normal case scheduled out when reduction
+ * count reach zero. When "save calls" is enabled reduction
+ * count is subtracted with CONTEXT_REDS, i.e. initial reduction
+ * count will be zero or less and process is scheduled out
+ * when -CONTEXT_REDS is reached.
+ *
+ * HiPE does not support the "save calls" feature, so we switch
+ * to using a positive reduction counter when executing in
+ * hipe mode, but need to restore the "save calls" when
+ * returning to beam. We also need to hide the save calls buffer
+ * from BIFs. We do that by moving the saved calls buf to
+ * suspended saved calls buf.
+ *
+ * Beam has initial reduction count in stored in p->def_arg_reg[5].
+ *
+ * Beam expects -neg_o_reds to be found in p->def_arg_reg[4]
+ * on return to beam.
+ */
+
+ {
+ struct saved_calls *scb = ERTS_PROC_SET_SAVED_CALLS_BUF(p, NULL);
+ if (scb) {
+ reds_in += CONTEXT_REDS;
+ p->fcalls += CONTEXT_REDS;
+ ERTS_PROC_SET_SUSPENDED_SAVED_CALLS_BUF(p, scb);
+ }
+ }
+
+ p->flags |= F_HIPE_MODE; /* inform bifs where we are comming from... */
p->i = NULL;
/* Set current_function to undefined. stdlib hibernate tests rely on it. */
@@ -481,12 +503,21 @@ Process *hipe_mode_switch(Process *p, unsigned cmd, Eterm reg[])
erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_MSG_RECEIVE);
do_schedule:
{
-#if !(NR_ARG_REGS > 5)
- int reds_in = p->def_arg_reg[5];
+ struct saved_calls *scb;
+
+ scb = ERTS_PROC_SET_SUSPENDED_SAVED_CALLS_BUF(p, NULL);
+ if (scb)
+ ERTS_PROC_SET_SAVED_CALLS_BUF(p, scb);
+
+#ifdef DEBUG
+ ASSERT(p->debug_reds_in == reds_in);
#endif
+ p->flags &= ~F_HIPE_MODE;
+
ERTS_SMP_UNREQ_PROC_MAIN_LOCK(p);
p = schedule(p, reds_in - p->fcalls);
ERTS_SMP_REQ_PROC_MAIN_LOCK(p);
+ ASSERT(!(p->flags & F_HIPE_MODE));
#ifdef ERTS_SMP
p->hipe_smp.have_receive_locks = 0;
reg = p->scheduler_data->x_reg_array;
@@ -501,28 +532,32 @@ Process *hipe_mode_switch(Process *p, unsigned cmd, Eterm reg[])
reg[i] = argp[i];
}
{
-#if !(NR_ARG_REGS > 5)
- Eterm reds_in;
-#endif
-#if !(NR_ARG_REGS > 4)
- Eterm o_reds;
-#endif
+ struct saved_calls *scb;
reds_in = p->fcalls;
- o_reds = 0;
- if (ERTS_PROC_GET_SAVED_CALLS_BUF(p)) {
- o_reds = reds_in;
- reds_in = 0;
- p->fcalls = 0;
- }
- p->def_arg_reg[4] = o_reds;
p->def_arg_reg[5] = reds_in;
+#ifdef DEBUG
+ p->debug_reds_in = reds_in;
+#endif
if (p->i == hipe_beam_pc_resume) {
+ p->flags |= F_HIPE_MODE; /* inform bifs where we are comming from... */
+ scb = ERTS_PROC_SET_SAVED_CALLS_BUF(p, NULL);
+ if (scb)
+ ERTS_PROC_SET_SUSPENDED_SAVED_CALLS_BUF(p, scb);
p->i = NULL;
p->arity = 0;
goto do_resume;
}
+
+ scb = ERTS_PROC_GET_SAVED_CALLS_BUF(p);
+ if (!scb)
+ p->def_arg_reg[4] = 0;
+ else {
+ p->def_arg_reg[4] = CONTEXT_REDS;
+ p->fcalls = -CONTEXT_REDS + reds_in;
+ }
}
+
HIPE_CHECK_PCB(p);
result = HIPE_MODE_SWITCH_RES_CALL_BEAM;
p->def_arg_reg[3] = result;
@@ -562,14 +597,29 @@ Process *hipe_mode_switch(Process *p, unsigned cmd, Eterm reg[])
default:
erts_exit(ERTS_ERROR_EXIT, "hipe_mode_switch: result %#x\r\n", result);
}
+
+ {
+ struct saved_calls *scb = ERTS_PROC_SET_SUSPENDED_SAVED_CALLS_BUF(p, NULL);
+ if (!scb)
+ p->def_arg_reg[4] = 0;
+ else {
+ p->def_arg_reg[4] = CONTEXT_REDS;
+ p->fcalls -= CONTEXT_REDS;
+ ERTS_PROC_SET_SAVED_CALLS_BUF(p, scb);
+ }
+ }
+
HIPE_CHECK_PCB(p);
p->def_arg_reg[3] = result;
-#if NR_ARG_REGS > 4
- p->def_arg_reg[4] = o_reds;
-#endif
#if NR_ARG_REGS > 5
+ /*
+ * When NR_ARG_REGS > 5, we need to protect the process' input
+ * reduction count (which BEAM stores in def_arg_reg[5]) from
+ * being clobbered by the arch glue code.
+ */
p->def_arg_reg[5] = reds_in;
#endif
+ p->flags &= ~F_HIPE_MODE;
return p;
}
diff --git a/erts/emulator/hipe/hipe_mode_switch.h b/erts/emulator/hipe/hipe_mode_switch.h
index 620cc6356b..c40077d558 100644
--- a/erts/emulator/hipe/hipe_mode_switch.h
+++ b/erts/emulator/hipe/hipe_mode_switch.h
@@ -2,7 +2,7 @@
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_native_bif.c b/erts/emulator/hipe/hipe_native_bif.c
index 0ec417999b..9c03b3811c 100644
--- a/erts/emulator/hipe/hipe_native_bif.c
+++ b/erts/emulator/hipe/hipe_native_bif.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
@@ -601,7 +601,7 @@ void hipe_clear_timeout(Process *c_p)
}
#endif
if (IS_TRACED_FL(c_p, F_TRACE_RECEIVE)) {
- trace_receive(c_p, am_timeout);
+ trace_receive(c_p, am_clock_service, am_timeout, NULL);
}
c_p->flags &= ~F_TIMO;
JOIN_MESSAGE(c_p);
diff --git a/erts/emulator/hipe/hipe_native_bif.h b/erts/emulator/hipe/hipe_native_bif.h
index 55a0d3bb1b..a02d26087b 100644
--- a/erts/emulator/hipe/hipe_native_bif.h
+++ b/erts/emulator/hipe/hipe_native_bif.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_ops.tab b/erts/emulator/hipe/hipe_ops.tab
index d021c72ac9..96e4c0da91 100644
--- a/erts/emulator/hipe/hipe_ops.tab
+++ b/erts/emulator/hipe/hipe_ops.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2001-2011. All Rights Reserved.
+# Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_ppc.c b/erts/emulator/hipe/hipe_ppc.c
index 3f86de626d..9b2048c457 100644
--- a/erts/emulator/hipe/hipe_ppc.c
+++ b/erts/emulator/hipe/hipe_ppc.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_ppc.h b/erts/emulator/hipe/hipe_ppc.h
index 777c9384d5..e86c122fb1 100644
--- a/erts/emulator/hipe/hipe_ppc.h
+++ b/erts/emulator/hipe/hipe_ppc.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_ppc.tab b/erts/emulator/hipe/hipe_ppc.tab
index 5bf2320cbe..274612d9ce 100644
--- a/erts/emulator/hipe/hipe_ppc.tab
+++ b/erts/emulator/hipe/hipe_ppc.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2011. All Rights Reserved.
+# Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_ppc64.tab b/erts/emulator/hipe/hipe_ppc64.tab
index 301a9752f7..a291185b57 100644
--- a/erts/emulator/hipe/hipe_ppc64.tab
+++ b/erts/emulator/hipe/hipe_ppc64.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2005-2011. All Rights Reserved.
+# Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/hipe/hipe_ppc_asm.m4 b/erts/emulator/hipe/hipe_ppc_asm.m4
index ea74923d1f..be25d65725 100644
--- a/erts/emulator/hipe/hipe_ppc_asm.m4
+++ b/erts/emulator/hipe/hipe_ppc_asm.m4
@@ -2,7 +2,7 @@ changecom(`/*', `*/')dnl
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_ppc_bifs.m4 b/erts/emulator/hipe/hipe_ppc_bifs.m4
index 28518827ec..57b4208bee 100644
--- a/erts/emulator/hipe/hipe_ppc_bifs.m4
+++ b/erts/emulator/hipe/hipe_ppc_bifs.m4
@@ -2,7 +2,7 @@ changecom(`/*', `*/')dnl
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_ppc_gc.h b/erts/emulator/hipe/hipe_ppc_gc.h
index 0854d9e950..a6ec1338ff 100644
--- a/erts/emulator/hipe/hipe_ppc_gc.h
+++ b/erts/emulator/hipe/hipe_ppc_gc.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_ppc_glue.S b/erts/emulator/hipe/hipe_ppc_glue.S
index 6e2022603c..44351dc06c 100644
--- a/erts/emulator/hipe/hipe_ppc_glue.S
+++ b/erts/emulator/hipe/hipe_ppc_glue.S
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_ppc_glue.h b/erts/emulator/hipe/hipe_ppc_glue.h
index 93ca39fcb3..2bfa10298c 100644
--- a/erts/emulator/hipe/hipe_ppc_glue.h
+++ b/erts/emulator/hipe/hipe_ppc_glue.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_ppc_primops.h b/erts/emulator/hipe/hipe_ppc_primops.h
index ce3dda9eb3..540605de9f 100644
--- a/erts/emulator/hipe/hipe_ppc_primops.h
+++ b/erts/emulator/hipe/hipe_ppc_primops.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/hipe/hipe_primops.h b/erts/emulator/hipe/hipe_primops.h
index 0bec677574..4fcbc9df38 100644
--- a/erts/emulator/hipe/hipe_primops.h
+++ b/erts/emulator/hipe/hipe_primops.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/hipe/hipe_process.h b/erts/emulator/hipe/hipe_process.h
index 60d09ea1c9..21c4239753 100644
--- a/erts/emulator/hipe/hipe_process.h
+++ b/erts/emulator/hipe/hipe_process.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_risc_gc.h b/erts/emulator/hipe/hipe_risc_gc.h
index 770ec93459..315f8e7f9f 100644
--- a/erts/emulator/hipe/hipe_risc_gc.h
+++ b/erts/emulator/hipe/hipe_risc_gc.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/emulator/hipe/hipe_risc_glue.h b/erts/emulator/hipe/hipe_risc_glue.h
index 51db7eac01..0284265307 100644
--- a/erts/emulator/hipe/hipe_risc_glue.h
+++ b/erts/emulator/hipe/hipe_risc_glue.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/emulator/hipe/hipe_risc_stack.c b/erts/emulator/hipe/hipe_risc_stack.c
index fd04421381..dc98c96b8f 100644
--- a/erts/emulator/hipe/hipe_risc_stack.c
+++ b/erts/emulator/hipe/hipe_risc_stack.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/emulator/hipe/hipe_signal.h b/erts/emulator/hipe/hipe_signal.h
index b2f461797d..5d8621135b 100644
--- a/erts/emulator/hipe/hipe_signal.h
+++ b/erts/emulator/hipe/hipe_signal.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2002-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.
diff --git a/erts/emulator/hipe/hipe_sparc.c b/erts/emulator/hipe/hipe_sparc.c
index bd95bc5d98..23020f34ee 100644
--- a/erts/emulator/hipe/hipe_sparc.c
+++ b/erts/emulator/hipe/hipe_sparc.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/hipe/hipe_sparc.h b/erts/emulator/hipe/hipe_sparc.h
index 0b74b2db26..25d513e988 100644
--- a/erts/emulator/hipe/hipe_sparc.h
+++ b/erts/emulator/hipe/hipe_sparc.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/hipe/hipe_sparc.tab b/erts/emulator/hipe/hipe_sparc.tab
index 2f528c0607..bc90d38168 100644
--- a/erts/emulator/hipe/hipe_sparc.tab
+++ b/erts/emulator/hipe/hipe_sparc.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2011. All Rights Reserved.
+# Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_sparc_asm.m4 b/erts/emulator/hipe/hipe_sparc_asm.m4
index 227a1658b4..8a9a516eab 100644
--- a/erts/emulator/hipe/hipe_sparc_asm.m4
+++ b/erts/emulator/hipe/hipe_sparc_asm.m4
@@ -2,7 +2,7 @@ changecom(`/*', `*/')dnl
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2007-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2007-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.
diff --git a/erts/emulator/hipe/hipe_sparc_bifs.m4 b/erts/emulator/hipe/hipe_sparc_bifs.m4
index a7bbe5b2cc..2e886ec1d1 100644
--- a/erts/emulator/hipe/hipe_sparc_bifs.m4
+++ b/erts/emulator/hipe/hipe_sparc_bifs.m4
@@ -2,7 +2,7 @@ changecom(`/*', `*/')dnl
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_sparc_gc.h b/erts/emulator/hipe/hipe_sparc_gc.h
index 99e55df1ce..eea0268ed5 100644
--- a/erts/emulator/hipe/hipe_sparc_gc.h
+++ b/erts/emulator/hipe/hipe_sparc_gc.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_sparc_glue.S b/erts/emulator/hipe/hipe_sparc_glue.S
index 7e47ffb52f..077db9b8ad 100644
--- a/erts/emulator/hipe/hipe_sparc_glue.S
+++ b/erts/emulator/hipe/hipe_sparc_glue.S
@@ -2,7 +2,7 @@
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_sparc_glue.h b/erts/emulator/hipe/hipe_sparc_glue.h
index 95ce1e5b4a..3a1795f408 100644
--- a/erts/emulator/hipe/hipe_sparc_glue.h
+++ b/erts/emulator/hipe/hipe_sparc_glue.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_sparc_primops.h b/erts/emulator/hipe/hipe_sparc_primops.h
index e42bcbad62..2ecfa1293e 100644
--- a/erts/emulator/hipe/hipe_sparc_primops.h
+++ b/erts/emulator/hipe/hipe_sparc_primops.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/hipe/hipe_stack.c b/erts/emulator/hipe/hipe_stack.c
index e088b45c57..e2e6eb74b1 100644
--- a/erts/emulator/hipe/hipe_stack.c
+++ b/erts/emulator/hipe/hipe_stack.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/hipe/hipe_stack.h b/erts/emulator/hipe/hipe_stack.h
index f575b97ce3..4ea7d5c031 100644
--- a/erts/emulator/hipe/hipe_stack.h
+++ b/erts/emulator/hipe/hipe_stack.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_x86.c b/erts/emulator/hipe/hipe_x86.c
index 19b70afced..3d25646231 100644
--- a/erts/emulator/hipe/hipe_x86.c
+++ b/erts/emulator/hipe/hipe_x86.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/hipe/hipe_x86.h b/erts/emulator/hipe/hipe_x86.h
index 30dc5666ae..8967793171 100644
--- a/erts/emulator/hipe/hipe_x86.h
+++ b/erts/emulator/hipe/hipe_x86.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/hipe/hipe_x86.tab b/erts/emulator/hipe/hipe_x86.tab
index 55fb03cde8..b922f05165 100644
--- a/erts/emulator/hipe/hipe_x86.tab
+++ b/erts/emulator/hipe/hipe_x86.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2011. All Rights Reserved.
+# Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_x86_abi.txt b/erts/emulator/hipe/hipe_x86_abi.txt
index b74fcef127..31a4a0e121 100644
--- a/erts/emulator/hipe/hipe_x86_abi.txt
+++ b/erts/emulator/hipe/hipe_x86_abi.txt
@@ -1,7 +1,7 @@
%CopyrightBegin%
- Copyright Ericsson AB 2001-2011. All Rights Reserved.
+ Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_x86_asm.m4 b/erts/emulator/hipe/hipe_x86_asm.m4
index 3457574622..91c60382eb 100644
--- a/erts/emulator/hipe/hipe_x86_asm.m4
+++ b/erts/emulator/hipe/hipe_x86_asm.m4
@@ -2,7 +2,7 @@ changecom(`/*', `*/')dnl
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2002-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.
diff --git a/erts/emulator/hipe/hipe_x86_bifs.m4 b/erts/emulator/hipe/hipe_x86_bifs.m4
index 0c0a8da6eb..b8ac5046d5 100644
--- a/erts/emulator/hipe/hipe_x86_bifs.m4
+++ b/erts/emulator/hipe/hipe_x86_bifs.m4
@@ -2,7 +2,7 @@ changecom(`/*', `*/')dnl
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_x86_gc.h b/erts/emulator/hipe/hipe_x86_gc.h
index a8770ef4f9..c22b28c2d5 100644
--- a/erts/emulator/hipe/hipe_x86_gc.h
+++ b/erts/emulator/hipe/hipe_x86_gc.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/hipe/hipe_x86_glue.S b/erts/emulator/hipe/hipe_x86_glue.S
index cf382c480d..8d6e377730 100644
--- a/erts/emulator/hipe/hipe_x86_glue.S
+++ b/erts/emulator/hipe/hipe_x86_glue.S
@@ -2,7 +2,7 @@
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_x86_glue.h b/erts/emulator/hipe/hipe_x86_glue.h
index 6c123e8938..818d7444e2 100644
--- a/erts/emulator/hipe/hipe_x86_glue.h
+++ b/erts/emulator/hipe/hipe_x86_glue.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_x86_primops.h b/erts/emulator/hipe/hipe_x86_primops.h
index 3e057059bc..68a284203e 100644
--- a/erts/emulator/hipe/hipe_x86_primops.h
+++ b/erts/emulator/hipe/hipe_x86_primops.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/hipe/hipe_x86_signal.c b/erts/emulator/hipe/hipe_x86_signal.c
index 0ecd13c4bc..50d08b96d3 100644
--- a/erts/emulator/hipe/hipe_x86_signal.c
+++ b/erts/emulator/hipe/hipe_x86_signal.c
@@ -2,7 +2,7 @@
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/hipe/hipe_x86_stack.c b/erts/emulator/hipe/hipe_x86_stack.c
index 6629713a05..f1559b1451 100644
--- a/erts/emulator/hipe/hipe_x86_stack.c
+++ b/erts/emulator/hipe/hipe_x86_stack.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/internal_doc/dec.erl b/erts/emulator/internal_doc/dec.erl
index e64e37a7d9..8ce83fa402 100644
--- a/erts/emulator/internal_doc/dec.erl
+++ b/erts/emulator/internal_doc/dec.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2000-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.
diff --git a/erts/emulator/internal_doc/erl_ext_dist.txt b/erts/emulator/internal_doc/erl_ext_dist.txt
index 23b7d0d8e5..0b9a783069 100644
--- a/erts/emulator/internal_doc/erl_ext_dist.txt
+++ b/erts/emulator/internal_doc/erl_ext_dist.txt
@@ -1,7 +1,7 @@
%CopyrightBegin%
- Copyright Ericsson AB 1997-2009. All Rights Reserved.
+ Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/nifs/common/erl_tracer_nif.c b/erts/emulator/nifs/common/erl_tracer_nif.c
new file mode 100644
index 0000000000..8a9a1bf16c
--- /dev/null
+++ b/erts/emulator/nifs/common/erl_tracer_nif.c
@@ -0,0 +1,257 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson 2015. 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%
+ */
+
+/*
+ * Purpose: NIF library for process/port tracer
+ *
+ */
+
+
+#define STATIC_ERLANG_NIF 1
+
+#include "erl_nif.h"
+#include "config.h"
+#include "sys.h"
+
+#ifdef VALGRIND
+# include <valgrind/memcheck.h>
+#endif
+
+/* NIF interface declarations */
+static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info);
+static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info);
+static void unload(ErlNifEnv* env, void* priv_data);
+
+/* The NIFs: */
+static ERL_NIF_TERM enabled(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+static ErlNifFunc nif_funcs[] = {
+ {"enabled", 3, enabled},
+ {"trace", 6, trace}
+};
+
+
+ERL_NIF_INIT(erl_tracer, nif_funcs, load, NULL, upgrade, unload)
+
+#define ATOMS \
+ ATOM_DECL(call); \
+ ATOM_DECL(command); \
+ ATOM_DECL(cpu_timestamp); \
+ ATOM_DECL(discard); \
+ ATOM_DECL(exception_from); \
+ ATOM_DECL(match_spec_result); \
+ ATOM_DECL(monotonic); \
+ ATOM_DECL(ok); \
+ ATOM_DECL(remove); \
+ ATOM_DECL(return_from); \
+ ATOM_DECL(scheduler_id); \
+ ATOM_DECL(send); \
+ ATOM_DECL(send_to_non_existing_process); \
+ ATOM_DECL(seq_trace); \
+ ATOM_DECL(spawn); \
+ ATOM_DECL(strict_monotonic); \
+ ATOM_DECL(timestamp); \
+ ATOM_DECL(trace); \
+ ATOM_DECL(trace_ts); \
+ ATOM_DECL(true); \
+ ATOM_DECL(gc_minor_start); \
+ ATOM_DECL(gc_minor_end); \
+ ATOM_DECL(gc_major_start); \
+ ATOM_DECL(gc_major_end); \
+ ATOM_DECL(undefined);
+
+#define ATOM_DECL(A) static ERL_NIF_TERM atom_##A
+ATOMS
+#undef ATOM_DECL
+
+static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
+{
+
+#define ATOM_DECL(A) atom_##A = enif_make_atom(env, #A)
+ATOMS
+#undef ATOM_DECL
+
+ *priv_data = NULL;
+
+ return 0;
+}
+
+static void unload(ErlNifEnv* env, void* priv_data)
+{
+
+}
+
+static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data,
+ ERL_NIF_TERM load_info)
+{
+ if (*old_priv_data != NULL) {
+ return -1; /* Don't know how to do that */
+ }
+ if (*priv_data != NULL) {
+ return -1; /* Don't know how to do that */
+ }
+ if (load(env, priv_data, load_info)) {
+ return -1;
+ }
+ return 0;
+}
+
+static ERL_NIF_TERM enabled(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifPid to_pid;
+ ErlNifPort to_port;
+ ASSERT(argc == 3);
+
+ if (enif_get_local_pid(env, argv[1], &to_pid)) {
+ if (!enif_is_process_alive(env, &to_pid))
+ /* tracer is dead so we should remove this trace point */
+ return atom_remove;
+ } else if (enif_get_local_port(env, argv[1], &to_port)) {
+ if (!enif_is_port_alive(env, &to_port))
+ /* tracer is dead so we should remove this trace point */
+ return atom_remove;
+ } else {
+ /* The state was not a pid or a port */
+ return atom_remove;
+ }
+
+ /* Only generate trace for when tracer != tracee */
+ if (enif_is_identical(argv[1], argv[2])) {
+ return atom_discard;
+ }
+
+ return atom_trace;
+}
+
+/*
+ -spec trace(seq_trace, TracerState :: pid() | port(),
+ Label :: non_neg_integer(),
+ Msg :: term(),
+ Opts :: map()) -> ignored();
+ trace(Tag :: atom(), TracerState :: pid() | port(),
+ Tracee :: pid() || port() || undefined,
+ Msg :: term(),
+ Opts :: map()) -> ignored().
+ -spec trace(Tag :: atom(), TracerState :: pid() | port(),
+ Tracee :: pid() || port() || undefined,
+ Msg :: term(),
+ Extra :: term(),
+ Opts :: map()) -> ignored().
+*/
+static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ERL_NIF_TERM value, msg, tt[8], opts;
+ ErlNifPid to_pid;
+ ErlNifPort to_port;
+ size_t tt_sz = 0;
+ int is_port = 0;
+ ASSERT(argc == 6);
+
+ if (!enif_get_local_pid(env, argv[1], &to_pid)) {
+ if (!enif_get_local_port(env, argv[1], &to_port)) {
+ /* This only fails if argv[1] is a not a local port/pid
+ which should not happen as it is checked in enabled */
+ ASSERT(0);
+ return atom_ok;
+ }
+ is_port = 1;
+ }
+
+ if (!enif_is_identical(argv[4], atom_undefined)) {
+ tt[tt_sz++] = atom_trace;
+ tt[tt_sz++] = argv[2];
+ tt[tt_sz++] = argv[0];
+ tt[tt_sz++] = argv[3];
+ tt[tt_sz++] = argv[4];
+ } else {
+ if (enif_is_identical(argv[0], atom_seq_trace)) {
+ tt[tt_sz++] = atom_seq_trace;
+ tt[tt_sz++] = argv[2];
+ tt[tt_sz++] = argv[3];
+ } else {
+ tt[tt_sz++] = atom_trace;
+ tt[tt_sz++] = argv[2];
+ tt[tt_sz++] = argv[0];
+ tt[tt_sz++] = argv[3];
+ }
+ }
+
+ opts = argv[5];
+
+ if (enif_get_map_value(env, opts, atom_match_spec_result,
+ &value)
+ && !enif_is_identical(value, atom_true)) {
+ tt[tt_sz++] = value;
+ }
+
+ if (enif_get_map_value(env, opts, atom_scheduler_id, &value)
+ && !enif_is_identical(value, atom_undefined)) {
+ tt[tt_sz++] = value;
+ }
+
+ if (enif_get_map_value(env, opts, atom_timestamp, &value)
+ && !enif_is_identical(value, atom_undefined)) {
+ ERL_NIF_TERM ts;
+ if (enif_is_identical(value, atom_monotonic)) {
+ ErlNifTime mon = enif_monotonic_time(ERL_NIF_NSEC);
+ ts = enif_make_int64(env, mon);
+ } else if (enif_is_identical(value, atom_strict_monotonic)) {
+ ErlNifTime mon = enif_monotonic_time(ERL_NIF_NSEC);
+ ERL_NIF_TERM unique = enif_make_unique_integer(
+ env, ERL_NIF_UNIQUE_MONOTONIC);
+ ts = enif_make_tuple2(env, enif_make_int64(env, mon), unique);
+ } else if (enif_is_identical(value, atom_timestamp)) {
+ ts = enif_now_time(env);
+ } else if (enif_is_identical(value, atom_cpu_timestamp)) {
+ ts = enif_cpu_time(env);
+ } else {
+ ASSERT(0);
+ goto error;
+ }
+ tt[tt_sz++] = ts;
+ if (tt[0] == atom_trace)
+ tt[0] = atom_trace_ts;
+ }
+
+ msg = enif_make_tuple_from_array(env, tt, tt_sz);
+
+ if (is_port) {
+ ErlNifBinary bin;
+
+ if (!enif_term_to_binary(env, msg, &bin))
+ goto error;
+
+ msg = enif_make_binary(env, &bin);
+
+ if (!enif_port_command(env, &to_port, NULL, msg))
+ /* port has probably died, enabled will clean up */;
+
+ enif_release_binary(&bin);
+ } else {
+
+ if (!enif_send(env, &to_pid, NULL, msg))
+ /* process has probably died, enabled will clean up */;
+ }
+
+error:
+
+ return atom_ok;
+}
diff --git a/erts/emulator/pcre/pcre.mk b/erts/emulator/pcre/pcre.mk
index b844b77214..38b91237a2 100644
--- a/erts/emulator/pcre/pcre.mk
+++ b/erts/emulator/pcre/pcre.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2012. All Rights Reserved.
+# Copyright Ericsson AB 2012-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.
diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c
index f87196d724..44a77f3ea5 100644
--- a/erts/emulator/sys/common/erl_check_io.c
+++ b/erts/emulator/sys/common/erl_check_io.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
@@ -39,6 +39,7 @@
#include "erl_check_io.h"
#include "erl_thr_progress.h"
#include "dtrace-wrapper.h"
+#include "lttng-wrapper.h"
#define ERTS_WANT_TIMER_WHEEL_API
#include "erl_time.h"
@@ -395,6 +396,7 @@ forget_removed(struct pollset_info* psi)
if (drv_ptr) {
int was_unmasked = erts_block_fpe();
DTRACE1(driver_stop_select, drv_ptr->name);
+ LTTNG1(driver_stop_select, drv_ptr->name);
(*drv_ptr->stop_select) ((ErlDrvEvent) fd, NULL);
erts_unblock_fpe(was_unmasked);
if (drv_ptr->handle) {
@@ -1055,6 +1057,7 @@ done_unknown:
if (stop_select_fn) {
int was_unmasked = erts_block_fpe();
DTRACE1(driver_stop_select, name);
+ LTTNG1(driver_stop_select, "unknown");
(*stop_select_fn)(e, NULL);
erts_unblock_fpe(was_unmasked);
}
diff --git a/erts/emulator/sys/common/erl_check_io.h b/erts/emulator/sys/common/erl_check_io.h
index c8675a7d9d..14f1ea3f43 100644
--- a/erts/emulator/sys/common/erl_check_io.h
+++ b/erts/emulator/sys/common/erl_check_io.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
diff --git a/erts/emulator/sys/common/erl_mmap.c b/erts/emulator/sys/common/erl_mmap.c
index 889d6f3868..53009a1481 100644
--- a/erts/emulator/sys/common/erl_mmap.c
+++ b/erts/emulator/sys/common/erl_mmap.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2002-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.
@@ -28,6 +28,8 @@
#include "erl_mmap.h"
#include <stddef.h>
+#if HAVE_ERTS_MMAP
+
/* #define ERTS_MMAP_OP_RINGBUF_SZ 100 */
#if defined(DEBUG) || 0
@@ -294,12 +296,13 @@ typedef struct {
}ErtsFreeSegMap;
struct ErtsMemMapper_ {
- int (*reserve_physical)(char *, UWord);
+ int (*reserve_physical)(char *, UWord, int exec);
void (*unreserve_physical)(char *, UWord);
int supercarrier;
int no_os_mmap;
+ int executable; /* is client a native code allocator? */
/*
- * Super unaligend area is located above super aligned
+ * Super unaligned area is located above super aligned
* area. That is, `sa.bot` is beginning of the super
* carrier, `sua.top` is the end of the super carrier,
* and sa.top and sua.bot moves towards eachother.
@@ -355,6 +358,12 @@ char* erts_literals_start;
UWord erts_literals_size;
#endif
+#ifdef ERTS_ALC_A_EXEC
+ErtsMemMapper erts_exec_mmapper;
+#endif
+
+
+
#define ERTS_MMAP_SIZE_SC_SA_INC(SZ) \
do { \
mm->size.supercarrier.used.total += (SZ); \
@@ -1232,6 +1241,7 @@ Eterm build_free_seg_list(Process* p, ErtsFreeSegMap* map)
#if HAVE_MMAP
# define ERTS_MMAP_PROT (PROT_READ|PROT_WRITE)
+# define ERTS_MMAP_PROT_EXEC (PROT_READ|PROT_WRITE|PROT_EXEC)
# if defined(MAP_ANONYMOUS)
# define ERTS_MMAP_FLAGS (MAP_ANON|MAP_PRIVATE)
# define ERTS_MMAP_FD (-1)
@@ -1245,24 +1255,26 @@ Eterm build_free_seg_list(Process* p, ErtsFreeSegMap* map)
#endif
static ERTS_INLINE void *
-os_mmap(void *hint_ptr, UWord size, int try_superalign)
+os_mmap(void *hint_ptr, UWord size, int try_superalign, int executable)
{
#if HAVE_MMAP
+ const int prot = executable ? ERTS_MMAP_PROT_EXEC : ERTS_MMAP_PROT;
void *res;
#ifdef MAP_ALIGN
if (try_superalign)
- res = mmap((void *) ERTS_SUPERALIGNED_SIZE, size, ERTS_MMAP_PROT,
+ res = mmap((void *) ERTS_SUPERALIGNED_SIZE, size, prot,
ERTS_MMAP_FLAGS|MAP_ALIGN, ERTS_MMAP_FD, 0);
else
#endif
- res = mmap((void *) hint_ptr, size, ERTS_MMAP_PROT,
+ res = mmap((void *) hint_ptr, size, prot,
ERTS_MMAP_FLAGS, ERTS_MMAP_FD, 0);
if (res == MAP_FAILED)
return NULL;
return res;
#elif HAVE_VIRTUALALLOC
+ const DWORD prot = executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
return (void *) VirtualAlloc(NULL, (SIZE_T) size,
- MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
+ MEM_COMMIT|MEM_RESERVE, prot);
#else
# error "missing mmap() or similar"
#endif
@@ -1319,6 +1331,7 @@ os_mremap(void *ptr, UWord old_size, UWord new_size, int try_superalign)
#if HAVE_MMAP
#define ERTS_MMAP_RESERVE_PROT (ERTS_MMAP_PROT)
+#define ERTS_MMAP_RESERVE_PROT_EXEC (ERTS_MMAP_PROT_EXEC)
#define ERTS_MMAP_RESERVE_FLAGS (ERTS_MMAP_FLAGS|MAP_FIXED)
#define ERTS_MMAP_UNRESERVE_PROT (PROT_NONE)
#define ERTS_MMAP_UNRESERVE_FLAGS (ERTS_MMAP_FLAGS|MAP_NORESERVE|MAP_FIXED)
@@ -1326,9 +1339,10 @@ os_mremap(void *ptr, UWord old_size, UWord new_size, int try_superalign)
#define ERTS_MMAP_VIRTUAL_FLAGS (ERTS_MMAP_FLAGS|MAP_NORESERVE)
static int
-os_reserve_physical(char *ptr, UWord size)
+os_reserve_physical(char *ptr, UWord size, int exec)
{
- void *res = mmap((void *) ptr, (size_t) size, ERTS_MMAP_RESERVE_PROT,
+ const int prot = exec ? ERTS_MMAP_RESERVE_PROT_EXEC : ERTS_MMAP_RESERVE_PROT;
+ void *res = mmap((void *) ptr, (size_t) size, prot,
ERTS_MMAP_RESERVE_FLAGS, ERTS_MMAP_FD, 0);
if (res == (void *) MAP_FAILED)
return 0;
@@ -1345,10 +1359,39 @@ os_unreserve_physical(char *ptr, UWord size)
}
static void *
-os_mmap_virtual(char *ptr, UWord size)
+os_mmap_virtual(char *ptr, UWord size, int exec)
{
- void *res = mmap((void *) ptr, (size_t) size, ERTS_MMAP_VIRTUAL_PROT,
- ERTS_MMAP_VIRTUAL_FLAGS, ERTS_MMAP_FD, 0);
+ int flags = ERTS_MMAP_VIRTUAL_FLAGS;
+ void* res;
+
+#ifdef ERTS_ALC_A_EXEC
+ if (exec) {
+ ASSERT(!ptr);
+ /* OTP-19.0: Nice hack below cut-and-pasted from hipe_amd64.c */
+
+# ifdef MAP_32BIT
+ /* If we got MAP_32BIT (Linux), then use that to ask for low memory */
+ flags |= MAP_32BIT;
+# else
+ /* FreeBSD doesn't have MAP_32BIT, and it doesn't respect
+ a plain map_hint (returns high mappings even though the
+ hint refers to a free area), so we have to use both map_hint
+ and MAP_FIXED to get addresses below the 2GB boundary.
+ This is even worse than the Linux/ppc64 case.
+ Similarly, Solaris 10 doesn't have MAP_32BIT,
+ and it doesn't respect a plain map_hint. */
+ ptr = (char*)(512*1024*1024); /* 0.5GB */
+
+# if defined(__FreeBSD__) || defined(__sun__)
+ flags |= MAP_FIXED;
+# endif
+# endif /* !MAP_32BIT */
+ }
+#else /* !ERTS_ALC_A_EXEC */
+ ASSERT(!exec);
+#endif
+ res = mmap((void *) ptr, (size_t) size, ERTS_MMAP_VIRTUAL_PROT,
+ flags, ERTS_MMAP_FD, 0);
if (res == (void *) MAP_FAILED)
return NULL;
return res;
@@ -1361,7 +1404,7 @@ os_mmap_virtual(char *ptr, UWord size)
#endif /* ERTS_HAVE_OS_MMAP */
-static int reserve_noop(char *ptr, UWord size)
+static int reserve_noop(char *ptr, UWord size, int exec)
{
#ifdef ERTS_MMAP_DEBUG_FILL_AREAS
Uint32 *uip, *end = (Uint32 *) (ptr + size);
@@ -1404,7 +1447,7 @@ alloc_desc_insert_free_seg(ErtsMemMapper* mm,
#if ERTS_HAVE_OS_MMAP
if (!mm->no_os_mmap) {
- ptr = os_mmap(mm->desc.new_area_hint, ERTS_PAGEALIGNED_SIZE, 0);
+ ptr = os_mmap(mm->desc.new_area_hint, ERTS_PAGEALIGNED_SIZE, 0, 0);
if (ptr) {
mm->desc.new_area_hint = ptr+ERTS_PAGEALIGNED_SIZE;
ERTS_MMAP_SIZE_OS_INC(ERTS_PAGEALIGNED_SIZE);
@@ -1423,7 +1466,7 @@ alloc_desc_insert_free_seg(ErtsMemMapper* mm,
da_map = &mm->sua.map;
desc = lookup_free_seg(da_map, ERTS_PAGEALIGNED_SIZE);
if (desc) {
- if (mm->reserve_physical(desc->start, ERTS_PAGEALIGNED_SIZE))
+ if (mm->reserve_physical(desc->start, ERTS_PAGEALIGNED_SIZE, 0))
ERTS_MMAP_SIZE_SC_SUA_INC(ERTS_PAGEALIGNED_SIZE);
else
desc = NULL;
@@ -1433,7 +1476,7 @@ alloc_desc_insert_free_seg(ErtsMemMapper* mm,
da_map = &mm->sa.map;
desc = lookup_free_seg(da_map, ERTS_PAGEALIGNED_SIZE);
if (desc) {
- if (mm->reserve_physical(desc->start, ERTS_PAGEALIGNED_SIZE))
+ if (mm->reserve_physical(desc->start, ERTS_PAGEALIGNED_SIZE, 0))
ERTS_MMAP_SIZE_SC_SA_INC(ERTS_PAGEALIGNED_SIZE);
else
desc = NULL;
@@ -1494,7 +1537,7 @@ erts_mmap(ErtsMemMapper* mm, Uint32 flags, UWord *sizep)
if (desc) {
seg = desc->start;
end = seg+asize;
- if (!mm->reserve_physical(seg, asize))
+ if (!mm->reserve_physical(seg, asize, mm->executable))
goto supercarrier_reserve_failure;
if (desc->end == end) {
delete_free_seg(&mm->sua.map, desc);
@@ -1509,8 +1552,8 @@ erts_mmap(ErtsMemMapper* mm, Uint32 flags, UWord *sizep)
}
if (asize <= mm->sua.bot - mm->sa.top) {
- if (!mm->reserve_physical(mm->sua.bot - asize,
- asize))
+ if (!mm->reserve_physical(mm->sua.bot - asize, asize,
+ mm->executable))
goto supercarrier_reserve_failure;
mm->sua.bot -= asize;
seg = mm->sua.bot;
@@ -1526,7 +1569,8 @@ erts_mmap(ErtsMemMapper* mm, Uint32 flags, UWord *sizep)
char *start = seg = desc->start;
seg = (char *) ERTS_SUPERALIGNED_CEILING(seg);
end = seg+asize;
- if (!mm->reserve_physical(start, (UWord) (end - start)))
+ if (!mm->reserve_physical(start, (UWord) (end - start),
+ mm->executable))
goto supercarrier_reserve_failure;
ERTS_MMAP_SIZE_SC_SA_INC(asize);
if (desc->end == end) {
@@ -1558,7 +1602,8 @@ erts_mmap(ErtsMemMapper* mm, Uint32 flags, UWord *sizep)
if (asize + (seg - start) <= mm->sua.bot - start) {
end = seg + asize;
- if (!mm->reserve_physical(start, (UWord) (end - start)))
+ if (!mm->reserve_physical(start, (UWord) (end - start),
+ mm->executable))
goto supercarrier_reserve_failure;
mm->sa.top = end;
ERTS_MMAP_SIZE_SC_SA_INC(asize);
@@ -1580,7 +1625,8 @@ erts_mmap(ErtsMemMapper* mm, Uint32 flags, UWord *sizep)
seg = (char *) ERTS_SUPERALIGNED_CEILING(org_start);
end = seg + asize;
- if (!mm->reserve_physical(seg, (UWord) (org_end - seg)))
+ if (!mm->reserve_physical(seg, (UWord) (org_end - seg),
+ mm->executable))
goto supercarrier_reserve_failure;
ERTS_MMAP_SIZE_SC_SUA_INC(asize);
if (org_start != seg) {
@@ -1613,13 +1659,13 @@ erts_mmap(ErtsMemMapper* mm, Uint32 flags, UWord *sizep)
/* Map using OS primitives */
if (!(ERTS_MMAPFLG_SUPERCARRIER_ONLY & flags) && !mm->no_os_mmap) {
if (!(ERTS_MMAPFLG_SUPERALIGNED & flags)) {
- seg = os_mmap(NULL, asize, 0);
+ seg = os_mmap(NULL, asize, 0, mm->executable);
if (!seg)
goto failure;
}
else {
asize = ERTS_SUPERALIGNED_CEILING(*sizep);
- seg = os_mmap(NULL, asize, 1);
+ seg = os_mmap(NULL, asize, 1, mm->executable);
if (!seg)
goto failure;
@@ -1629,7 +1675,8 @@ erts_mmap(ErtsMemMapper* mm, Uint32 flags, UWord *sizep)
os_munmap(seg, asize);
- ptr = os_mmap(NULL, asize + ERTS_SUPERALIGNED_SIZE, 1);
+ ptr = os_mmap(NULL, asize + ERTS_SUPERALIGNED_SIZE, 1,
+ mm->executable);
if (!ptr)
goto failure;
@@ -1964,7 +2011,8 @@ erts_mremap(ErtsMemMapper* mm,
if (next && new_end <= next->end) {
if (!mm->reserve_physical(((char *) ptr) + old_size,
- asize - old_size))
+ asize - old_size,
+ mm->executable))
goto supercarrier_reserve_failure;
if (new_end < next->end)
resize_free_seg(&mm->sua.map, next, new_end, next->end);
@@ -1982,7 +2030,8 @@ erts_mremap(ErtsMemMapper* mm,
if (end == mm->sa.top) {
if (new_end <= mm->sua.bot) {
if (!mm->reserve_physical(((char *) ptr) + old_size,
- asize - old_size))
+ asize - old_size,
+ mm->executable))
goto supercarrier_reserve_failure;
mm->sa.top = new_end;
new_ptr = ptr;
@@ -1994,7 +2043,8 @@ erts_mremap(ErtsMemMapper* mm,
adjacent_free_seg(&mm->sa.map, start, end, &prev, &next);
if (next && new_end <= next->end) {
if (!mm->reserve_physical(((char *) ptr) + old_size,
- asize - old_size))
+ asize - old_size,
+ mm->executable))
goto supercarrier_reserve_failure;
if (new_end < next->end)
resize_free_seg(&mm->sa.map, next, new_end, next->end);
@@ -2051,6 +2101,7 @@ int erts_mmap_in_supercarrier(ErtsMemMapper* mm, void *ptr)
}
static struct {
+ Eterm options;
Eterm total;
Eterm total_sa;
Eterm total_sua;
@@ -2084,6 +2135,7 @@ static void init_atoms(void)
erts_mtx_lock(&am.init_mutex);
if (!am.is_initialized) {
+ AM_INIT(options);
AM_INIT(total);
AM_INIT(total_sa);
AM_INIT(total_sua);
@@ -2112,7 +2164,7 @@ static void hard_dbg_mseg_init(void);
#endif
void
-erts_mmap_init(ErtsMemMapper* mm, ErtsMMapInit *init)
+erts_mmap_init(ErtsMemMapper* mm, ErtsMMapInit *init, int executable)
{
static int is_first_call = 1;
int virtual_map = 0;
@@ -2144,6 +2196,7 @@ erts_mmap_init(ErtsMemMapper* mm, ErtsMMapInit *init)
mm->supercarrier = 0;
mm->reserve_physical = reserve_noop;
mm->unreserve_physical = unreserve_noop;
+ mm->executable = executable;
#if HAVE_MMAP && !defined(MAP_ANON)
mm->mmap_fd = open("/dev/zero", O_RDWR);
@@ -2163,7 +2216,7 @@ erts_mmap_init(ErtsMemMapper* mm, ErtsMMapInit *init)
ptr = (char *) ERTS_PAGEALIGNED_CEILING(init->virtual_range.start);
end = (char *) ERTS_PAGEALIGNED_FLOOR(init->virtual_range.end);
sz = end - ptr;
- start = os_mmap_virtual(ptr, sz);
+ start = os_mmap_virtual(ptr, sz, executable);
if (!start || start > ptr || start >= end)
erts_exit(1,
"erts_mmap: Failed to create virtual range for super carrier\n");
@@ -2188,7 +2241,7 @@ erts_mmap_init(ErtsMemMapper* mm, ErtsMMapInit *init)
sz = ERTS_PAGEALIGNED_CEILING(init->scs);
#ifdef ERTS_HAVE_OS_PHYSICAL_MEMORY_RESERVATION
if (!init->scrpm) {
- start = os_mmap_virtual(NULL, sz);
+ start = os_mmap_virtual(NULL, sz, executable);
mm->reserve_physical = os_reserve_physical;
mm->unreserve_physical = os_unreserve_physical;
virtual_map = 1;
@@ -2200,7 +2253,7 @@ erts_mmap_init(ErtsMemMapper* mm, ErtsMMapInit *init)
* The whole supercarrier will by physically
* reserved all the time.
*/
- start = os_mmap(NULL, sz, 1);
+ start = os_mmap(NULL, sz, 1, executable);
}
if (!start)
erts_exit(1,
@@ -2274,7 +2327,7 @@ erts_mmap_init(ErtsMemMapper* mm, ErtsMMapInit *init)
mm->sua.top -= ERTS_PAGEALIGNED_SIZE;
mm->size.supercarrier.used.total += ERTS_PAGEALIGNED_SIZE;
#ifdef ERTS_HAVE_OS_PHYSICAL_MEMORY_RESERVATION
- if (!virtual_map || os_reserve_physical(mm->sua.top, ERTS_PAGEALIGNED_SIZE))
+ if (!virtual_map || os_reserve_physical(mm->sua.top, ERTS_PAGEALIGNED_SIZE, 0))
#endif
add_free_desc_area(mm, mm->sua.top, end);
mm->desc.reserved += (end - mm->sua.top) / sizeof(ErtsFreeSegDesc);
@@ -2287,7 +2340,7 @@ erts_mmap_init(ErtsMemMapper* mm, ErtsMMapInit *init)
* will be used for free segment descritors.
*/
#ifdef ERTS_HAVE_OS_PHYSICAL_MEMORY_RESERVATION
- if (virtual_map && !os_reserve_physical(start, mm->sa.bot - start))
+ if (virtual_map && !os_reserve_physical(start, mm->sa.bot - start, 0))
erts_exit(1, "erts_mmap: Failed to reserve physical memory for descriptors\n");
#endif
mm->desc.unused_start = start;
@@ -2338,9 +2391,9 @@ Eterm erts_mmap_info(ErtsMemMapper* mm,
Eterm seg_tags[] = { am.used, am.max, am.allocated, am.reserved, am.used_sa, am.used_sua };
Eterm group[2];
Eterm group_tags[] = { am.sizes, am.free_segs };
- Eterm list[2];
- Eterm list_tags[2]; /* { am.supercarrier, am.os } */
- int lix;
+ Eterm list[3];
+ Eterm list_tags[3]; /* { am.options, am.supercarrier, am.os } */
+ int lix = 0;
Eterm res = THE_NON_VALUE;
if (!hpp) {
@@ -2363,6 +2416,12 @@ Eterm erts_mmap_info(ErtsMemMapper* mm,
erts_smp_mtx_unlock(&mm->mtx);
}
+ list[lix] = erts_mmap_info_options(mm, "option ", print_to_p, print_to_arg,
+ hpp, szp);
+ list_tags[lix] = am.options;
+ lix++;
+
+
if (print_to_p) {
int to = *print_to_p;
void *arg = print_to_arg;
@@ -2392,7 +2451,6 @@ Eterm erts_mmap_info(ErtsMemMapper* mm,
init_atoms();
}
- lix = 0;
if (mm->supercarrier) {
group[0] = erts_bld_atom_uword_2tup_list(hpp, szp,
sizeof(size_tags)/sizeof(Eterm),
@@ -2457,9 +2515,13 @@ Eterm erts_mmap_info_options(ErtsMemMapper* mm,
return res;
}
+#endif /* HAVE_ERTS_MMAP */
-Eterm erts_mmap_debug_info(ErtsMemMapper* mm, Process* p)
+Eterm erts_mmap_debug_info(Process* p)
{
+#if HAVE_ERTS_MMAP
+ ErtsMemMapper* mm = &erts_dflt_mmapper;
+
if (mm->supercarrier) {
ERTS_DECL_AM(sabot);
ERTS_DECL_AM(satop);
@@ -2497,9 +2559,8 @@ Eterm erts_mmap_debug_info(ErtsMemMapper* mm, Process* p)
HRelease(p, hp_end, hp);
return list;
}
- else {
- return am_undefined;
- }
+#endif
+ return am_undefined;
}
diff --git a/erts/emulator/sys/common/erl_mmap.h b/erts/emulator/sys/common/erl_mmap.h
index 67e131b53e..7ac61a82c1 100644
--- a/erts/emulator/sys/common/erl_mmap.h
+++ b/erts/emulator/sys/common/erl_mmap.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2013. All Rights Reserved.
+ * Copyright Ericsson AB 2013-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.
@@ -26,9 +26,36 @@
#define ERTS_MMAP_SUPERALIGNED_BITS (18)
/* Affects hard limits for sbct and lmbcs documented in erts_alloc.xml */
-#define ERTS_MMAPFLG_OS_ONLY (((Uint32) 1) << 0)
-#define ERTS_MMAPFLG_SUPERCARRIER_ONLY (((Uint32) 1) << 1)
-#define ERTS_MMAPFLG_SUPERALIGNED (((Uint32) 1) << 2)
+#ifndef HAVE_MMAP
+# define HAVE_MMAP 0
+#endif
+#ifndef HAVE_MREMAP
+# define HAVE_MREMAP 0
+#endif
+#if HAVE_MMAP
+# define ERTS_HAVE_OS_MMAP 1
+# define ERTS_HAVE_GENUINE_OS_MMAP 1
+# if HAVE_MREMAP
+# define ERTS_HAVE_OS_MREMAP 1
+# endif
+# if defined(MAP_FIXED) && defined(MAP_NORESERVE)
+# define ERTS_HAVE_OS_PHYSICAL_MEMORY_RESERVATION 1
+# endif
+#endif
+
+#ifndef HAVE_VIRTUALALLOC
+# define HAVE_VIRTUALALLOC 0
+#endif
+#if HAVE_VIRTUALALLOC
+# define ERTS_HAVE_OS_MMAP 1
+#endif
+
+#ifdef ERTS_HAVE_GENUINE_OS_MMAP
+# define HAVE_ERTS_MMAP 1
+#else
+# define HAVE_ERTS_MMAP 0
+#endif
+
extern UWord erts_page_inv_mask;
@@ -53,28 +80,13 @@ typedef struct {
#define ERTS_LITERAL_VIRTUAL_AREA_SIZE (UWORD_CONSTANT(1)*1024*1024*1024)
#define ERTS_MMAP_INIT_LITERAL_INITER \
- {{NULL, NULL}, {NULL, NULL}, ERTS_LITERAL_VIRTUAL_AREA_SIZE, 1, (1 << 16), 0}
+ {{NULL, NULL}, {NULL, NULL}, ERTS_LITERAL_VIRTUAL_AREA_SIZE, 1, (1 << 10), 0}
-typedef struct ErtsMemMapper_ ErtsMemMapper;
+#define ERTS_HIPE_EXEC_VIRTUAL_AREA_SIZE (UWORD_CONSTANT(512)*1024*1024)
+
+#define ERTS_MMAP_INIT_HIPE_EXEC_INITER \
+ {{NULL, NULL}, {NULL, NULL}, ERTS_HIPE_EXEC_VIRTUAL_AREA_SIZE, 1, (1 << 10), 0}
-void *erts_mmap(ErtsMemMapper*, Uint32 flags, UWord *sizep);
-void erts_munmap(ErtsMemMapper*, Uint32 flags, void *ptr, UWord size);
-void *erts_mremap(ErtsMemMapper*, Uint32 flags, void *ptr, UWord old_size, UWord *sizep);
-int erts_mmap_in_supercarrier(ErtsMemMapper*, void *ptr);
-void erts_mmap_init(ErtsMemMapper*, ErtsMMapInit*);
-struct erts_mmap_info_struct
-{
- UWord sizes[6];
- UWord segs[6];
- UWord os_used;
-};
-Eterm erts_mmap_info(ErtsMemMapper*, int *print_to_p, void *print_to_arg,
- Eterm** hpp, Uint* szp, struct erts_mmap_info_struct*);
-Eterm erts_mmap_info_options(ErtsMemMapper*,
- char *prefix, int *print_to_p, void *print_to_arg,
- Uint **hpp, Uint *szp);
-struct process;
-Eterm erts_mmap_debug_info(ErtsMemMapper*, struct process*);
#define ERTS_SUPERALIGNED_SIZE \
(1 << ERTS_MMAP_SUPERALIGNED_BITS)
@@ -102,34 +114,46 @@ Eterm erts_mmap_debug_info(ErtsMemMapper*, struct process*);
#define ERTS_PAGEALIGNED_SIZE \
(ERTS_INV_PAGEALIGNED_MASK + 1)
-#ifndef HAVE_MMAP
-# define HAVE_MMAP 0
-#endif
-#ifndef HAVE_MREMAP
-# define HAVE_MREMAP 0
-#endif
-#if HAVE_MMAP
-# define ERTS_HAVE_OS_MMAP 1
-# define ERTS_HAVE_GENUINE_OS_MMAP 1
-# if HAVE_MREMAP
-# define ERTS_HAVE_OS_MREMAP 1
-# endif
-# if defined(MAP_FIXED) && defined(MAP_NORESERVE)
-# define ERTS_HAVE_OS_PHYSICAL_MEMORY_RESERVATION 1
-# endif
-#endif
+struct process;
+Eterm erts_mmap_debug_info(struct process*);
-#ifndef HAVE_VIRTUALALLOC
-# define HAVE_VIRTUALALLOC 0
-#endif
-#if HAVE_VIRTUALALLOC
-# define ERTS_HAVE_OS_MMAP 1
-#endif
+#if HAVE_ERTS_MMAP
+
+typedef struct ErtsMemMapper_ ErtsMemMapper;
+
+#define ERTS_MMAPFLG_OS_ONLY (((Uint32) 1) << 0)
+#define ERTS_MMAPFLG_SUPERCARRIER_ONLY (((Uint32) 1) << 1)
+#define ERTS_MMAPFLG_SUPERALIGNED (((Uint32) 1) << 2)
+
+void *erts_mmap(ErtsMemMapper*, Uint32 flags, UWord *sizep);
+void erts_munmap(ErtsMemMapper*, Uint32 flags, void *ptr, UWord size);
+void *erts_mremap(ErtsMemMapper*, Uint32 flags, void *ptr, UWord old_size, UWord *sizep);
+int erts_mmap_in_supercarrier(ErtsMemMapper*, void *ptr);
+void erts_mmap_init(ErtsMemMapper*, ErtsMMapInit*, int executable);
+struct erts_mmap_info_struct
+{
+ UWord sizes[6];
+ UWord segs[6];
+ UWord os_used;
+};
+Eterm erts_mmap_info(ErtsMemMapper*, int *print_to_p, void *print_to_arg,
+ Eterm** hpp, Uint* szp, struct erts_mmap_info_struct*);
+Eterm erts_mmap_info_options(ErtsMemMapper*,
+ char *prefix, int *print_to_p, void *print_to_arg,
+ Uint **hpp, Uint *szp);
+
+
+#ifdef ERTS_WANT_MEM_MAPPERS
+# include "erl_alloc_types.h"
extern ErtsMemMapper erts_dflt_mmapper;
-#if defined(ARCH_64) && defined(ERTS_HAVE_OS_PHYSICAL_MEMORY_RESERVATION)
+# if defined(ARCH_64) && defined(ERTS_HAVE_OS_PHYSICAL_MEMORY_RESERVATION)
extern ErtsMemMapper erts_literal_mmapper;
-#endif
+# endif
+# ifdef ERTS_ALC_A_EXEC
+extern ErtsMemMapper erts_exec_mmapper;
+# endif
+#endif /* ERTS_WANT_MEM_MAPPERS */
/*#define HARD_DEBUG_MSEG*/
#ifdef HARD_DEBUG_MSEG
@@ -142,4 +166,6 @@ void hard_dbg_remove_mseg(void* seg, UWord sz);
# define HARD_DBG_REMOVE_MSEG(SEG,SZ)
#endif
+#endif /* HAVE_ERTS_MMAP */
+
#endif /* ERL_MMAP_H__ */
diff --git a/erts/emulator/sys/common/erl_mseg.c b/erts/emulator/sys/common/erl_mseg.c
index 286130bece..f3306a888c 100644
--- a/erts/emulator/sys/common/erl_mseg.c
+++ b/erts/emulator/sys/common/erl_mseg.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2002-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.
@@ -31,6 +31,7 @@
# include "config.h"
#endif
+#define ERTS_WANT_MEM_MAPPERS
#include "sys.h"
#include "erl_mseg.h"
#include "global.h"
@@ -995,10 +996,7 @@ info_options(ErtsMsegAllctr_t *ma,
Uint **hpp,
Uint *szp)
{
- Eterm res;
-
- res = erts_mmap_info_options(&erts_dflt_mmapper,
- prefix, print_to_p, print_to_arg, hpp, szp);
+ Eterm res = NIL;
if (print_to_p) {
int to = *print_to_p;
@@ -1109,7 +1107,7 @@ info_calls(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg, Uint **hpp
static Eterm
info_status(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg,
- int begin_new_max_period, Uint **hpp, Uint *szp)
+ int begin_new_max_period, int only_sz, Uint **hpp, Uint *szp)
{
Eterm res = THE_NON_VALUE;
@@ -1122,38 +1120,41 @@ info_status(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg,
int to = *print_to_p;
void *arg = print_to_arg;
- erts_print(to, arg, "cached_segments: %beu\n", ma->cache_size);
- erts_print(to, arg, "cache_hits: %beu\n", ma->cache_hits);
- erts_print(to, arg, "segments: %beu %beu %beu\n",
- ma->segments.current.no, ma->segments.max.no, ma->segments.max_ever.no);
- erts_print(to, arg, "segments_size: %beu %beu %beu\n",
+ if (!only_sz) {
+ erts_print(to, arg, "cached_segments: %beu\n", ma->cache_size);
+ erts_print(to, arg, "cache_hits: %beu\n", ma->cache_hits);
+ erts_print(to, arg, "segments: %beu %beu %beu\n",
+ ma->segments.current.no, ma->segments.max.no, ma->segments.max_ever.no);
+ erts_print(to, arg, "segments_watermark: %beu\n",
+ ma->segments.current.watermark);
+ }
+ erts_print(to, arg, "segments_size: %beu %beu %beu\n",
ma->segments.current.sz, ma->segments.max.sz, ma->segments.max_ever.sz);
- erts_print(to, arg, "segments_watermark: %beu\n",
- ma->segments.current.watermark);
}
if (hpp || szp) {
res = NIL;
- add_2tup(hpp, szp, &res,
- am.segments_watermark,
- bld_unstable_uint(hpp, szp, ma->segments.current.watermark));
- add_4tup(hpp, szp, &res,
- am.segments_size,
- bld_unstable_uint(hpp, szp, ma->segments.current.sz),
- bld_unstable_uint(hpp, szp, ma->segments.max.sz),
- bld_unstable_uint(hpp, szp, ma->segments.max_ever.sz));
- add_4tup(hpp, szp, &res,
- am.segments,
- bld_unstable_uint(hpp, szp, ma->segments.current.no),
- bld_unstable_uint(hpp, szp, ma->segments.max.no),
- bld_unstable_uint(hpp, szp, ma->segments.max_ever.no));
- add_2tup(hpp, szp, &res,
- am.cache_hits,
- bld_unstable_uint(hpp, szp, ma->cache_hits));
- add_2tup(hpp, szp, &res,
- am.cached_segments,
- bld_unstable_uint(hpp, szp, ma->cache_size));
-
+ add_4tup(hpp, szp, &res,
+ am.segments_size,
+ bld_unstable_uint(hpp, szp, ma->segments.current.sz),
+ bld_unstable_uint(hpp, szp, ma->segments.max.sz),
+ bld_unstable_uint(hpp, szp, ma->segments.max_ever.sz));
+ if (!only_sz) {
+ add_2tup(hpp, szp, &res,
+ am.segments_watermark,
+ bld_unstable_uint(hpp, szp, ma->segments.current.watermark));
+ add_4tup(hpp, szp, &res,
+ am.segments,
+ bld_unstable_uint(hpp, szp, ma->segments.current.no),
+ bld_unstable_uint(hpp, szp, ma->segments.max.no),
+ bld_unstable_uint(hpp, szp, ma->segments.max_ever.no));
+ add_2tup(hpp, szp, &res,
+ am.cache_hits,
+ bld_unstable_uint(hpp, szp, ma->cache_hits));
+ add_2tup(hpp, szp, &res,
+ am.cached_segments,
+ bld_unstable_uint(hpp, szp, ma->cache_size));
+ }
}
if (begin_new_max_period) {
@@ -1165,26 +1166,31 @@ info_status(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg,
}
static Eterm info_memkind(ErtsMsegAllctr_t *ma, int *print_to_p, void *print_to_arg,
- int begin_max_per, Uint **hpp, Uint *szp)
+ int begin_max_per, int only_sz, Uint **hpp, Uint *szp)
{
Eterm res = THE_NON_VALUE;
Eterm atoms[3];
Eterm values[3];
- if (print_to_p) {
- erts_print(*print_to_p, print_to_arg, "memory kind: %s\n", "all memory");
- }
- if (hpp || szp) {
- atoms[0] = am.name;
- atoms[1] = am.status;
- atoms[2] = am.calls;
- values[0] = erts_bld_string(hpp, szp, "all memory");
+ if (!only_sz) {
+ if (print_to_p) {
+ erts_print(*print_to_p, print_to_arg, "memory kind: %s\n", "all memory");
+ }
+ if (hpp || szp) {
+ atoms[0] = am.name;
+ atoms[1] = am.status;
+ atoms[2] = am.calls;
+ values[0] = erts_bld_string(hpp, szp, "all memory");
+ }
}
- values[1] = info_status(ma, print_to_p, print_to_arg, begin_max_per, hpp, szp);
- values[2] = info_calls(ma, print_to_p, print_to_arg, hpp, szp);
+ res = info_status(ma, print_to_p, print_to_arg, begin_max_per, only_sz, hpp, szp);
+ if (!only_sz) {
+ values[1] = res;
+ values[2] = info_calls(ma, print_to_p, print_to_arg, hpp, szp);
- if (hpp || szp)
- res = bld_2tup_list(hpp, szp, 3, atoms, values);
+ if (hpp || szp)
+ res = bld_2tup_list(hpp, szp, 3, atoms, values);
+ }
return res;
}
@@ -1228,6 +1234,7 @@ erts_mseg_info(int ix,
int *print_to_p,
void *print_to_arg,
int begin_max_per,
+ int only_sz,
Uint **hpp,
Uint *szp)
{
@@ -1238,24 +1245,29 @@ erts_mseg_info(int ix,
Uint n = 0;
if (hpp || szp) {
-
- if (!atoms_initialized)
- init_atoms(ma);
-
- atoms[0] = am.version;
- atoms[1] = am.options;
- atoms[2] = am.memkind;
- atoms[3] = am.memkind;
+ if (!atoms_initialized)
+ init_atoms(ma);
+ }
+ if (!only_sz) {
+ if (hpp || szp) {
+ atoms[0] = am.version;
+ atoms[1] = am.options;
+ atoms[2] = am.memkind;
+ }
+ values[n++] = info_version(ma, print_to_p, print_to_arg, hpp, szp);
+ values[n++] = info_options(ma, "option ", print_to_p, print_to_arg, hpp, szp);
}
- values[n++] = info_version(ma, print_to_p, print_to_arg, hpp, szp);
- values[n++] = info_options(ma, "option ", print_to_p, print_to_arg, hpp, szp);
ERTS_MSEG_LOCK(ma);
ERTS_DBG_MA_CHK_THR_ACCESS(ma);
- values[n++] = info_memkind(ma, print_to_p, print_to_arg, begin_max_per, hpp, szp);
- if (hpp || szp)
- res = bld_2tup_list(hpp, szp, n, atoms, values);
+ res = info_memkind(ma, print_to_p, print_to_arg, begin_max_per, only_sz, hpp, szp);
+
+ if (!only_sz) {
+ values[n++] = res;
+ if (hpp || szp)
+ res = bld_2tup_list(hpp, szp, n, atoms, values);
+ }
ERTS_MSEG_UNLOCK(ma);
@@ -1402,9 +1414,15 @@ erts_mseg_init(ErtsMsegInit_t *init)
erts_mtx_init(&init_atoms_mutex, "mseg_init_atoms");
- erts_mmap_init(&erts_dflt_mmapper, &init->dflt_mmap);
+#ifdef ERTS_ALC_A_EXEC
+ /* Initialize erts_exec_mapper *FIRST*, to increase probability
+ * of getting low memory for HiPE AMD64's small code model.
+ */
+ erts_mmap_init(&erts_exec_mmapper, &init->exec_mmap, 1);
+#endif
+ erts_mmap_init(&erts_dflt_mmapper, &init->dflt_mmap, 0);
#if defined(ARCH_64) && defined(ERTS_HAVE_OS_PHYSICAL_MEMORY_RESERVATION)
- erts_mmap_init(&erts_literal_mmapper, &init->literal_mmap);
+ erts_mmap_init(&erts_literal_mmapper, &init->literal_mmap, 0);
#endif
if (!IS_2POW(GET_PAGE_SIZE))
diff --git a/erts/emulator/sys/common/erl_mseg.h b/erts/emulator/sys/common/erl_mseg.h
index 2acd8f8505..a43b409e94 100644
--- a/erts/emulator/sys/common/erl_mseg.h
+++ b/erts/emulator/sys/common/erl_mseg.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2002-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.
@@ -61,6 +61,7 @@ typedef struct {
Uint nos;
ErtsMMapInit dflt_mmap;
ErtsMMapInit literal_mmap;
+ ErtsMMapInit exec_mmap;
} ErtsMsegInit_t;
#define ERTS_MSEG_INIT_DEFAULT_INITIALIZER \
@@ -70,7 +71,8 @@ typedef struct {
10, /* mcs: Max cache size */ \
1000, /* cci: Cache check interval */ \
ERTS_MMAP_INIT_DEFAULT_INITER, \
- ERTS_MMAP_INIT_LITERAL_INITER \
+ ERTS_MMAP_INIT_LITERAL_INITER, \
+ ERTS_MMAP_INIT_HIPE_EXEC_INITER \
}
typedef struct {
@@ -97,7 +99,7 @@ void erts_mseg_init(ErtsMsegInit_t *init);
void erts_mseg_late_init(void); /* Have to be called after all allocators,
threads and timers have been initialized. */
Eterm erts_mseg_info_options(int, int *, void*, Uint **, Uint *);
-Eterm erts_mseg_info(int, int *, void*, int, Uint **, Uint *);
+Eterm erts_mseg_info(int, int *, void*, int, int, Uint **, Uint *);
#endif /* #if HAVE_ERTS_MSEG */
diff --git a/erts/emulator/sys/common/erl_mtrace_sys_wrap.c b/erts/emulator/sys/common/erl_mtrace_sys_wrap.c
index a8c575835a..fc871f94f1 100644
--- a/erts/emulator/sys/common/erl_mtrace_sys_wrap.c
+++ b/erts/emulator/sys/common/erl_mtrace_sys_wrap.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/sys/common/erl_os_monotonic_time_extender.c b/erts/emulator/sys/common/erl_os_monotonic_time_extender.c
index 367b22d989..d53190fdd5 100644
--- a/erts/emulator/sys/common/erl_os_monotonic_time_extender.c
+++ b/erts/emulator/sys/common/erl_os_monotonic_time_extender.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2015. All Rights Reserved.
+ * Copyright Ericsson AB 2015-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.
diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c
index 36ee94111c..e394d84f73 100644
--- a/erts/emulator/sys/common/erl_poll.c
+++ b/erts/emulator/sys/common/erl_poll.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
diff --git a/erts/emulator/sys/common/erl_poll.h b/erts/emulator/sys/common/erl_poll.h
index bc2c681876..c16122610d 100644
--- a/erts/emulator/sys/common/erl_poll.h
+++ b/erts/emulator/sys/common/erl_poll.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
diff --git a/erts/emulator/sys/common/erl_sys_common_misc.c b/erts/emulator/sys/common/erl_sys_common_misc.c
index e292741bfa..79f87eb3a9 100644
--- a/erts/emulator/sys/common/erl_sys_common_misc.c
+++ b/erts/emulator/sys/common/erl_sys_common_misc.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
diff --git a/erts/emulator/sys/common/erl_util_queue.h b/erts/emulator/sys/common/erl_util_queue.h
index b50e062dd5..73293e0225 100644
--- a/erts/emulator/sys/common/erl_util_queue.h
+++ b/erts/emulator/sys/common/erl_util_queue.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2013. All Rights Reserved.
+ * Copyright Ericsson AB 2013-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.
diff --git a/erts/emulator/sys/unix/driver_int.h b/erts/emulator/sys/unix/driver_int.h
index a6b9085245..840b832878 100644
--- a/erts/emulator/sys/unix/driver_int.h
+++ b/erts/emulator/sys/unix/driver_int.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/sys/unix/erl_child_setup.c b/erts/emulator/sys/unix/erl_child_setup.c
index 8dd14bbac6..6beb316350 100644
--- a/erts/emulator/sys/unix/erl_child_setup.c
+++ b/erts/emulator/sys/unix/erl_child_setup.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2015. All Rights Reserved.
+ * Copyright Ericsson AB 2002-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.
diff --git a/erts/emulator/sys/unix/erl_main.c b/erts/emulator/sys/unix/erl_main.c
index c417bea622..972b93a505 100644
--- a/erts/emulator/sys/unix/erl_main.c
+++ b/erts/emulator/sys/unix/erl_main.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2000-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2000-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.
diff --git a/erts/emulator/sys/unix/erl_unix_sys.h b/erts/emulator/sys/unix/erl_unix_sys.h
index 8b1822ca9f..241540b894 100644
--- a/erts/emulator/sys/unix/erl_unix_sys.h
+++ b/erts/emulator/sys/unix/erl_unix_sys.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2011. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
@@ -321,6 +321,7 @@ typedef void (*SIGFUNC)(int);
extern SIGFUNC sys_signal(int, SIGFUNC);
extern void sys_sigrelease(int);
extern void sys_sigblock(int);
+extern void sys_init_suspend_handler(void);
/*
* Handling of floating point exceptions.
diff --git a/erts/emulator/sys/unix/erl_unix_sys_ddll.c b/erts/emulator/sys/unix/erl_unix_sys_ddll.c
index daed5af1b6..8f1ceac883 100644
--- a/erts/emulator/sys/unix/erl_unix_sys_ddll.c
+++ b/erts/emulator/sys/unix/erl_unix_sys_ddll.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c
index 0a18e54389..6fb86f6dda 100644
--- a/erts/emulator/sys/unix/sys.c
+++ b/erts/emulator/sys/unix/sys.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -121,8 +121,10 @@ erts_smp_atomic_t sys_misc_mem_sz;
static void smp_sig_notify(char c);
static int sig_notify_fds[2] = {-1, -1};
+#if !defined(ETHR_UNUSABLE_SIGUSRX) && defined(ERTS_THR_HAVE_SIG_FUNCS)
static int sig_suspend_fds[2] = {-1, -1};
#define ERTS_SYS_SUSPEND_SIGNAL SIGUSR2
+#endif
#endif
@@ -678,7 +680,7 @@ sigusr1_exit(void)
#else
-#ifdef ERTS_SMP
+#ifdef ERTS_SYS_SUSPEND_SIGNAL
void
sys_thr_suspend(erts_tid_t tid) {
erts_thr_kill(tid, ERTS_SYS_SUSPEND_SIGNAL);
@@ -706,7 +708,7 @@ static RETSIGTYPE user_signal1(int signum)
#endif
}
-#ifdef ERTS_SMP
+#ifdef ERTS_SYS_SUSPEND_SIGNAL
#if (defined(SIG_SIGSET) || defined(SIG_SIGNAL))
static RETSIGTYPE suspend_signal(void)
#else
@@ -719,7 +721,7 @@ static RETSIGTYPE suspend_signal(int signum)
res = read(sig_suspend_fds[0], buf, sizeof(int));
} while (res < 0 && errno == EINTR);
}
-#endif /* #ifdef ERTS_SMP */
+#endif /* #ifdef ERTS_SYS_SUSPEND_SIGNAL */
#endif /* #ifndef ETHR_UNUSABLE_SIGUSRX */
@@ -772,13 +774,17 @@ void init_break_handler(void)
sys_signal(SIGINT, request_break);
#ifndef ETHR_UNUSABLE_SIGUSRX
sys_signal(SIGUSR1, user_signal1);
-#ifdef ERTS_SMP
- sys_signal(ERTS_SYS_SUSPEND_SIGNAL, suspend_signal);
-#endif /* #ifdef ERTS_SMP */
#endif /* #ifndef ETHR_UNUSABLE_SIGUSRX */
sys_signal(SIGQUIT, do_quit);
}
+void sys_init_suspend_handler(void)
+{
+#ifdef ERTS_SYS_SUSPEND_SIGNAL
+ sys_signal(ERTS_SYS_SUSPEND_SIGNAL, suspend_signal);
+#endif
+}
+
int sys_max_files(void)
{
return(max_files);
@@ -1323,12 +1329,14 @@ init_smp_sig_notify(void)
static void
init_smp_sig_suspend(void) {
+#ifdef ERTS_SYS_SUSPEND_SIGNAL
if (pipe(sig_suspend_fds) < 0) {
erts_exit(ERTS_ABORT_EXIT,
"Failed to create sig_suspend pipe: %s (%d)\n",
erl_errno_id(errno),
errno);
}
+#endif
}
#ifdef __DARWIN__
diff --git a/erts/emulator/sys/unix/sys_drivers.c b/erts/emulator/sys/unix/sys_drivers.c
index 82fea1b330..ac39b8a389 100644
--- a/erts/emulator/sys/unix/sys_drivers.c
+++ b/erts/emulator/sys/unix/sys_drivers.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/sys/unix/sys_float.c b/erts/emulator/sys/unix/sys_float.c
index 8fe7e599e5..6435da086f 100644
--- a/erts/emulator/sys/unix/sys_float.c
+++ b/erts/emulator/sys/unix/sys_float.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
@@ -53,7 +53,7 @@ static void erts_init_fp_exception(void)
void erts_thread_init_fp_exception(void)
{
unsigned long *fpe = erts_alloc(ERTS_ALC_T_FP_EXCEPTION, sizeof(*fpe));
- *fpe = 0L;
+ *fpe = 0;
erts_tsd_set(fpe_key, fpe);
}
@@ -102,6 +102,17 @@ void erts_fp_check_init_error(volatile unsigned long *fpexnp)
#define __DARWIN__ 1
#endif
+/*
+ * Define two processor and possibly OS-specific primitives:
+ *
+ * static void unmask_fpe(void);
+ * -- unmask invalid, overflow, and divide-by-zero exceptions
+ *
+ * static int mask_fpe(void);
+ * -- mask invalid, overflow, and divide-by-zero exceptions
+ * -- return non-zero if the previous state was unmasked
+ */
+
#if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__)
static void unmask_x87(void)
@@ -113,7 +124,6 @@ static void unmask_x87(void)
__asm__ __volatile__("fldcw %0" : : "m"(cw));
}
-/* mask x87 FPE, return true if the previous state was unmasked */
static int mask_x87(void)
{
unsigned short cw;
@@ -136,7 +146,6 @@ static void unmask_sse2(void)
__asm__ __volatile__("ldmxcsr %0" : : "m"(mxcsr));
}
-/* mask SSE2 FPE, return true if the previous state was unmasked */
static int mask_sse2(void)
{
unsigned int mxcsr;
@@ -257,21 +266,19 @@ static int cpu_has_sse2(void)
}
#endif /* !__x86_64__ */
-static void unmask_fpe(void)
+static void unmask_fpe_internal(void)
{
- __asm__ __volatile__("fnclex");
unmask_x87();
if (cpu_has_sse2())
unmask_sse2();
}
-static void unmask_fpe_conditional(int unmasked)
+static void unmask_fpe(void)
{
- if (unmasked)
- unmask_fpe();
+ __asm__ __volatile__("fnclex");
+ unmask_fpe_internal();
}
-/* mask x86 FPE, return true if the previous state was unmasked */
static int mask_fpe(void)
{
int unmasked;
@@ -285,9 +292,7 @@ static int mask_fpe(void)
void erts_restore_fpu(void)
{
__asm__ __volatile__("fninit");
- unmask_x87();
- if (cpu_has_sse2())
- unmask_sse2();
+ unmask_fpe_internal();
}
#elif defined(__sparc__) && defined(__linux__)
@@ -310,13 +315,6 @@ static void unmask_fpe(void)
__asm__ __volatile__(LDX " %0, %%fsr" : : "m"(fsr));
}
-static void unmask_fpe_conditional(int unmasked)
-{
- if (unmasked)
- unmask_fpe();
-}
-
-/* mask SPARC FPE, return true if the previous state was unmasked */
static int mask_fpe(void)
{
unsigned long fsr;
@@ -431,13 +429,6 @@ static void unmask_fpe(void)
set_fpscr(0x80|0x40|0x10); /* VE, OE, ZE; not UE or XE */
}
-static void unmask_fpe_conditional(int unmasked)
-{
- if (unmasked)
- unmask_fpe();
-}
-
-/* mask PowerPC FPE, return true if the previous state was unmasked */
static int mask_fpe(void)
{
int unmasked;
@@ -447,20 +438,13 @@ static int mask_fpe(void)
return unmasked;
}
-#else
+#else /* !(x86 || (sparc && linux) || (powerpc && (linux || darwin))) */
static void unmask_fpe(void)
{
fpsetmask(FP_X_INV | FP_X_OFL | FP_X_DZ);
}
-static void unmask_fpe_conditional(int unmasked)
-{
- if (unmasked)
- unmask_fpe();
-}
-
-/* mask IEEE FPE, return true if previous state was unmasked */
static int mask_fpe(void)
{
const fp_except unmasked_mask = FP_X_INV | FP_X_OFL | FP_X_DZ;
@@ -472,6 +456,16 @@ static int mask_fpe(void)
#endif
+/*
+ * Define a processor and OS-specific SIGFPE handler.
+ *
+ * The effect of receiving a SIGFPE should be:
+ * 1. Update the processor context:
+ * a) on x86: mask FP exceptions, do not skip faulting instruction
+ * b) on SPARC and PowerPC: unmask FP exceptions, skip faulting instruction
+ * 2. call set_current_fp_exception with the PC of the faulting instruction
+ */
+
#if (defined(__linux__) && (defined(__i386__) || defined(__x86_64__) || defined(__sparc__) || defined(__powerpc__))) || (defined(__DARWIN__) && (defined(__i386__) || defined(__x86_64__) || defined(__ppc__))) || (defined(__FreeBSD__) && (defined(__x86_64__) || defined(__i386__))) || ((defined(__NetBSD__) || defined(__OpenBSD__)) && defined(__x86_64__)) || (defined(__sun__) && defined(__x86_64__))
#if defined(__linux__) && defined(__i386__)
@@ -499,18 +493,8 @@ static int mask_fpe(void)
#define mc_pc(mc) ((mc)->gregs[REG_RIP])
#elif defined(__linux__) && defined(__i386__)
#define mc_pc(mc) ((mc)->gregs[REG_EIP])
-#elif defined(__DARWIN__) && defined(__i386__)
-#ifdef DARWIN_MODERN_MCONTEXT
-#define mc_pc(mc) ((mc)->__ss.__eip)
-#else
-#define mc_pc(mc) ((mc)->ss.eip)
-#endif
-#elif defined(__DARWIN__) && defined(__x86_64__)
-#ifdef DARWIN_MODERN_MCONTEXT
-#define mc_pc(mc) ((mc)->__ss.__rip)
-#else
-#define mc_pc(mc) ((mc)->ss.rip)
-#endif
+#elif defined(__DARWIN__)
+# error "Floating-point exceptions not supported on MacOS X"
#elif defined(__FreeBSD__) && defined(__x86_64__)
#define mc_pc(mc) ((mc)->mc_rip)
#elif defined(__FreeBSD__) && defined(__i386__)
@@ -530,8 +514,7 @@ static void fpe_sig_action(int sig, siginfo_t *si, void *puc)
ucontext_t *uc = puc;
unsigned long pc;
-#if defined(__linux__)
-#if defined(__x86_64__)
+#if defined(__linux__) && defined(__x86_64__)
mcontext_t *mc = &uc->uc_mcontext;
fpregset_t fpstate = mc->fpregs;
pc = mc_pc(mc);
@@ -543,26 +526,26 @@ static void fpe_sig_action(int sig, siginfo_t *si, void *puc)
set encoding makes that a poor solution here. */
fpstate->mxcsr = 0x1F80;
fpstate->swd &= ~0xFF;
-#elif defined(__i386__)
+#elif defined(__linux__) && defined(__i386__)
mcontext_t *mc = &uc->uc_mcontext;
fpregset_t fpstate = mc->fpregs;
pc = mc_pc(mc);
if ((fpstate->status >> 16) == X86_FXSR_MAGIC)
((struct _fpstate*)fpstate)->mxcsr = 0x1F80;
fpstate->sw &= ~0xFF;
-#elif defined(__sparc__) && defined(__arch64__)
+#elif defined(__linux__) && defined(__sparc__) && defined(__arch64__)
/* on SPARC the 3rd parameter points to a sigcontext not a ucontext */
struct sigcontext *sc = (struct sigcontext*)puc;
pc = sc->sigc_regs.tpc;
sc->sigc_regs.tpc = sc->sigc_regs.tnpc;
sc->sigc_regs.tnpc += 4;
-#elif defined(__sparc__)
+#elif defined(__linux__) && defined(__sparc__)
/* on SPARC the 3rd parameter points to a sigcontext not a ucontext */
struct sigcontext *sc = (struct sigcontext*)puc;
pc = sc->si_regs.pc;
sc->si_regs.pc = sc->si_regs.npc;
sc->si_regs.npc = (unsigned long)sc->si_regs.npc + 4;
-#elif defined(__powerpc__)
+#elif defined(__linux__) && defined(__powerpc__)
#if defined(__powerpc64__)
mcontext_t *mc = &uc->uc_mcontext;
unsigned long *regs = &mc->gp_regs[0];
@@ -573,19 +556,8 @@ static void fpe_sig_action(int sig, siginfo_t *si, void *puc)
pc = regs[PT_NIP];
regs[PT_NIP] += 4;
regs[PT_FPSCR] = 0x80|0x40|0x10; /* VE, OE, ZE; not UE or XE */
-#endif
#elif defined(__DARWIN__) && (defined(__i386__) || defined(__x86_64__))
-#ifdef DARWIN_MODERN_MCONTEXT
- mcontext_t mc = uc->uc_mcontext;
- pc = mc_pc(mc);
- mc->__fs.__fpu_mxcsr = 0x1F80;
- *(unsigned short *)&mc->__fs.__fpu_fsw &= ~0xFF;
-#else
- mcontext_t mc = uc->uc_mcontext;
- pc = mc_pc(mc);
- mc->fs.fpu_mxcsr = 0x1F80;
- *(unsigned short *)&mc->fs.fpu_fsw &= ~0xFF;
-#endif /* DARWIN_MODERN_MCONTEXT */
+# error "Floating-point exceptions not supported on MacOS X"
#elif defined(__DARWIN__) && defined(__ppc__)
mcontext_t mc = uc->uc_mcontext;
pc = mc->ss.srr0;
@@ -641,7 +613,7 @@ static void fpe_sig_action(int sig, siginfo_t *si, void *puc)
#endif
#if 0
{
- char buf[64];
+ char buf[128];
snprintf(buf, sizeof buf, "%s: FPE at %p\r\n", __FUNCTION__, (void*)pc);
write(2, buf, strlen(buf));
}
@@ -726,7 +698,8 @@ int erts_sys_block_fpe(void)
void erts_sys_unblock_fpe(int unmasked)
{
- unmask_fpe_conditional(unmasked);
+ if (unmasked)
+ unmask_fpe();
}
#endif
@@ -838,11 +811,6 @@ sys_chars_to_double(char* buf, double* fp)
int
matherr(struct exception *exc)
{
-#if !defined(NO_FPE_SIGNALS)
- volatile unsigned long *fpexnp = erts_get_current_fp_exception();
- if (fpexnp != NULL)
- *fpexnp = (unsigned long)__builtin_return_address(0);
-#endif
return 1;
}
diff --git a/erts/emulator/sys/unix/sys_time.c b/erts/emulator/sys/unix/sys_time.c
index 8ce02506ab..60f8decd96 100644
--- a/erts/emulator/sys/unix/sys_time.c
+++ b/erts/emulator/sys/unix/sys_time.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/sys/unix/sys_uds.c b/erts/emulator/sys/unix/sys_uds.c
index 015d0346a1..dd0a3b03ff 100644
--- a/erts/emulator/sys/unix/sys_uds.c
+++ b/erts/emulator/sys/unix/sys_uds.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2002-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.
diff --git a/erts/emulator/sys/unix/sys_uds.h b/erts/emulator/sys/unix/sys_uds.h
index 844a2804d8..a598102d5c 100644
--- a/erts/emulator/sys/unix/sys_uds.h
+++ b/erts/emulator/sys/unix/sys_uds.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2002-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.
diff --git a/erts/emulator/sys/win32/dosmap.c b/erts/emulator/sys/win32/dosmap.c
index a98065c666..95fbba384b 100644
--- a/erts/emulator/sys/win32/dosmap.c
+++ b/erts/emulator/sys/win32/dosmap.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/emulator/sys/win32/driver_int.h b/erts/emulator/sys/win32/driver_int.h
index b931da52f5..50097d3fd2 100644
--- a/erts/emulator/sys/win32/driver_int.h
+++ b/erts/emulator/sys/win32/driver_int.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/sys/win32/erl_main.c b/erts/emulator/sys/win32/erl_main.c
index 21d9a58da6..9eee300f48 100644
--- a/erts/emulator/sys/win32/erl_main.c
+++ b/erts/emulator/sys/win32/erl_main.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2000-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2000-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.
diff --git a/erts/emulator/sys/win32/erl_poll.c b/erts/emulator/sys/win32/erl_poll.c
index 9c1bef5f4f..94f3840b5f 100644
--- a/erts/emulator/sys/win32/erl_poll.c
+++ b/erts/emulator/sys/win32/erl_poll.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2007-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2007-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.
diff --git a/erts/emulator/sys/win32/erl_win32_sys_ddll.c b/erts/emulator/sys/win32/erl_win32_sys_ddll.c
index 7c24a77e31..274133a346 100644
--- a/erts/emulator/sys/win32/erl_win32_sys_ddll.c
+++ b/erts/emulator/sys/win32/erl_win32_sys_ddll.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
diff --git a/erts/emulator/sys/win32/erl_win_dyn_driver.h b/erts/emulator/sys/win32/erl_win_dyn_driver.h
index 9c699fdba0..6f28d513c2 100644
--- a/erts/emulator/sys/win32/erl_win_dyn_driver.h
+++ b/erts/emulator/sys/win32/erl_win_dyn_driver.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/sys/win32/erl_win_sys.h b/erts/emulator/sys/win32/erl_win_sys.h
index 99c1066ab3..7bdfac168b 100644
--- a/erts/emulator/sys/win32/erl_win_sys.h
+++ b/erts/emulator/sys/win32/erl_win_sys.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c
index ea7523ddc2..cf821b05cb 100644
--- a/erts/emulator/sys/win32/sys.c
+++ b/erts/emulator/sys/win32/sys.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2014. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -3079,6 +3079,8 @@ erl_bin_write(buf, sz, max)
}
}
+#endif /* DEBUG */
+
void
erl_assert_error(const char* expr, const char* func, const char* file, int line)
{
@@ -3094,7 +3096,6 @@ erl_assert_error(const char* expr, const char* func, const char* file, int line)
DebugBreak();
}
-#endif /* DEBUG */
static void
check_supported_os_version(void)
diff --git a/erts/emulator/sys/win32/sys_env.c b/erts/emulator/sys/win32/sys_env.c
index 67b6e55377..21ef71ad9a 100644
--- a/erts/emulator/sys/win32/sys_env.c
+++ b/erts/emulator/sys/win32/sys_env.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2002-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.
diff --git a/erts/emulator/sys/win32/sys_float.c b/erts/emulator/sys/win32/sys_float.c
index 86e822da5b..2b2d6ab7d3 100644
--- a/erts/emulator/sys/win32/sys_float.c
+++ b/erts/emulator/sys/win32/sys_float.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
@@ -139,8 +139,7 @@ sys_double_to_chars_ext(double fp, char *buffer, size_t buffer_size, size_t deci
int
matherr(struct _exception *exc)
{
- erl_fp_exception = 1;
- DEBUGF(("FP exception (matherr) (0x%x) (%d)\n", exc->type, erl_fp_exception));
+ DEBUGF(("FP exception (matherr) (0x%x)\n", exc->type));
return 1;
}
diff --git a/erts/emulator/sys/win32/sys_interrupt.c b/erts/emulator/sys/win32/sys_interrupt.c
index a89211fa8e..df838960eb 100644
--- a/erts/emulator/sys/win32/sys_interrupt.c
+++ b/erts/emulator/sys/win32/sys_interrupt.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2012. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/sys/win32/sys_time.c b/erts/emulator/sys/win32/sys_time.c
index 9a9d90610d..e8c67b3928 100644
--- a/erts/emulator/sys/win32/sys_time.c
+++ b/erts/emulator/sys/win32/sys_time.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/Makefile b/erts/emulator/test/Makefile
index 318db4b45e..de395dfb97 100644
--- a/erts/emulator/test/Makefile
+++ b/erts/emulator/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2012. All Rights Reserved.
+# Copyright Ericsson AB 1997-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.
@@ -70,6 +70,7 @@ MODULES= \
hash_SUITE \
hibernate_SUITE \
list_bif_SUITE \
+ lttng_SUITE \
map_SUITE \
match_spec_SUITE \
module_info_SUITE \
@@ -109,8 +110,11 @@ MODULES= \
trace_meta_SUITE \
trace_call_count_SUITE \
trace_call_time_SUITE \
+ tracer_SUITE \
+ tracer_test \
scheduler_SUITE \
old_scheduler_SUITE \
+ port_trace_SUITE \
unique_SUITE \
z_SUITE \
old_mod \
diff --git a/erts/emulator/test/a_SUITE.erl b/erts/emulator/test/a_SUITE.erl
index 5b3a213154..880c5a5821 100644
--- a/erts/emulator/test/a_SUITE.erl
+++ b/erts/emulator/test/a_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2006-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.
diff --git a/erts/emulator/test/after_SUITE.erl b/erts/emulator/test/after_SUITE.erl
index a72cd8deea..4f20ad3656 100644
--- a/erts/emulator/test/after_SUITE.erl
+++ b/erts/emulator/test/after_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/alloc_SUITE.erl b/erts/emulator/test/alloc_SUITE.erl
index 1f690c5015..1f7b499dcb 100644
--- a/erts/emulator/test/alloc_SUITE.erl
+++ b/erts/emulator/test/alloc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2003-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.
@@ -55,21 +55,13 @@ end_per_testcase(_Case, Config) when is_list(Config) ->
%% %%
basic(Cfg) -> drv_case(Cfg).
-
coalesce(Cfg) -> drv_case(Cfg).
-
threads(Cfg) -> drv_case(Cfg).
-
realloc_copy(Cfg) -> drv_case(Cfg).
-
bucket_index(Cfg) -> drv_case(Cfg).
-
bucket_mask(Cfg) -> drv_case(Cfg).
-
rbtree(Cfg) -> drv_case(Cfg).
-
mseg_clear_cache(Cfg) -> drv_case(Cfg).
-
cpool(Cfg) -> drv_case(Cfg).
migration(Cfg) ->
@@ -81,7 +73,7 @@ migration(Cfg) ->
end.
erts_mmap(Config) when is_list(Config) ->
- case test_server:os_type() of
+ case os:type() of
{unix, _} ->
[erts_mmap_do(Config, SCO, SCRPM, SCRFSD)
|| SCO <-[true,false], SCRFSD <-[1234,0], SCRPM <- [true,false]];
@@ -109,25 +101,26 @@ erts_mmap_do(Config, SCO, SCRPM, SCRFSD) ->
{ok, Node} = start_node(Config, Opts),
Self = self(),
Ref = make_ref(),
- F = fun () ->
- SI = erlang:system_info({allocator,mseg_alloc}),
- {erts_mmap,EM} = lists:keyfind(erts_mmap, 1, SI),
- {supercarrier,SC} = lists:keyfind(supercarrier, 1, EM),
- {sizes,Sizes} = lists:keyfind(sizes, 1, SC),
- {free_segs,Segs} = lists:keyfind(free_segs,1,SC),
- {total,Total} = lists:keyfind(total,1,Sizes),
- Total = SCS*1024*1024,
-
- {reserved,Reserved} = lists:keyfind(reserved,1,Segs),
- true = (Reserved >= SCRFSD),
-
- case {SCO,lists:keyfind(os,1,EM)} of
- {true, false} -> ok;
- {false, {os,_}} -> ok
- end,
-
- Self ! {Ref, ok}
- end,
+ F = fun() ->
+ SI = erlang:system_info({allocator,erts_mmap}),
+ {default_mmap,EM} = lists:keyfind(default_mmap, 1, SI),
+ {supercarrier,SC} = lists:keyfind(supercarrier, 1, EM),
+ {sizes,Sizes} = lists:keyfind(sizes, 1, SC),
+ {free_segs,Segs} = lists:keyfind(free_segs,1,SC),
+ {total,Total} = lists:keyfind(total,1,Sizes),
+ io:format("Expecting total ~w, got ~w~n", [SCS*1024*1024,Total]),
+ Total = SCS*1024*1024,
+
+ {reserved,Reserved} = lists:keyfind(reserved,1,Segs),
+ true = (Reserved >= SCRFSD),
+
+ case {SCO,lists:keyfind(os,1,EM)} of
+ {true, false} -> ok;
+ {false, {os,_}} -> ok
+ end,
+
+ Self ! {Ref, ok}
+ end,
spawn_link(Node, F),
Result = receive {Ref, Rslt} -> Rslt end,
@@ -144,7 +137,7 @@ drv_case(Config) ->
drv_case(Config, one_shot, "").
drv_case(Config, Mode, NodeOpts) when is_list(Config) ->
- case test_server:os_type() of
+ case os:type() of
{Family, _} when Family == unix; Family == win32 ->
{ok, Node} = start_node(Config, NodeOpts),
Self = self(),
diff --git a/erts/emulator/test/alloc_SUITE_data/cpool.c b/erts/emulator/test/alloc_SUITE_data/cpool.c
index 73026cc758..0c41f4d747 100644
--- a/erts/emulator/test/alloc_SUITE_data/cpool.c
+++ b/erts/emulator/test/alloc_SUITE_data/cpool.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2013. All Rights Reserved.
+ * Copyright Ericsson AB 2013-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.
diff --git a/erts/emulator/test/alloc_SUITE_data/migration.c b/erts/emulator/test/alloc_SUITE_data/migration.c
index b006360043..b9a4de03b3 100644
--- a/erts/emulator/test/alloc_SUITE_data/migration.c
+++ b/erts/emulator/test/alloc_SUITE_data/migration.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2014. All Rights Reserved.
+ * Copyright Ericsson AB 2014-2016. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
diff --git a/erts/emulator/test/beam_SUITE.erl b/erts/emulator/test/beam_SUITE.erl
index 07dfeb6633..6a54fa87e0 100644
--- a/erts/emulator/test/beam_SUITE.erl
+++ b/erts/emulator/test/beam_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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.
@@ -24,17 +24,19 @@
init_per_group/2,end_per_group/2,
packed_registers/1, apply_last/1, apply_last_bif/1,
buildo_mucho/1, heap_sizes/1, big_lists/1, fconv/1,
- select_val/1]).
+ select_val/1, swap_temp_apply/1]).
--export([applied/2]).
+-export([applied/2,swap_temp_applied/1]).
-include_lib("common_test/include/ct.hrl").
+-include_lib("syntax_tools/include/merl.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[packed_registers, apply_last, apply_last_bif,
- buildo_mucho, heap_sizes, big_lists, select_val].
+ buildo_mucho, heap_sizes, big_lists, select_val,
+ swap_temp_apply].
groups() ->
[].
@@ -92,48 +94,46 @@ applied(Starter, N) ->
apply_last_bif(Config) when is_list(Config) ->
apply(erlang, abs, [1]).
-%% Test three high register numbers in a put_list instruction
-%% (to test whether packing works properly).
+%% Test whether packing works properly.
packed_registers(Config) when is_list(Config) ->
- PrivDir = proplists:get_value(priv_dir, Config),
- Mod = packed_regs,
- Name = filename:join(PrivDir, atom_to_list(Mod) ++ ".erl"),
-
- %% Generate a module which generates a list of tuples.
- %% put_list(A) -> [{A, 600}, {A, 999}, ... {A, 0}].
- Code = gen_packed_regs(600, ["-module("++atom_to_list(Mod)++").\n",
- "-export([put_list/1]).\n",
- "put_list(A) ->\n["]),
- ok = file:write_file(Name, Code),
-
- %% Compile the module.
- io:format("Compiling: ~s\n", [Name]),
- CompRc = compile:file(Name, [{outdir, PrivDir}, report]),
- io:format("Result: ~p\n",[CompRc]),
- {ok, Mod} = CompRc,
-
- %% Load it.
- io:format("Loading...\n",[]),
- LoadRc = code:load_abs(filename:join(PrivDir, atom_to_list(Mod))),
- {module,_Module} = LoadRc,
-
- %% Call it and verify result.
- Term = {a, b},
- L = Mod:put_list(Term),
- verify_packed_regs(L, Term, 600),
+ Mod = ?FUNCTION_NAME,
+
+ %% Generate scrambled sequence.
+ Seq0 = [{erlang:phash2(I),I} || I <- lists:seq(0, 260)],
+ Seq = [I || {_,I} <- lists:sort(Seq0)],
+
+ %% Generate a test modules that uses get_list/3 instructions
+ %% with high register numbers.
+ S0 = [begin
+ VarName = list_to_atom("V"++integer_to_list(V)),
+ {merl:var(VarName),V}
+ end || V <- Seq],
+ Vars = [V || {V,_} <- S0],
+ NewVars = [begin
+ VarName = list_to_atom("M"++integer_to_list(V)),
+ merl:var(VarName)
+ end || V <- Seq],
+ S = [?Q("_@Var = id(_@Value@)") || {Var,Value} <- S0],
+ Code = ?Q(["-module('@Mod@').\n"
+ "-export([f/0]).\n"
+ "f() ->\n"
+ "_@S,\n"
+ "_ = id(0),\n"
+ "L = [_@Vars],\n"
+ "_ = id(1),\n"
+ "[_@NewVars] = L,\n" %Test get_list/3.
+ "_ = id(2),\n"
+ "id([_@Vars,_@NewVars]).\n"
+ "id(I) -> I.\n"]),
+ merl:compile_and_load(Code),
+ CombinedSeq = Seq ++ Seq,
+ CombinedSeq = Mod:f(),
+
+ %% Clean up.
+ true = code:delete(Mod),
+ false = code:purge(Mod),
ok.
-gen_packed_regs(0, Acc) ->
- [Acc|"{A,0}].\n"];
-gen_packed_regs(N, Acc) ->
- gen_packed_regs(N-1, [Acc,"{A,",integer_to_list(N)|"},\n"]).
-
-verify_packed_regs([], _, -1) -> ok;
-verify_packed_regs([{Term, N}| T], Term, N) ->
- verify_packed_regs(T, Term, N-1);
-verify_packed_regs(L, Term, N) ->
- ct:fail("Expected [{~p, ~p}|T]; got\n~p\n", [Term, N, L]).
-
buildo_mucho(Config) when is_list(Config) ->
buildo_mucho_1(),
ok.
@@ -346,3 +346,41 @@ do_select_val(X) ->
Int when is_integer(Int) ->
integer
end.
+
+swap_temp_apply(_Config) ->
+ {swap_temp_applied,42} = do_swap_temp_apply(41),
+ not_an_integer = do_swap_temp_apply(not_an_integer),
+ ok.
+
+do_swap_temp_apply(Msg) ->
+ case swap_temp_apply_function(Msg) of
+ undefined -> Msg;
+ Type ->
+ %% The following sequence:
+ %% move {x,0} {x,2}
+ %% move {y,0} {x,0}
+ %% move {x,2} {y,0}
+ %% apply 1
+ %%
+ %% Would be incorrectly transformed to:
+ %% swap {x,0} {y,0}
+ %% apply 1
+ %%
+ %% ({x,1} is the module, {x,2} the function to be applied).
+ %%
+ %% If the instructions are to be transformed, the correct
+ %% transformation is:
+ %%
+ %% swap_temp {x,0} {y,0} {x,2}
+ %% apply 1
+ Fields = ?MODULE:Type(Msg),
+ {Type,Fields}
+ end.
+
+swap_temp_apply_function(Int) when is_integer(Int) ->
+ swap_temp_applied;
+swap_temp_apply_function(_) ->
+ undefined.
+
+swap_temp_applied(Int) ->
+ Int+1.
diff --git a/erts/emulator/test/beam_literals_SUITE.erl b/erts/emulator/test/beam_literals_SUITE.erl
index b013ff5fbb..09761263e2 100644
--- a/erts/emulator/test/beam_literals_SUITE.erl
+++ b/erts/emulator/test/beam_literals_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl
index 43d00e699a..26bb416bf0 100644
--- a/erts/emulator/test/bif_SUITE.erl
+++ b/erts/emulator/test/bif_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/test/big_SUITE.erl b/erts/emulator/test/big_SUITE.erl
index d331083661..402751393a 100644
--- a/erts/emulator/test/big_SUITE.erl
+++ b/erts/emulator/test/big_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/big_SUITE_data/literal_test.erl b/erts/emulator/test/big_SUITE_data/literal_test.erl
index 1620693bfa..17c4db467a 100644
--- a/erts/emulator/test/big_SUITE_data/literal_test.erl
+++ b/erts/emulator/test/big_SUITE_data/literal_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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.
diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl
index fcd49e43d3..1c7d278bb0 100644
--- a/erts/emulator/test/binary_SUITE.erl
+++ b/erts/emulator/test/binary_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/bs_bincomp_SUITE.erl b/erts/emulator/test/bs_bincomp_SUITE.erl
index 8836fe40ae..c481e93e41 100644
--- a/erts/emulator/test/bs_bincomp_SUITE.erl
+++ b/erts/emulator/test/bs_bincomp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2006-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.
diff --git a/erts/emulator/test/bs_bit_binaries_SUITE.erl b/erts/emulator/test/bs_bit_binaries_SUITE.erl
index dd056d10af..d393bc5b91 100644
--- a/erts/emulator/test/bs_bit_binaries_SUITE.erl
+++ b/erts/emulator/test/bs_bit_binaries_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2006-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.
diff --git a/erts/emulator/test/bs_construct_SUITE.erl b/erts/emulator/test/bs_construct_SUITE.erl
index 8deb0c7422..941cb435f7 100644
--- a/erts/emulator/test/bs_construct_SUITE.erl
+++ b/erts/emulator/test/bs_construct_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/test/bs_match_bin_SUITE.erl b/erts/emulator/test/bs_match_bin_SUITE.erl
index 6f7abf8c4e..f5c996ae9e 100644
--- a/erts/emulator/test/bs_match_bin_SUITE.erl
+++ b/erts/emulator/test/bs_match_bin_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/test/bs_match_int_SUITE.erl b/erts/emulator/test/bs_match_int_SUITE.erl
index 42d692c1ba..a7bd4b8ac3 100644
--- a/erts/emulator/test/bs_match_int_SUITE.erl
+++ b/erts/emulator/test/bs_match_int_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/test/bs_match_misc_SUITE.erl b/erts/emulator/test/bs_match_misc_SUITE.erl
index 114d7ecb36..17759d78f3 100644
--- a/erts/emulator/test/bs_match_misc_SUITE.erl
+++ b/erts/emulator/test/bs_match_misc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2000-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.
diff --git a/erts/emulator/test/bs_match_tail_SUITE.erl b/erts/emulator/test/bs_match_tail_SUITE.erl
index 8392a0df47..cbebc554c7 100644
--- a/erts/emulator/test/bs_match_tail_SUITE.erl
+++ b/erts/emulator/test/bs_match_tail_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/test/bs_utf_SUITE.erl b/erts/emulator/test/bs_utf_SUITE.erl
index f1c09bfbb0..a344f5c456 100644
--- a/erts/emulator/test/bs_utf_SUITE.erl
+++ b/erts/emulator/test/bs_utf_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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.
diff --git a/erts/emulator/test/busy_port_SUITE.erl b/erts/emulator/test/busy_port_SUITE.erl
index c582f8d77b..bb0632ae08 100644
--- a/erts/emulator/test/busy_port_SUITE.erl
+++ b/erts/emulator/test/busy_port_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/busy_port_SUITE_data/Makefile.src b/erts/emulator/test/busy_port_SUITE_data/Makefile.src
index 0f2842e515..ae6378a6ff 100644
--- a/erts/emulator/test/busy_port_SUITE_data/Makefile.src
+++ b/erts/emulator/test/busy_port_SUITE_data/Makefile.src
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2013. All Rights Reserved.
+# Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/busy_port_SUITE_data/hard_busy_drv.c b/erts/emulator/test/busy_port_SUITE_data/hard_busy_drv.c
index f83fa1eeaa..c4e0f13f06 100644
--- a/erts/emulator/test/busy_port_SUITE_data/hard_busy_drv.c
+++ b/erts/emulator/test/busy_port_SUITE_data/hard_busy_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009. All Rights Reserved.
+ * Copyright Ericsson AB 2009-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.
diff --git a/erts/emulator/test/busy_port_SUITE_data/hs_busy_drv.c b/erts/emulator/test/busy_port_SUITE_data/hs_busy_drv.c
index be913cf56e..ffaca18e90 100644
--- a/erts/emulator/test/busy_port_SUITE_data/hs_busy_drv.c
+++ b/erts/emulator/test/busy_port_SUITE_data/hs_busy_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2009-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.
diff --git a/erts/emulator/test/busy_port_SUITE_data/scheduling_drv.c b/erts/emulator/test/busy_port_SUITE_data/scheduling_drv.c
index 40e42b6ac2..296b3f21de 100644
--- a/erts/emulator/test/busy_port_SUITE_data/scheduling_drv.c
+++ b/erts/emulator/test/busy_port_SUITE_data/scheduling_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2009-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.
diff --git a/erts/emulator/test/busy_port_SUITE_data/soft_busy_drv.c b/erts/emulator/test/busy_port_SUITE_data/soft_busy_drv.c
index 3c5bafb451..8a98f050f1 100644
--- a/erts/emulator/test/busy_port_SUITE_data/soft_busy_drv.c
+++ b/erts/emulator/test/busy_port_SUITE_data/soft_busy_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009. All Rights Reserved.
+ * Copyright Ericsson AB 2009-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.
diff --git a/erts/emulator/test/call_trace_SUITE.erl b/erts/emulator/test/call_trace_SUITE.erl
index 4ec18aa49e..6ba6301c7c 100644
--- a/erts/emulator/test/call_trace_SUITE.erl
+++ b/erts/emulator/test/call_trace_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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.
@@ -84,32 +84,46 @@ process_specs(Config) when is_list(Config) ->
{tracer,Tracer} = trace_info(self(), tracer),
trace_func({?MODULE,worker_foo,1}, []),
- %% Test the 'new' flag.
-
- {Work1A,Work1B} = start_and_trace(new, [1,2,3], A1B={3,2,1}),
- {flags,[]} = trace_info(Work1A, flags),
- {tracer,[]} = trace_info(Work1A, tracer),
- {tracer,Tracer} = trace_info(Work1B, tracer),
- {flags,[call]} = trace_info(Work1B, flags),
- expect({trace,Work1B,call,{?MODULE,worker_foo,[A1B]}}),
- unlink(Work1B),
- Mref = erlang:monitor(process, Work1B),
- exit(Work1B, kill),
- receive
- {'DOWN',Mref,_,_,_} -> ok
- end,
- undefined = trace_info(Work1B, flags),
- {flags,[]} = trace_info(new, flags),
- {tracer,[]} = trace_info(new, tracer),
-
- %% Test the 'existing' flag.
- {Work2A,_Work2B} = start_and_trace(existing, A2A=[5,6,7], [7,6,5]),
- expect({trace,Work2A,call,{?MODULE,worker_foo,[A2A]}}),
-
- %% Test the 'all' flag.
- {Work3A,Work3B} = start_and_trace(all, A3A=[12,13], A3B=[13,12]),
- expect({trace,Work3A,call,{?MODULE,worker_foo,[A3A]}}),
- expect({trace,Work3B,call,{?MODULE,worker_foo,[A3B]}}),
+ %% Test the 'new' and 'new_processes' flags.
+
+ New = fun(Flag) ->
+ {Work1A,Work1B} = start_and_trace(Flag, [1,2,3], A1B={3,2,1}),
+ {flags,[]} = trace_info(Work1A, flags),
+ {tracer,[]} = trace_info(Work1A, tracer),
+ {tracer,Tracer} = trace_info(Work1B, tracer),
+ {flags,[call]} = trace_info(Work1B, flags),
+ expect({trace,Work1B,call,{?MODULE,worker_foo,[A1B]}}),
+ unlink(Work1B),
+ Mref = erlang:monitor(process, Work1B),
+ exit(Work1B, kill),
+ receive
+ {'DOWN',Mref,_,_,_} -> ok
+ end,
+ undefined = trace_info(Work1B, flags),
+ {flags,[]} = trace_info(Flag, flags),
+ {tracer,[]} = trace_info(Flag, tracer)
+ end,
+ New(new),
+ New(new_processes),
+
+ %% Test the 'existing' and 'existing_processes' flags.
+ Existing =
+ fun(Flag) ->
+ {Work2A,_Work2B} = start_and_trace(Flag, A2A=[5,6,7], [7,6,5]),
+ expect({trace,Work2A,call,{?MODULE,worker_foo,[A2A]}})
+ end,
+ Existing(existing),
+ Existing(existing_processes),
+
+ %% Test the 'all' and 'processes' flags.
+ All =
+ fun(Flag) ->
+ {Work3A,Work3B} = start_and_trace(Flag, A3A=[12,13], A3B=[13,12]),
+ expect({trace,Work3A,call,{?MODULE,worker_foo,[A3A]}}),
+ expect({trace,Work3B,call,{?MODULE,worker_foo,[A3B]}})
+ end,
+ All(all),
+ All(processes),
ok.
diff --git a/erts/emulator/test/code_SUITE.erl b/erts/emulator/test/code_SUITE.erl
index db285a3977..29b95ef674 100644
--- a/erts/emulator/test/code_SUITE.erl
+++ b/erts/emulator/test/code_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/test/code_SUITE_data/another_code_test.erl b/erts/emulator/test/code_SUITE_data/another_code_test.erl
index f6f9e32996..5708ec682c 100644
--- a/erts/emulator/test/code_SUITE_data/another_code_test.erl
+++ b/erts/emulator/test/code_SUITE_data/another_code_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2006-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.
diff --git a/erts/emulator/test/code_SUITE_data/cpbugx.erl b/erts/emulator/test/code_SUITE_data/cpbugx.erl
index ea01ce411b..ae2075c867 100644
--- a/erts/emulator/test/code_SUITE_data/cpbugx.erl
+++ b/erts/emulator/test/code_SUITE_data/cpbugx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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.
diff --git a/erts/emulator/test/code_SUITE_data/fun_confusion.erl b/erts/emulator/test/code_SUITE_data/fun_confusion.erl
index 8d42937d3c..35279f241d 100644
--- a/erts/emulator/test/code_SUITE_data/fun_confusion.erl
+++ b/erts/emulator/test/code_SUITE_data/fun_confusion.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-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.
diff --git a/erts/emulator/test/code_SUITE_data/literals.erl b/erts/emulator/test/code_SUITE_data/literals.erl
index a36bfe09dd..7c3b0ebe73 100644
--- a/erts/emulator/test/code_SUITE_data/literals.erl
+++ b/erts/emulator/test/code_SUITE_data/literals.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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.
diff --git a/erts/emulator/test/code_SUITE_data/many_funs.erl b/erts/emulator/test/code_SUITE_data/many_funs.erl
index e832f271d0..ada570feee 100644
--- a/erts/emulator/test/code_SUITE_data/many_funs.erl
+++ b/erts/emulator/test/code_SUITE_data/many_funs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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.
diff --git a/erts/emulator/test/code_SUITE_data/my_code_test.erl b/erts/emulator/test/code_SUITE_data/my_code_test.erl
index 57d867a5ac..d2386157d6 100644
--- a/erts/emulator/test/code_SUITE_data/my_code_test.erl
+++ b/erts/emulator/test/code_SUITE_data/my_code_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/test/code_SUITE_data/versions.erl b/erts/emulator/test/code_SUITE_data/versions.erl
index 0e2d92c8f1..56407e877a 100644
--- a/erts/emulator/test/code_SUITE_data/versions.erl
+++ b/erts/emulator/test/code_SUITE_data/versions.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-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.
diff --git a/erts/emulator/test/code_parallel_load_SUITE.erl b/erts/emulator/test/code_parallel_load_SUITE.erl
index e9e7000434..827add71e5 100644
--- a/erts/emulator/test/code_parallel_load_SUITE.erl
+++ b/erts/emulator/test/code_parallel_load_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2012-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.
diff --git a/erts/emulator/test/crypto_SUITE.erl b/erts/emulator/test/crypto_SUITE.erl
index 6212997272..afb1be7332 100644
--- a/erts/emulator/test/crypto_SUITE.erl
+++ b/erts/emulator/test/crypto_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/test/crypto_reference.erl b/erts/emulator/test/crypto_reference.erl
index 7797eacd75..950b0c1560 100644
--- a/erts/emulator/test/crypto_reference.erl
+++ b/erts/emulator/test/crypto_reference.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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.
diff --git a/erts/emulator/test/ddll_SUITE.erl b/erts/emulator/test/ddll_SUITE.erl
index 6982178827..93b6f2d956 100644
--- a/erts/emulator/test/ddll_SUITE.erl
+++ b/erts/emulator/test/ddll_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/decode_packet_SUITE.erl b/erts/emulator/test/decode_packet_SUITE.erl
index ad592f7147..54ee4d5567 100644
--- a/erts/emulator/test/decode_packet_SUITE.erl
+++ b/erts/emulator/test/decode_packet_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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.
diff --git a/erts/emulator/test/dgawd_handler.erl b/erts/emulator/test/dgawd_handler.erl
index bba69ef87e..52cdd26427 100644
--- a/erts/emulator/test/dgawd_handler.erl
+++ b/erts/emulator/test/dgawd_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2006-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.
diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl
index f116ec979b..d0096fb1bc 100644
--- a/erts/emulator/test/distribution_SUITE.erl
+++ b/erts/emulator/test/distribution_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
@@ -1034,6 +1034,7 @@ atom_roundtrip(Config) when is_list(Config) ->
atom_roundtrip_r15b(Config) when is_list(Config) ->
case test_server:is_release_available("r15b") of
true ->
+ ct:timetrap({minutes, 6}),
AtomData = atom_data(),
verify_atom_data(AtomData),
{ok, Node} = start_node(Config, [], "r15b"),
diff --git a/erts/emulator/test/distribution_SUITE_data/run.erl b/erts/emulator/test/distribution_SUITE_data/run.erl
index d5ed139369..f574b2c02c 100644
--- a/erts/emulator/test/distribution_SUITE_data/run.erl
+++ b/erts/emulator/test/distribution_SUITE_data/run.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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.
diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl
index c589470f5b..f134a197aa 100644
--- a/erts/emulator/test/driver_SUITE.erl
+++ b/erts/emulator/test/driver_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/driver_SUITE_data/async_blast_drv.c b/erts/emulator/test/driver_SUITE_data/async_blast_drv.c
index a1008afcae..1432bc42c1 100644
--- a/erts/emulator/test/driver_SUITE_data/async_blast_drv.c
+++ b/erts/emulator/test/driver_SUITE_data/async_blast_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
diff --git a/erts/emulator/test/driver_SUITE_data/consume_timeslice_drv.c b/erts/emulator/test/driver_SUITE_data/consume_timeslice_drv.c
index 192ac02d3e..142ae46247 100644
--- a/erts/emulator/test/driver_SUITE_data/consume_timeslice_drv.c
+++ b/erts/emulator/test/driver_SUITE_data/consume_timeslice_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2012-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2012-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.
diff --git a/erts/emulator/test/driver_SUITE_data/ioq_exit_drv.c b/erts/emulator/test/driver_SUITE_data/ioq_exit_drv.c
index e2221b9e17..d87c2bec93 100644
--- a/erts/emulator/test/driver_SUITE_data/ioq_exit_drv.c
+++ b/erts/emulator/test/driver_SUITE_data/ioq_exit_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2007-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2007-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.
diff --git a/erts/emulator/test/driver_SUITE_data/otp_9302_drv.c b/erts/emulator/test/driver_SUITE_data/otp_9302_drv.c
index fdf8e4c0ad..37cb93fb3a 100644
--- a/erts/emulator/test/driver_SUITE_data/otp_9302_drv.c
+++ b/erts/emulator/test/driver_SUITE_data/otp_9302_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
diff --git a/erts/emulator/test/driver_SUITE_data/thr_free_drv.c b/erts/emulator/test/driver_SUITE_data/thr_free_drv.c
index 54205f190e..48fe5fa435 100644
--- a/erts/emulator/test/driver_SUITE_data/thr_free_drv.c
+++ b/erts/emulator/test/driver_SUITE_data/thr_free_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
diff --git a/erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c b/erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c
index f7a7cc2b8e..56183c9484 100644
--- a/erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c
+++ b/erts/emulator/test/driver_SUITE_data/thr_msg_blast_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2012. All Rights Reserved.
+ * Copyright Ericsson AB 2012-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.
diff --git a/erts/emulator/test/efile_SUITE.erl b/erts/emulator/test/efile_SUITE.erl
index cefa35a3ee..6bb8487c4e 100644
--- a/erts/emulator/test/efile_SUITE.erl
+++ b/erts/emulator/test/efile_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/erl_drv_thread_SUITE.erl b/erts/emulator/test/erl_drv_thread_SUITE.erl
index 41a761229c..f99c151936 100644
--- a/erts/emulator/test/erl_drv_thread_SUITE.erl
+++ b/erts/emulator/test/erl_drv_thread_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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.
@@ -65,7 +65,7 @@ drv_case(Config, CaseName, Command, TimeTrap) when is_list(Config),
is_atom(CaseName),
is_list(Command),
is_integer(TimeTrap) ->
- case test_server:os_type() of
+ case os:type() of
{Family, _} when Family == unix; Family == win32 ->
run_drv_case(Config, CaseName, Command, TimeTrap);
SkipOs ->
diff --git a/erts/emulator/test/erl_link_SUITE.erl b/erts/emulator/test/erl_link_SUITE.erl
index 56fdfc35c0..93d2065ba3 100644
--- a/erts/emulator/test/erl_link_SUITE.erl
+++ b/erts/emulator/test/erl_link_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/test/erts_debug_SUITE.erl b/erts/emulator/test/erts_debug_SUITE.erl
index e757ebdb3d..23871585f7 100644
--- a/erts/emulator/test/erts_debug_SUITE.erl
+++ b/erts/emulator/test/erts_debug_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/test/estone_SUITE.erl b/erts/emulator/test/estone_SUITE.erl
index 93728b299b..1180a45585 100644
--- a/erts/emulator/test/estone_SUITE.erl
+++ b/erts/emulator/test/estone_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2002-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.
diff --git a/erts/emulator/test/evil_SUITE.erl b/erts/emulator/test/evil_SUITE.erl
index 5f5a0ef305..9416ac7a02 100644
--- a/erts/emulator/test/evil_SUITE.erl
+++ b/erts/emulator/test/evil_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2002-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.
diff --git a/erts/emulator/test/exception_SUITE.erl b/erts/emulator/test/exception_SUITE.erl
index 1cad7e7920..76e3556bc4 100644
--- a/erts/emulator/test/exception_SUITE.erl
+++ b/erts/emulator/test/exception_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/float_SUITE.erl b/erts/emulator/test/float_SUITE.erl
index 78dec8c725..e85addae3a 100644
--- a/erts/emulator/test/float_SUITE.erl
+++ b/erts/emulator/test/float_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/float_SUITE_data/has_fpe_bug.erl b/erts/emulator/test/float_SUITE_data/has_fpe_bug.erl
index 79ab74dfff..26837de274 100644
--- a/erts/emulator/test/float_SUITE_data/has_fpe_bug.erl
+++ b/erts/emulator/test/float_SUITE_data/has_fpe_bug.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/fun_SUITE.erl b/erts/emulator/test/fun_SUITE.erl
index 044c6aabca..26fa955e3c 100644
--- a/erts/emulator/test/fun_SUITE.erl
+++ b/erts/emulator/test/fun_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/test/fun_r13_SUITE.erl b/erts/emulator/test/fun_r13_SUITE.erl
index d66026705b..a45ed08b9d 100644
--- a/erts/emulator/test/fun_r13_SUITE.erl
+++ b/erts/emulator/test/fun_r13_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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.
diff --git a/erts/emulator/test/gc_SUITE.erl b/erts/emulator/test/gc_SUITE.erl
index 8e5f0b05a1..79c229a34d 100644
--- a/erts/emulator/test/gc_SUITE.erl
+++ b/erts/emulator/test/gc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/guard_SUITE.erl b/erts/emulator/test/guard_SUITE.erl
index 6ad4456e6b..e155e5f49f 100644
--- a/erts/emulator/test/guard_SUITE.erl
+++ b/erts/emulator/test/guard_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/hash_SUITE.erl b/erts/emulator/test/hash_SUITE.erl
index be254f5543..a39d101b0d 100644
--- a/erts/emulator/test/hash_SUITE.erl
+++ b/erts/emulator/test/hash_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2000-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.
diff --git a/erts/emulator/test/hibernate_SUITE.erl b/erts/emulator/test/hibernate_SUITE.erl
index 45f0bdc4da..6f8ce02266 100644
--- a/erts/emulator/test/hibernate_SUITE.erl
+++ b/erts/emulator/test/hibernate_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/test/ignore_cores.erl b/erts/emulator/test/ignore_cores.erl
index 7373303a39..25dce346b9 100644
--- a/erts/emulator/test/ignore_cores.erl
+++ b/erts/emulator/test/ignore_cores.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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.
@@ -94,7 +94,7 @@ setup(Suite, Testcase, Config, SetCwd) when is_atom(Suite),
end,
ok = file:write_file(filename:join([IgnDir, "ignore_core_files"]), <<>>),
%% cores are dumped in /cores on MacOS X
- CoresDir = case {test_server:os_type(), filelib:is_dir("/cores")} of
+ CoresDir = case {os:type(), filelib:is_dir("/cores")} of
{{unix,darwin}, true} ->
filelib:fold_files("/cores",
"^core.*$",
diff --git a/erts/emulator/test/list_bif_SUITE.erl b/erts/emulator/test/list_bif_SUITE.erl
index 1f64a6a8e5..514dd2f412 100644
--- a/erts/emulator/test/list_bif_SUITE.erl
+++ b/erts/emulator/test/list_bif_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/long_timers_test.erl b/erts/emulator/test/long_timers_test.erl
index 9415e1cced..7c055a31f9 100644
--- a/erts/emulator/test/long_timers_test.erl
+++ b/erts/emulator/test/long_timers_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2006-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.
diff --git a/erts/emulator/test/lttng_SUITE.erl b/erts/emulator/test/lttng_SUITE.erl
new file mode 100644
index 0000000000..efc79f42ed
--- /dev/null
+++ b/erts/emulator/test/lttng_SUITE.erl
@@ -0,0 +1,499 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2011. 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%
+%%
+
+-module(lttng_SUITE).
+
+-export([all/0, suite/0]).
+-export([init_per_suite/1, end_per_suite/1]).
+-export([init_per_testcase/2, end_per_testcase/2]).
+
+-export([t_lttng_list/1,
+ t_carrier_pool/1,
+ t_memory_carrier/1,
+ t_async_io_pool/1,
+ t_driver_control_ready_async/1,
+ t_driver_start_stop/1,
+ t_driver_ready_input_output/1,
+ t_driver_timeout/1,
+ t_driver_caller/1,
+ t_driver_flush/1,
+ t_scheduler_poll/1]).
+
+-include_lib("common_test/include/ct.hrl").
+
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap, {seconds, 10}}].
+
+all() ->
+ [t_lttng_list,
+ t_carrier_pool,
+ t_async_io_pool,
+ t_driver_start_stop,
+ t_driver_ready_input_output,
+ t_driver_control_ready_async,
+ t_driver_timeout,
+ t_driver_caller,
+ t_driver_flush,
+ t_scheduler_poll,
+ t_memory_carrier].
+
+
+init_per_suite(Config) ->
+ case erlang:system_info(dynamic_trace) of
+ lttng ->
+ ensure_lttng_stopped("--all"),
+ Config;
+ _ ->
+ {skip, "No LTTng configured on system."}
+ end.
+
+end_per_suite(_Config) ->
+ ensure_lttng_stopped("--all"),
+ ok.
+
+init_per_testcase(Case, Config) ->
+ Name = atom_to_list(Case),
+ ok = ensure_lttng_started(Name, Config),
+ [{session, Name}|Config].
+
+end_per_testcase(Case, _Config) ->
+ Name = atom_to_list(Case),
+ ok = ensure_lttng_stopped(Name),
+ ok.
+
+%% Not tested yet
+%% com_ericsson_otp:driver_process_exit
+%% com_ericsson_otp:driver_event
+
+%% tracepoints
+%%
+%% com_ericsson_otp:carrier_pool_get
+%% com_ericsson_otp:carrier_pool_put
+%% com_ericsson_otp:carrier_destroy
+%% com_ericsson_otp:carrier_create
+%% com_ericsson_otp:aio_pool_put
+%% com_ericsson_otp:aio_pool_get
+%% com_ericsson_otp:driver_control
+%% com_ericsson_otp:driver_call
+%% com_ericsson_otp:driver_finish
+%% com_ericsson_otp:driver_ready_async
+%% com_ericsson_otp:driver_process_exit
+%% com_ericsson_otp:driver_stop
+%% com_ericsson_otp:driver_flush
+%% com_ericsson_otp:driver_stop_select
+%% com_ericsson_otp:driver_timeout
+%% com_ericsson_otp:driver_event
+%% com_ericsson_otp:driver_ready_output
+%% com_ericsson_otp:driver_ready_input
+%% com_ericsson_otp:driver_output
+%% com_ericsson_otp:driver_outputv
+%% com_ericsson_otp:driver_init
+%% com_ericsson_otp:driver_start
+%% com_ericsson_otp:scheduler_poll
+
+%%
+%% Testcases
+%%
+
+t_lttng_list(_Config) ->
+ {ok, _} = cmd("lttng list -u"),
+ ok.
+
+%% com_ericsson_otp:carrier_pool_get
+%% com_ericsson_otp:carrier_pool_put
+t_carrier_pool(Config) ->
+ case have_carriers() of
+ false ->
+ {skip, "No Memory Carriers configured on system."};
+ true ->
+ ok = lttng_start_event("com_ericsson_otp:carrier_pool*", Config),
+
+ ok = ets_load(),
+
+ Res = lttng_stop_and_view(Config),
+ ok = check_tracepoint("com_ericsson_otp:carrier_pool_get", Res),
+ ok = check_tracepoint("com_ericsson_otp:carrier_pool_put", Res),
+ ok
+ end.
+
+%% com_ericsson_otp:carrier_destroy
+%% com_ericsson_otp:carrier_create
+t_memory_carrier(Config) ->
+ case have_carriers() of
+ false ->
+ {skip, "No Memory Carriers configured on system."};
+ true ->
+ ok = lttng_start_event("com_ericsson_otp:carrier_*", Config),
+
+ ok = ets_load(),
+
+ Res = lttng_stop_and_view(Config),
+ ok = check_tracepoint("com_ericsson_otp:carrier_destroy", Res),
+ ok = check_tracepoint("com_ericsson_otp:carrier_create", Res),
+ ok
+ end.
+
+%% com_ericsson_otp:aio_pool_put
+%% com_ericsson_otp:aio_pool_get
+t_async_io_pool(Config) ->
+ case have_async_threads() of
+ false ->
+ {skip, "No Async Threads configured on system."};
+ true ->
+ ok = lttng_start_event("com_ericsson_otp:aio_pool_*", Config),
+
+ Path1 = proplists:get_value(priv_dir, Config),
+ {ok, [[Path2]]} = init:get_argument(home),
+ {ok, _} = file:list_dir(Path1),
+ {ok, _} = file:list_dir(Path2),
+ {ok, _} = file:list_dir(Path1),
+ {ok, _} = file:list_dir(Path2),
+
+ Res = lttng_stop_and_view(Config),
+ ok = check_tracepoint("com_ericsson_otp:aio_pool_put", Res),
+ ok = check_tracepoint("com_ericsson_otp:aio_pool_get", Res),
+ ok
+ end.
+
+
+%% com_ericsson_otp:driver_start
+%% com_ericsson_otp:driver_stop
+t_driver_start_stop(Config) ->
+ ok = lttng_start_event("com_ericsson_otp:driver_*", Config),
+ Path = proplists:get_value(priv_dir, Config),
+ Name = filename:join(Path, "sometext.txt"),
+ Bin = txt(),
+ ok = file:write_file(Name, Bin),
+ {ok, Bin} = file:read_file(Name),
+ Res = lttng_stop_and_view(Config),
+ ok = check_tracepoint("com_ericsson_otp:driver_start", Res),
+ ok = check_tracepoint("com_ericsson_otp:driver_stop", Res),
+ ok = check_tracepoint("com_ericsson_otp:driver_control", Res),
+ ok = check_tracepoint("com_ericsson_otp:driver_outputv", Res),
+ ok = check_tracepoint("com_ericsson_otp:driver_ready_async", Res),
+ ok.
+
+%% com_ericsson_otp:driver_control
+%% com_ericsson_otp:driver_outputv
+%% com_ericsson_otp:driver_ready_async
+t_driver_control_ready_async(Config) ->
+ ok = lttng_start_event("com_ericsson_otp:driver_control", Config),
+ ok = lttng_start_event("com_ericsson_otp:driver_outputv", Config),
+ ok = lttng_start_event("com_ericsson_otp:driver_ready_async", Config),
+ Path = proplists:get_value(priv_dir, Config),
+ Name = filename:join(Path, "sometext.txt"),
+ Bin = txt(),
+ ok = file:write_file(Name, Bin),
+ {ok, Bin} = file:read_file(Name),
+ Res = lttng_stop_and_view(Config),
+ ok = check_tracepoint("com_ericsson_otp:driver_control", Res),
+ ok = check_tracepoint("com_ericsson_otp:driver_outputv", Res),
+ ok = check_tracepoint("com_ericsson_otp:driver_ready_async", Res),
+ ok.
+
+%% com_ericsson_otp:driver_ready_input
+%% com_ericsson_otp:driver_ready_output
+t_driver_ready_input_output(Config) ->
+ ok = lttng_start_event("com_ericsson_otp:driver_ready_*", Config),
+ Me = self(),
+ Pid = spawn_link(fun() -> tcp_server(Me, active) end),
+ receive {Pid, accept} -> ok end,
+ Bin = txt(),
+ Sz = byte_size(Bin),
+
+ {ok, Sock} = gen_tcp:connect("localhost", 5679, [binary, {packet, 2}]),
+ ok = gen_tcp:send(Sock, <<Sz:16, Bin/binary>>),
+ ok = gen_tcp:send(Sock, <<Sz:16, Bin/binary>>),
+ ok = gen_tcp:close(Sock),
+ receive {Pid, done} -> ok end,
+
+ Res = lttng_stop_and_view(Config),
+ ok = check_tracepoint("com_ericsson_otp:driver_ready_input", Res),
+ ok = check_tracepoint("com_ericsson_otp:driver_ready_output", Res),
+ ok.
+
+
+%% com_ericsson_otp:driver_stop_select
+%% com_ericsson_otp:driver_timeout
+t_driver_timeout(Config) ->
+ ok = lttng_start_event("com_ericsson_otp:driver_*", Config),
+ Me = self(),
+ Pid = spawn_link(fun() -> tcp_server(Me, timeout) end),
+ receive {Pid, accept} -> ok end,
+ {ok, Sock} = gen_tcp:connect("localhost", 5679, [binary]),
+ ok = gen_tcp:send(Sock, <<"hej">>),
+ receive {Pid, done} -> ok end,
+ ok = gen_tcp:close(Sock),
+ Res = lttng_stop_and_view(Config),
+ ok = check_tracepoint("com_ericsson_otp:driver_timeout", Res),
+ ok = check_tracepoint("com_ericsson_otp:driver_stop_select", Res),
+ ok.
+
+%% com_ericsson_otp:driver_call
+%% com_ericsson_otp:driver_output
+%% com_ericsson_otp:driver_init
+%% com_ericsson_otp:driver_finish
+t_driver_caller(Config) ->
+ ok = lttng_start_event("com_ericsson_otp:driver_*", Config),
+
+ Drv = 'caller_drv',
+ os:putenv("CALLER_DRV_USE_OUTPUTV", "false"),
+
+ ok = load_driver(proplists:get_value(data_dir, Config), Drv),
+ Port = open_port({spawn, Drv}, []),
+ true = is_port(Port),
+
+ chk_caller(Port, start, self()),
+ chk_caller(Port, output, spawn_link(fun() ->
+ port_command(Port, "")
+ end)),
+ Port ! {self(), {command, ""}},
+ chk_caller(Port, output, self()),
+ chk_caller(Port, control, spawn_link(fun () ->
+ port_control(Port, 0, "")
+ end)),
+ chk_caller(Port, call, spawn_link(fun() ->
+ erlang:port_call(Port, 0, "")
+ end)),
+
+ true = port_close(Port),
+ erl_ddll:unload_driver(Drv),
+
+ Res = lttng_stop_and_view(Config),
+ ok = check_tracepoint("com_ericsson_otp:driver_call", Res),
+ ok = check_tracepoint("com_ericsson_otp:driver_output", Res),
+ ok = check_tracepoint("com_ericsson_otp:driver_init", Res),
+ ok = check_tracepoint("com_ericsson_otp:driver_finish", Res),
+ ok.
+
+%% com_ericsson_otp:scheduler_poll
+t_scheduler_poll(Config) ->
+ ok = lttng_start_event("com_ericsson_otp:scheduler_poll", Config),
+
+ ok = memory_load(),
+
+ Res = lttng_stop_and_view(Config),
+ ok = check_tracepoint("com_ericsson_otp:scheduler_poll", Res),
+ ok.
+
+%% com_ericsson_otp:driver_flush
+t_driver_flush(Config) ->
+ ok = lttng_start_event("com_ericsson_otp:driver_flush", Config),
+
+ Me = self(),
+ Pid = spawn_link(fun() -> tcp_server(Me, passive_no_read) end),
+ receive {Pid, accept} -> ok end,
+ Bin = iolist_to_binary([txt() || _ <- lists:seq(1,100)]),
+ Sz = byte_size(Bin),
+
+ %% We want to create a scenario where sendings stalls and we
+ %% queue packets in the driver.
+ %% When we close the socket it has to flush the queue.
+ {ok, Sock} = gen_tcp:connect("localhost", 5679, [binary, {packet, 2},
+ {send_timeout, 10},
+ {sndbuf, 10000000}]),
+ Pids = [spawn_link(fun() ->
+ gen_tcp:send(Sock, <<Sz:16, Bin/binary>>),
+ Me ! {self(), ok}
+ end) || _ <- lists:seq(1,100)],
+ [receive {P, ok} -> ok end || P <- Pids],
+ ok = gen_tcp:close(Sock),
+ Pid ! die,
+ receive {Pid, done} -> ok end,
+
+ Res = lttng_stop_and_view(Config),
+ ok = check_tracepoint("com_ericsson_otp:driver_flush", Res),
+ ok.
+
+%%
+%% AUX
+%%
+
+chk_caller(Port, Callback, ExpectedCaller) ->
+ receive
+ {caller, Port, Callback, Caller} ->
+ ExpectedCaller = Caller
+ end.
+
+
+ets_load() ->
+ Tid = ets:new(ets_load, [public,set]),
+ N = erlang:system_info(schedulers_online),
+ Pids = [spawn_link(fun() -> ets_shuffle(Tid) end) || _ <- lists:seq(1,N)],
+ ok = ets_kill(Pids, 500),
+ ok.
+
+
+ets_kill([], _) -> ok;
+ets_kill([Pid|Pids], Time) ->
+ timer:sleep(Time),
+ Pid ! done,
+ ets_kill(Pids, Time).
+
+ets_shuffle(Tid) ->
+ Payload = lists:duplicate(100, $x),
+ ets_shuffle(Tid, 100, Payload).
+ets_shuffle(Tid, I, Data) ->
+ ets_shuffle(Tid, I, I, Data, Data).
+
+ets_shuffle(Tid, 0, N, _, Data) ->
+ ets_shuffle(Tid, N, N, Data, Data);
+ets_shuffle(Tid, I, N, Data, Data0) ->
+ receive
+ done -> ok
+ after 0 ->
+ Key = rand:uniform(1000),
+ Data1 = [I|Data],
+ ets:insert(Tid, {Key, Data1}),
+ ets_shuffle(Tid, I - 1, N, Data1, Data0)
+ end.
+
+
+
+
+memory_load() ->
+ Me = self(),
+ Pids0 = [spawn_link(fun() -> memory_loop(Me, 20, <<42>>) end) || _ <- lists:seq(1,30)],
+ timer:sleep(50),
+ Pids1 = [spawn_link(fun() -> memory_loop(Me, 20, <<42>>) end) || _ <- lists:seq(1,30)],
+ [receive {Pid, done} -> ok end || Pid <- Pids0 ++ Pids1],
+ timer:sleep(500),
+ ok.
+
+memory_loop(Parent, N, Bin) ->
+ memory_loop(Parent, N, Bin, []).
+
+memory_loop(Parent, 0, _Bin, _) ->
+ Parent ! {self(), done};
+memory_loop(Parent, N, Bin0, Ls) ->
+ Bin = binary:copy(<<Bin0/binary, Bin0/binary>>),
+ memory_loop(Parent, N - 1, Bin, [a,b,c|Ls]).
+
+tcp_server(Pid, Type) ->
+ {ok, LSock} = gen_tcp:listen(5679, [binary,
+ {reuseaddr, true},
+ {active, false}]),
+ Pid ! {self(), accept},
+ {ok, Sock} = gen_tcp:accept(LSock),
+ case Type of
+ passive_no_read ->
+ receive die -> ok end;
+ active ->
+ inet:setopts(Sock, [{active, once}, {packet,2}]),
+ receive Msg1 -> io:format("msg1: ~p~n", [Msg1]) end,
+ inet:setopts(Sock, [{active, once}, {packet,2}]),
+ receive Msg2 -> io:format("msg2: ~p~n", [Msg2]) end,
+ ok = gen_tcp:close(Sock);
+ timeout ->
+ Res = gen_tcp:recv(Sock, 2000, 1000),
+ io:format("res ~p~n", [Res])
+ end,
+ Pid ! {self(), done},
+ ok.
+
+txt() ->
+ <<"%% tracepoints\n"
+ "%%\n"
+ "%% com_ericsson_otp:carrier_pool_get\n"
+ "%% com_ericsson_otp:carrier_pool_put\n"
+ "%% com_ericsson_otp:carrier_destroy\n"
+ "%% com_ericsson_otp:carrier_create\n"
+ "%% com_ericsson_otp:aio_pool_put\n"
+ "%% com_ericsson_otp:aio_pool_get\n"
+ "%% com_ericsson_otp:driver_control\n"
+ "%% com_ericsson_otp:driver_call\n"
+ "%% com_ericsson_otp:driver_finish\n"
+ "%% com_ericsson_otp:driver_ready_async\n"
+ "%% com_ericsson_otp:driver_process_exit\n"
+ "%% com_ericsson_otp:driver_stop\n"
+ "%% com_ericsson_otp:driver_flush\n"
+ "%% com_ericsson_otp:driver_stop_select\n"
+ "%% com_ericsson_otp:driver_timeout\n"
+ "%% com_ericsson_otp:driver_event\n"
+ "%% com_ericsson_otp:driver_ready_output\n"
+ "%% com_ericsson_otp:driver_ready_input\n"
+ "%% com_ericsson_otp:driver_output\n"
+ "%% com_ericsson_otp:driver_outputv\n"
+ "%% com_ericsson_otp:driver_init\n"
+ "%% com_ericsson_otp:driver_start\n"
+ "%% com_ericsson_otp:scheduler_poll">>.
+
+load_driver(Dir, Driver) ->
+ case erl_ddll:load_driver(Dir, Driver) of
+ ok -> ok;
+ {error, Error} = Res ->
+ io:format("~s\n", [erl_ddll:format_error(Error)]),
+ Res
+ end.
+
+%% check
+
+have_carriers() ->
+ Cap = element(3,erlang:system_info(allocator)),
+ case Cap -- [sys_alloc,sys_aligned_alloc] of
+ [] -> false;
+ _ -> true
+ end.
+
+have_async_threads() ->
+ Tps = erlang:system_info(thread_pool_size),
+ if Tps =:= 0 -> false;
+ true -> true
+ end.
+
+%% lttng
+lttng_stop_and_view(Config) ->
+ Path = proplists:get_value(priv_dir, Config),
+ Name = proplists:get_value(session, Config),
+ {ok,_} = cmd("lttng stop " ++ Name),
+ {ok,Res} = cmd("lttng view " ++ Name ++ " --trace-path=" ++ Path),
+ Res.
+
+check_tracepoint(TP, Data) ->
+ case re:run(Data, TP, [global]) of
+ {match, _} -> ok;
+ _ -> notfound
+ end.
+
+lttng_start_event(Event, Config) ->
+ Name = proplists:get_value(session, Config),
+ {ok, _} = cmd("lttng enable-event -u " ++ Event ++ " --session=" ++ Name),
+ {ok, _} = cmd("lttng start " ++ Name),
+ ok.
+
+ensure_lttng_started(Name, Config) ->
+ Out = case proplists:get_value(priv_dir, Config) of
+ undefined -> [];
+ Path -> "--output="++Path++" "
+ end,
+ {ok,_} = cmd("lttng create " ++ Out ++ Name),
+ ok.
+
+ensure_lttng_stopped(Name) ->
+ {ok,_} = cmd("lttng stop"),
+ {ok,_} = cmd("lttng destroy " ++ Name),
+ ok.
+
+cmd(Cmd) ->
+ io:format("<< ~ts~n", [Cmd]),
+ Res = os:cmd(Cmd),
+ io:format(">> ~ts~n", [Res]),
+ {ok,Res}.
diff --git a/erts/emulator/test/lttng_SUITE_data/Makefile.src b/erts/emulator/test/lttng_SUITE_data/Makefile.src
new file mode 100644
index 0000000000..fe7a1b6ef3
--- /dev/null
+++ b/erts/emulator/test/lttng_SUITE_data/Makefile.src
@@ -0,0 +1,7 @@
+
+MISC_DRVS = caller_drv@dll@
+
+
+all: $(MISC_DRVS)
+
+@SHLIB_RULES@
diff --git a/erts/emulator/test/lttng_SUITE_data/caller_drv.c b/erts/emulator/test/lttng_SUITE_data/caller_drv.c
new file mode 100644
index 0000000000..86fd0a2995
--- /dev/null
+++ b/erts/emulator/test/lttng_SUITE_data/caller_drv.c
@@ -0,0 +1,159 @@
+/* ``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.
+ *
+ * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+ * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+ * AB. All Rights Reserved.''
+ *
+ * $Id$
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "erl_driver.h"
+
+static int init();
+static void stop(ErlDrvData drv_data);
+static void finish();
+static void flush(ErlDrvData drv_data);
+static ErlDrvData start(ErlDrvPort port, char *command);
+static void output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len);
+static void outputv(ErlDrvData drv_data, ErlIOVec *ev);
+static ErlDrvSSizeT control(ErlDrvData drv_data,
+ unsigned int command, char *buf,
+ ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen);
+static ErlDrvSSizeT call(ErlDrvData drv_data,
+ unsigned int command,
+ char *buf, ErlDrvSizeT len,
+ char **rbuf, ErlDrvSizeT rlen,
+ unsigned int *flags);
+
+static ErlDrvEntry caller_drv_entry = {
+ init,
+ start,
+ stop,
+ output,
+ NULL /* ready_input */,
+ NULL /* ready_output */,
+ "caller_drv",
+ finish,
+ NULL /* handle */,
+ control,
+ NULL /* timeout */,
+ outputv,
+ NULL /* ready_async */,
+ flush,
+ call,
+ NULL /* event */,
+ ERL_DRV_EXTENDED_MARKER,
+ ERL_DRV_EXTENDED_MAJOR_VERSION,
+ ERL_DRV_EXTENDED_MINOR_VERSION,
+ ERL_DRV_FLAG_USE_PORT_LOCKING,
+ NULL /* handle2 */,
+ NULL /* handle_monitor */
+};
+
+DRIVER_INIT(caller_drv)
+{
+ char buf[10];
+ size_t bufsz = sizeof(buf);
+ char *use_outputv;
+ use_outputv = (erl_drv_getenv("CALLER_DRV_USE_OUTPUTV", buf, &bufsz) == 0
+ ? buf
+ : "false");
+ if (strcmp(use_outputv, "true") != 0)
+ caller_drv_entry.outputv = NULL;
+ return &caller_drv_entry;
+}
+
+void
+send_caller(ErlDrvData drv_data, char *func)
+{
+ int res;
+ ErlDrvPort port = (ErlDrvPort) drv_data;
+ ErlDrvTermData msg[] = {
+ ERL_DRV_ATOM, driver_mk_atom("caller"),
+ ERL_DRV_PORT, driver_mk_port(port),
+ ERL_DRV_ATOM, driver_mk_atom(func),
+ ERL_DRV_PID, driver_caller(port),
+ ERL_DRV_TUPLE, (ErlDrvTermData) 4
+ };
+ res = erl_drv_output_term(driver_mk_port(port), msg, sizeof(msg)/sizeof(ErlDrvTermData));
+ if (res <= 0)
+ driver_failure_atom(port, "erl_drv_output_term failed");
+}
+
+static int
+init() {
+ return 0;
+}
+
+static void
+stop(ErlDrvData drv_data)
+{
+
+}
+
+static void
+flush(ErlDrvData drv_data)
+{
+
+}
+
+static void
+finish()
+{
+
+}
+
+static ErlDrvData
+start(ErlDrvPort port, char *command)
+{
+ send_caller((ErlDrvData) port, "start");
+ return (ErlDrvData) port;
+}
+
+static void
+output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len)
+{
+ send_caller(drv_data, "output");
+}
+
+static void
+outputv(ErlDrvData drv_data, ErlIOVec *ev)
+{
+ send_caller(drv_data, "outputv");
+}
+
+static ErlDrvSSizeT
+control(ErlDrvData drv_data,
+ unsigned int command, char *buf,
+ ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen)
+{
+ send_caller(drv_data, "control");
+ return 0;
+}
+
+static ErlDrvSSizeT
+call(ErlDrvData drv_data,
+ unsigned int command,
+ char *buf, ErlDrvSizeT len,
+ char **rbuf, ErlDrvSizeT rlen,
+ unsigned int *flags)
+{
+ /* echo call */
+ if (len > rlen)
+ *rbuf = driver_alloc(len);
+ memcpy((void *) *rbuf, (void *) buf, len);
+ send_caller(drv_data, "call");
+ return len;
+}
diff --git a/erts/emulator/test/map_SUITE.erl b/erts/emulator/test/map_SUITE.erl
index 956b82335c..b3870f0313 100644
--- a/erts/emulator/test/map_SUITE.erl
+++ b/erts/emulator/test/map_SUITE.erl
@@ -48,6 +48,7 @@
t_bif_map_new/1,
t_bif_map_put/1,
t_bif_map_remove/1,
+ t_bif_map_take/1, t_bif_map_take_large/1,
t_bif_map_update/1,
t_bif_map_values/1,
t_bif_map_to_list/1,
@@ -112,7 +113,9 @@ all() -> [t_build_and_match_literals, t_build_and_match_literals_large,
t_bif_map_get,t_bif_map_find,t_bif_map_is_key,
t_bif_map_keys, t_bif_map_merge, t_bif_map_new,
t_bif_map_put,
- t_bif_map_remove, t_bif_map_update,
+ t_bif_map_remove,
+ t_bif_map_take, t_bif_map_take_large,
+ t_bif_map_update,
t_bif_map_values,
t_bif_map_to_list, t_bif_map_from_list,
@@ -1970,7 +1973,7 @@ t_bif_map_remove(Config) when is_list(Config) ->
0 = erlang:map_size(maps:remove(some_key, #{})),
M0 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
- 4 => number, 18446744073709551629 => wat},
+ 4 => number, 18446744073709551629 => wat},
M1 = maps:remove("hi", M0),
true = is_members([4,18446744073709551629,int,<<"key">>],maps:keys(M1)),
@@ -1999,10 +2002,71 @@ t_bif_map_remove(Config) when is_list(Config) ->
%% error case
do_badmap(fun(T) ->
- {'EXIT',{{badmap,T},[{maps,remove,_,_}|_]}} =
- (catch maps:remove(a, T))
+ {'EXIT',{{badmap,T},[{maps,remove,_,_}|_]}} = (catch maps:remove(a, T))
end),
- ok.
+ ok.
+
+t_bif_map_take(Config) when is_list(Config) ->
+ error = maps:take(some_key, #{}),
+
+ M0 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
+ 4 => number, 18446744073709551629 => wat},
+
+ 5 = maps:size(M0),
+ {"hello", M1} = maps:take("hi", M0),
+ true = is_members([4,18446744073709551629,int,<<"key">>],maps:keys(M1)),
+ true = is_members([number,wat,3,<<"value">>],maps:values(M1)),
+ error = maps:take("hi", M1),
+ 4 = maps:size(M1),
+
+ {3, M2} = maps:take(int, M1),
+ true = is_members([4,18446744073709551629,<<"key">>],maps:keys(M2)),
+ true = is_members([number,wat,<<"value">>],maps:values(M2)),
+ error = maps:take(int, M2),
+ 3 = maps:size(M2),
+
+ {<<"value">>,M3} = maps:take(<<"key">>, M2),
+ true = is_members([4,18446744073709551629],maps:keys(M3)),
+ true = is_members([number,wat],maps:values(M3)),
+ error = maps:take(<<"key">>, M3),
+ 2 = maps:size(M3),
+
+ {wat,M4} = maps:take(18446744073709551629, M3),
+ true = is_members([4],maps:keys(M4)),
+ true = is_members([number],maps:values(M4)),
+ error = maps:take(18446744073709551629, M4),
+ 1 = maps:size(M4),
+
+ {number,M5} = maps:take(4, M4),
+ [] = maps:keys(M5),
+ [] = maps:values(M5),
+ error = maps:take(4, M5),
+ 0 = maps:size(M5),
+
+ {wat,#{ "hi" := "hello", int := 3, 4 := number, <<"key">> := <<"value">>}} = maps:take(18446744073709551629,M0),
+
+ %% error case
+ do_badmap(fun(T) ->
+ {'EXIT',{{badmap,T},[{maps,take,_,_}|_]}} = (catch maps:take(a, T))
+ end),
+ ok.
+
+t_bif_map_take_large(Config) when is_list(Config) ->
+ KVs = [{{erlang:md5(<<I:64>>),I}, I}|| I <- lists:seq(1,500)],
+ M0 = maps:from_list(KVs),
+ ok = bif_map_take_all(KVs, M0),
+ ok.
+
+bif_map_take_all([], M0) ->
+ 0 = maps:size(M0),
+ ok;
+bif_map_take_all([{K,V}|KVs],M0) ->
+ {ok,V} = maps:find(K,M0),
+ {V,M1} = maps:take(K,M0),
+ error = maps:find(K,M1),
+ error = maps:take(K,M1),
+ bif_map_take_all(KVs,M1).
+
t_bif_map_update(Config) when is_list(Config) ->
M0 = #{ "hi" => "hello", int => 3, <<"key">> => <<"value">>,
diff --git a/erts/emulator/test/match_spec_SUITE.erl b/erts/emulator/test/match_spec_SUITE.erl
index baa6eb8fe0..6733237b20 100644
--- a/erts/emulator/test/match_spec_SUITE.erl
+++ b/erts/emulator/test/match_spec_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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.
@@ -23,7 +23,7 @@
-export([all/0, suite/0, not_run/1]).
-export([test_1/1, test_2/1, test_3/1, bad_match_spec_bin/1,
trace_control_word/1, silent/1, silent_no_ms/1, silent_test/1,
- ms_trace2/1, ms_trace3/1, boxed_and_small/1,
+ ms_trace2/1, ms_trace3/1, ms_trace_dead/1, boxed_and_small/1,
destructive_in_test_bif/1, guard_exceptions/1,
empty_list/1,
unary_plus/1, unary_minus/1, moving_labels/1]).
@@ -49,7 +49,7 @@ all() ->
false ->
[test_1, test_2, test_3, bad_match_spec_bin,
trace_control_word, silent, silent_no_ms, silent_test, ms_trace2,
- ms_trace3, boxed_and_small, destructive_in_test_bif,
+ ms_trace3, ms_trace_dead, boxed_and_small, destructive_in_test_bif,
guard_exceptions, unary_plus, unary_minus, fpe,
moving_labels,
faulty_seq_trace,
@@ -500,6 +500,8 @@ ms_trace2(Config) when is_list(Config) ->
[[call,return_to],[]]},
ms_trace2}]
end),
+ %% Silence valgrind
+ erlang:trace_pattern({?MODULE,fn,'_'},[],[]),
ok.
@@ -595,7 +597,32 @@ ms_trace3(Config) when is_list(Config) ->
end),
ok.
-
+%% Test that a dead tracer is removed using ms
+ms_trace_dead(_Config) ->
+ Self = self(),
+ TFun = fun F() -> receive M -> Self ! M, F() end end,
+ {Tracer, MRef} = spawn_monitor(TFun),
+ MetaTracer = spawn_link(TFun),
+ erlang:trace_pattern({?MODULE, f1, '_'},
+ [{'_',[],[{message, false},
+ {trace,[],
+ [call,{const,{tracer,Tracer}}]}]}],
+ [{meta, MetaTracer}]),
+ erlang:trace_pattern({?MODULE, f2, '_'}, []),
+ ?MODULE:f2(1,2),
+ ?MODULE:f1(1),
+ {tracer,Tracer} = erlang:trace_info(self(), tracer),
+ {flags,[call]} = erlang:trace_info(self(), flags),
+ ?MODULE:f2(2,3),
+ receive {trace, Self, call, {?MODULE, f2, _}} -> ok end,
+ exit(Tracer, stop),
+ receive {'DOWN',MRef,_,_,_} -> ok end,
+ ?MODULE:f1(2),
+ {tracer,[]} = erlang:trace_info(self(), tracer),
+ ?MODULE:f2(3,4),
+ TRef = erlang:trace_delivered(all),
+ receive {trace_delivered, _, TRef} -> ok end,
+ receive M -> ct:fail({unexpected, M}) after 10 -> ok end.
%% Test that destructive operations in test bif does not really happen
destructive_in_test_bif(Config) when is_list(Config) ->
@@ -905,34 +932,40 @@ collect([]) ->
collect([TM | TMs]) ->
io:format( "Expecting: ~p~n", [TM]),
receive
- M0 ->
- M = case element(1, M0) of
- trace_ts ->
- list_to_tuple(lists:reverse(
- tl(lists:reverse(tuple_to_list(M0)))));
- _ -> M0
- end,
- case is_function(TM,1) of
- true ->
- case (catch TM(M)) of
- true ->
- io:format("Got: ~p~n", [M]),
- collect(TMs);
- _ ->
- io:format("Got unexpected: ~p~n", [M]),
- flush({got_unexpected,M})
- end;
-
- false ->
- case M of
- TM ->
- io:format("Got: ~p~n", [M]),
- collect(TMs);
- _ ->
- io:format("Got unexpected: ~p~n", [M]),
- flush({got_unexpected,M})
- end
- end
+ %% We only look at trace messages with the same tracee
+ %% as the message we are looking for. This because
+ %% the order of trace messages is only guaranteed from
+ %% within a single process.
+ M0 when element(2, M0) =:= element(2, TM); is_function(TM, 1) ->
+ M = case element(1, M0) of
+ trace_ts ->
+ list_to_tuple(lists:reverse(
+ tl(lists:reverse(tuple_to_list(M0)))));
+ _ -> M0
+ end,
+ case is_function(TM,1) of
+ true ->
+ case (catch TM(M)) of
+ true ->
+ io:format("Got: ~p~n", [M]),
+ collect(TMs);
+ _ ->
+ io:format("Got unexpected: ~p~n", [M]),
+ flush({got_unexpected,M})
+ end;
+
+ false ->
+ case M of
+ TM ->
+ io:format("Got: ~p~n", [M]),
+ collect(TMs);
+ _ ->
+ io:format("Got unexpected: ~p~n", [M]),
+ flush({got_unexpected,M})
+ end
+ end
+ after 15000 ->
+ flush(timeout)
end.
flush(Reason) ->
diff --git a/erts/emulator/test/message_queue_data_SUITE.erl b/erts/emulator/test/message_queue_data_SUITE.erl
index 12c42d24aa..226462676c 100644
--- a/erts/emulator/test/message_queue_data_SUITE.erl
+++ b/erts/emulator/test/message_queue_data_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014. All Rights Reserved.
+%% Copyright Ericsson AB 2014-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.
@@ -21,7 +21,7 @@
-module(message_queue_data_SUITE).
-export([all/0, suite/0]).
--export([basic/1, process_info_messages/1]).
+-export([basic/1, process_info_messages/1, total_heap_size/1]).
-export([basic_test/1]).
@@ -32,7 +32,7 @@ suite() ->
{timetrap, {minutes, 2}}].
all() ->
- [basic, process_info_messages].
+ [basic, process_info_messages, total_heap_size].
%%
%%
@@ -44,15 +44,15 @@ basic(Config) when is_list(Config) ->
basic_test(erlang:system_info(message_queue_data)),
- {ok, Node1} = start_node(Config, "+xmqd off_heap"),
+ {ok, Node1} = start_node(Config, "+hmqd off_heap"),
ok = rpc:call(Node1, ?MODULE, basic_test, [off_heap]),
stop_node(Node1),
- {ok, Node2} = start_node(Config, "+xmqd on_heap"),
+ {ok, Node2} = start_node(Config, "+hmqd on_heap"),
ok = rpc:call(Node2, ?MODULE, basic_test, [on_heap]),
stop_node(Node2),
- {ok, Node3} = start_node(Config, "+xmqd mixed"),
+ {ok, Node3} = start_node(Config, "+hmqd mixed"),
ok = rpc:call(Node3, ?MODULE, basic_test, [mixed]),
stop_node(Node3),
@@ -190,6 +190,28 @@ process_info_messages(Config) when is_list(Config) ->
ok.
+total_heap_size(_Config) ->
+
+ Fun = fun F() -> receive Pid when is_pid(Pid) -> Pid ! ok,F() end end,
+
+ %% Test that on_heap messages grow the heap even if they are not received
+ OnPid = spawn_opt(Fun, [{message_queue_data, on_heap}]),
+ {total_heap_size, OnSize} = erlang:process_info(OnPid, total_heap_size),
+ [OnPid ! lists:duplicate(N,N) || N <- lists:seq(1,100)],
+ OnPid ! self(), receive ok -> ok end,
+ {total_heap_size, OnSizeAfter} = erlang:process_info(OnPid, total_heap_size),
+ ct:log("OnSize = ~p, OnSizeAfter = ~p",[OnSize, OnSizeAfter]),
+ true = OnSize < OnSizeAfter,
+
+ %% Test that off_heap messages do not grow the heap if they are not received
+ OffPid = spawn_opt(Fun, [{message_queue_data, off_heap}]),
+ {total_heap_size, OffSize} = erlang:process_info(OffPid, total_heap_size),
+ [OffPid ! lists:duplicate(N,N) || N <- lists:seq(1,100)],
+ OffPid ! self(), receive ok -> ok end,
+ {total_heap_size, OffSizeAfter} = erlang:process_info(OffPid, total_heap_size),
+ ct:log("OffSize = ~p, OffSizeAfter = ~p",[OffSize, OffSizeAfter]),
+ true = OffSize == OffSizeAfter.
+
%%
%%
%% helpers
diff --git a/erts/emulator/test/module_info_SUITE.erl b/erts/emulator/test/module_info_SUITE.erl
index f8208c5866..ba9b564fdc 100644
--- a/erts/emulator/test/module_info_SUITE.erl
+++ b/erts/emulator/test/module_info_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/test/monitor_SUITE.erl b/erts/emulator/test/monitor_SUITE.erl
index 82e3a36c1e..8955e62df5 100644
--- a/erts/emulator/test/monitor_SUITE.erl
+++ b/erts/emulator/test/monitor_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/test/mtx_SUITE.erl b/erts/emulator/test/mtx_SUITE.erl
index a17b11f3bf..1493e52655 100644
--- a/erts/emulator/test/mtx_SUITE.erl
+++ b/erts/emulator/test/mtx_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
+%% 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.
diff --git a/erts/emulator/test/mtx_SUITE_data/Makefile.src b/erts/emulator/test/mtx_SUITE_data/Makefile.src
index dc880118f1..1816dc6798 100644
--- a/erts/emulator/test/mtx_SUITE_data/Makefile.src
+++ b/erts/emulator/test/mtx_SUITE_data/Makefile.src
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2013. All Rights Reserved.
+# 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.
diff --git a/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c b/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c
index 1911291448..e011aadce9 100644
--- a/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c
+++ b/erts/emulator/test/mtx_SUITE_data/mtx_SUITE.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2011. All Rights Reserved.
+ * 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.
diff --git a/erts/emulator/test/multi_load_SUITE.erl b/erts/emulator/test/multi_load_SUITE.erl
index 784b239116..edf3205812 100644
--- a/erts/emulator/test/multi_load_SUITE.erl
+++ b/erts/emulator/test/multi_load_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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.
@@ -19,32 +19,16 @@
%%
-module(multi_load_SUITE).
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- many/1,on_load/1,errors/1]).
+-export([all/0, suite/0, many/1, on_load/1, errors/1]).
-include_lib("common_test/include/ct.hrl").
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() ->
+ [{ct_hooks,[ts_install_cth]}].
all() ->
[many,on_load,errors].
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
many(_Config) ->
Ms = make_modules(100, fun many_module/1),
@@ -57,7 +41,6 @@ many(_Config) ->
io:put_chars("Heavy load\n"
"=========="),
many_measure(Ms),
-
ok.
many_module(M) ->
@@ -81,9 +64,12 @@ many_measure(Ms) ->
"Sequential: ~9w µs\n"
"Parallel: ~9w µs\n"
"Ratio: ~9w\n",
- [length(Ms),Us1,Us2,round(Us1/Us2)]),
+ [length(Ms),Us1,Us2,divide(Us1,Us2)]),
ok.
+divide(A,B) when B > 0 -> A div B;
+divide(_,_) -> inf.
+
many_load_seq(Ms) ->
[erlang:finish_loading([M]) || M <- Ms],
ok.
@@ -135,7 +121,6 @@ on_load(_Config) ->
SingleOnPrep = tl(OnPrep),
{on_load,[OnLoadMod]} = erlang:finish_loading(SingleOnPrep),
ok = erlang:call_on_load_function(OnLoadMod),
-
ok.
on_load_module(M) ->
diff --git a/erts/emulator/test/nested_SUITE.erl b/erts/emulator/test/nested_SUITE.erl
index c13e19f857..7af2873ce2 100644
--- a/erts/emulator/test/nested_SUITE.erl
+++ b/erts/emulator/test/nested_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index 84f5699890..a7767132ee 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2014. All Rights Reserved.
+%% 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.
@@ -42,7 +42,12 @@
dirty_nif_exception/1, call_dirty_nif_exception/1, nif_schedule/1,
nif_exception/1, call_nif_exception/1,
nif_nan_and_inf/1, nif_atom_too_long/1,
- nif_monotonic_time/1, nif_time_offset/1, nif_convert_time_unit/1]).
+ nif_monotonic_time/1, nif_time_offset/1, nif_convert_time_unit/1,
+ nif_now_time/1, nif_cpu_time/1, nif_unique_integer/1,
+ nif_is_process_alive/1, nif_is_port_alive/1,
+ nif_term_to_binary/1, nif_binary_to_term/1,
+ nif_port_command/1
+ ]).
-export([many_args_100/100]).
@@ -72,7 +77,11 @@ all() ->
otp_9668, consume_timeslice,
nif_schedule, dirty_nif, dirty_nif_send, dirty_nif_exception,
nif_exception, nif_nan_and_inf, nif_atom_too_long,
- nif_monotonic_time, nif_time_offset, nif_convert_time_unit
+ nif_monotonic_time, nif_time_offset, nif_convert_time_unit,
+ nif_now_time, nif_cpu_time, nif_unique_integer,
+ nif_is_process_alive, nif_is_port_alive,
+ nif_term_to_binary, nif_binary_to_term,
+ nif_port_command
].
init_per_testcase(_Case, Config) ->
@@ -1273,9 +1282,10 @@ send3_make_blob() ->
repeat(N bsr 1,
fun(_) -> grow_blob(MsgEnv,other_term(),rand:uniform(1 bsl 20))
end, void),
- case (N band 1) of
+ case (N band 3) of
0 -> {term,copy_blob(MsgEnv)};
- 1 -> {msgenv,MsgEnv}
+ 1 -> {copy,copy_blob(MsgEnv)};
+ _ -> {msgenv,MsgEnv}
end
end.
@@ -1288,6 +1298,9 @@ send3_send(Pid, Msg) ->
send3_send_nif(Pid, {term,Blob}) ->
%%io:format("~p send term nif\n",[self()]),
send_term(Pid, {blob, Blob}) =:= 1;
+send3_send_nif(Pid, {copy,Blob}) ->
+ %%io:format("~p send term nif\n",[self()]),
+ send_copy_term(Pid, {blob, Blob}) =:= 1;
send3_send_nif(Pid, {msgenv,MsgEnv}) ->
%%io:format("~p send blob nif\n",[self()]),
send3_blob(MsgEnv, Pid, blob) =:= 1.
@@ -1296,6 +1309,10 @@ send3_send_bang(Pid, {term,Blob}) ->
%%io:format("~p send term bang\n",[self()]),
Pid ! {blob, Blob},
true;
+send3_send_bang(Pid, {copy,Blob}) ->
+ %%io:format("~p send term bang\n",[self()]),
+ Pid ! {blob, Blob},
+ true;
send3_send_bang(Pid, {msgenv,MsgEnv}) ->
%%io:format("~p send blob bang\n",[self()]),
Pid ! {blob, copy_blob(MsgEnv)},
@@ -1365,14 +1382,16 @@ get_length(Config) when is_list(Config) ->
ensure_lib_loaded(Config) ->
ensure_lib_loaded(Config, 1).
ensure_lib_loaded(Config, Ver) ->
+ Path = ?config(data_dir, Config),
case lib_version() of
- undefined ->
- Path = proplists:get_value(data_dir, Config),
- Lib = "nif_SUITE." ++ integer_to_list(Ver),
- ok = erlang:load_nif(filename:join(Path,Lib), []);
- Ver when is_integer(Ver) ->
- ok
- end.
+ undefined ->
+ Lib = "nif_SUITE." ++ integer_to_list(Ver),
+ ok = erlang:load_nif(filename:join(Path,Lib), []);
+ Ver when is_integer(Ver) ->
+ ok
+ end,
+ erl_ddll:try_load(Path, echo_drv, []),
+ ok.
make_atom(Config) when is_list(Config) ->
ensure_lib_loaded(Config, 1),
@@ -1885,6 +1904,129 @@ chk_ctu(Time, FromTU, [ToTU|ToTUs]) ->
chk_ctu(Time, FromTU, ToTUs)
end.
+nif_now_time(Config) ->
+ ensure_lib_loaded(Config),
+
+ N1 = now(),
+ NifN1 = now_time(),
+ NifN2 = now_time(),
+ N2 = now(),
+ true = N1 < NifN1,
+ true = NifN1 < NifN2,
+ true = NifN2 < N2.
+
+nif_cpu_time(Config) ->
+ ensure_lib_loaded(Config),
+
+ try cpu_time() of
+ {_, _, _} ->
+ ok
+ catch error:badarg ->
+ {comment, "cpu_time not supported"}
+ end.
+
+nif_unique_integer(Config) ->
+ ensure_lib_loaded(Config),
+
+ UM1 = erlang:unique_integer([monotonic]),
+ UM2 = unique_integer_nif([monotonic]),
+ UM3 = erlang:unique_integer([monotonic]),
+
+ true = UM1 < UM2,
+ true = UM2 < UM3,
+
+ UMP1 = erlang:unique_integer([monotonic, positive]),
+ UMP2 = unique_integer_nif([monotonic, positive]),
+ UMP3 = erlang:unique_integer([monotonic, positive]),
+
+ true = 0 =< UMP1,
+ true = UMP1 < UMP2,
+ true = UMP2 < UMP3,
+
+ UP1 = erlang:unique_integer([positive]),
+ UP2 = unique_integer_nif([positive]),
+ UP3 = erlang:unique_integer([positive]),
+
+ true = 0 =< UP1,
+ true = 0 =< UP2,
+ true = 0 =< UP3,
+
+ true = is_integer(unique_integer_nif([])),
+ true = is_integer(unique_integer_nif([])),
+ true = is_integer(unique_integer_nif([])).
+
+nif_is_process_alive(Config) ->
+ ensure_lib_loaded(Config),
+
+ {Pid,_} = spawn_monitor(fun() -> receive ok -> nok end end),
+ true = is_process_alive_nif(Pid),
+ exit(Pid, die),
+ receive _ -> ok end, %% Clear monitor
+ false = is_process_alive_nif(Pid).
+
+nif_is_port_alive(Config) ->
+ ensure_lib_loaded(Config),
+
+ Port = open_port({spawn,echo_drv},[eof]),
+ true = is_port_alive_nif(Port),
+ port_close(Port),
+ false = is_port_alive_nif(Port).
+
+nif_term_to_binary(Config) ->
+ ensure_lib_loaded(Config),
+ T = {#{ok => nok}, <<0:8096>>, lists:seq(1,100)},
+ Bin = term_to_binary(T),
+ ct:log("~p",[Bin]),
+ Bin = term_to_binary_nif(T, undefined),
+ true = term_to_binary_nif(T, self()),
+ receive Bin -> ok end.
+
+-define(ERL_NIF_BIN2TERM_SAFE, 16#20000000).
+
+nif_binary_to_term(Config) ->
+ ensure_lib_loaded(Config),
+ T = {#{ok => nok}, <<0:8096>>, lists:seq(1,100)},
+ Bin = term_to_binary(T),
+ Len = byte_size(Bin),
+ {Len,T} = binary_to_term_nif(Bin, undefined, 0),
+ Len = binary_to_term_nif(Bin, self(), 0),
+ T = receive M -> M after 1000 -> timeout end,
+
+ {Len, T} = binary_to_term_nif(Bin, undefined, ?ERL_NIF_BIN2TERM_SAFE),
+ false = binary_to_term_nif(<<131,100,0,14,"undefined_atom">>,
+ undefined, ?ERL_NIF_BIN2TERM_SAFE),
+ false = binary_to_term_nif(Bin, undefined, 1),
+ ok.
+
+nif_port_command(Config) ->
+ ensure_lib_loaded(Config),
+
+ Port = open_port({spawn,echo_drv},[eof]),
+ true = port_command_nif(Port, "hello\n"),
+ receive {Port,{data,"hello\n"}} -> ok
+ after 1000 -> ct:fail(timeout) end,
+
+ RefcBin = lists:flatten([lists:duplicate(100, "hello"),"\n"]),
+ true = port_command_nif(Port, iolist_to_binary(RefcBin)),
+ receive {Port,{data,RefcBin}} -> ok
+ after 1000 -> ct:fail(timeout) end,
+
+ %% Test that invalid arguments correctly returns
+ %% badarg and that the port survives.
+ {'EXIT', {badarg, _}} = (catch port_command_nif(Port, [ok])),
+
+ IoList = [lists:duplicate(100,<<"hello">>),"\n"],
+ true = port_command_nif(Port, [IoList]),
+ FlatIoList = binary_to_list(iolist_to_binary(IoList)),
+ receive {Port,{data,FlatIoList}} -> ok
+ after 1000 -> ct:fail(timeout) end,
+
+ port_close(Port),
+
+ {'EXIT', {badarg, _}} = (catch port_command_nif(Port, "hello\n")),
+
+ ok.
+
%% The NIFs:
lib_version() -> undefined.
call_history() -> ?nif_stub.
@@ -1928,6 +2070,7 @@ send_blob_thread(_,_,_) -> ?nif_stub.
join_send_thread(_) -> ?nif_stub.
copy_blob(_) -> ?nif_stub.
send_term(_,_) -> ?nif_stub.
+send_copy_term(_,_) -> ?nif_stub.
reverse_list(_) -> ?nif_stub.
echo_int(_) -> ?nif_stub.
type_sizes() -> ?nif_stub.
@@ -1942,6 +2085,12 @@ call_dirty_nif_zero_args() -> ?nif_stub.
call_nif_exception(_) -> ?nif_stub.
call_nif_nan_or_inf(_) -> ?nif_stub.
call_nif_atom_too_long(_) -> ?nif_stub.
+unique_integer_nif(_) -> ?nif_stub.
+is_process_alive_nif(_) -> ?nif_stub.
+is_port_alive_nif(_) -> ?nif_stub.
+term_to_binary_nif(_, _) -> ?nif_stub.
+binary_to_term_nif(_, _, _) -> ?nif_stub.
+port_command_nif(_, _) -> ?nif_stub.
%% maps
is_map_nif(_) -> ?nif_stub.
@@ -1958,7 +2107,8 @@ sorted_list_from_maps_nif(_) -> ?nif_stub.
monotonic_time(_) -> ?nif_stub.
time_offset(_) -> ?nif_stub.
convert_time_unit(_,_,_) -> ?nif_stub.
-
+now_time() -> ?nif_stub.
+cpu_time() -> ?nif_stub.
nif_stub_error(Line) ->
exit({nif_not_loaded,module,?MODULE,line,Line}).
diff --git a/erts/emulator/test/nif_SUITE_data/Makefile.src b/erts/emulator/test/nif_SUITE_data/Makefile.src
index ab4ff77add..fbb8978771 100644
--- a/erts/emulator/test/nif_SUITE_data/Makefile.src
+++ b/erts/emulator/test/nif_SUITE_data/Makefile.src
@@ -4,8 +4,7 @@ NIF_LIBS = nif_SUITE.1@dll@ \
nif_mod.2@dll@ \
nif_mod.3@dll@
-all: $(NIF_LIBS) basic@dll@ rwlock@dll@ tsd@dll@
-
+all: $(NIF_LIBS) basic@dll@ rwlock@dll@ tsd@dll@ echo_drv@dll@
@SHLIB_RULES@
diff --git a/erts/emulator/test/nif_SUITE_data/echo_drv.c b/erts/emulator/test/nif_SUITE_data/echo_drv.c
new file mode 100644
index 0000000000..2b3510c641
--- /dev/null
+++ b/erts/emulator/test/nif_SUITE_data/echo_drv.c
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include "erl_driver.h"
+
+static ErlDrvPort erlang_port;
+static ErlDrvData echo_start(ErlDrvPort, char *);
+static void from_erlang(ErlDrvData, char*, ErlDrvSizeT);
+static ErlDrvSSizeT echo_call(ErlDrvData drv_data, unsigned int command,
+ char *buf, ErlDrvSizeT len,
+ char **rbuf, ErlDrvSizeT rlen, unsigned *ret_flags);
+static ErlDrvEntry echo_driver_entry = {
+ NULL, /* Init */
+ echo_start,
+ NULL, /* Stop */
+ from_erlang,
+ NULL, /* Ready input */
+ NULL, /* Ready output */
+ "echo_drv",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ echo_call,
+ NULL,
+ ERL_DRV_EXTENDED_MARKER,
+ ERL_DRV_EXTENDED_MAJOR_VERSION,
+ ERL_DRV_EXTENDED_MINOR_VERSION,
+ 0,
+ NULL,
+ NULL,
+ NULL
+};
+
+DRIVER_INIT(echo_drv)
+{
+ return &echo_driver_entry;
+}
+
+static ErlDrvData
+echo_start(ErlDrvPort port, char *buf)
+{
+ return (ErlDrvData) port;
+}
+
+static void
+from_erlang(ErlDrvData data, char *buf, ErlDrvSizeT count)
+{
+ driver_output((ErlDrvPort) data, buf, count);
+}
+
+static ErlDrvSSizeT
+echo_call(ErlDrvData drv_data, unsigned int command,
+ char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen,
+ unsigned *ret_flags)
+{
+ *rbuf = buf;
+ *ret_flags |= DRIVER_CALL_KEEP_BUFFER;
+ return len;
+}
+
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index 1acb270d1f..11e5dab58e 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2009-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.
@@ -30,6 +30,7 @@ static int static_cntA; /* zero by default */
static int static_cntB = NIF_SUITE_LIB_VER * 100;
static ERL_NIF_TERM atom_false;
+static ERL_NIF_TERM atom_true;
static ERL_NIF_TERM atom_self;
static ERL_NIF_TERM atom_ok;
static ERL_NIF_TERM atom_join;
@@ -138,6 +139,7 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
msgenv_dtor,
ERL_NIF_RT_CREATE, NULL);
atom_false = enif_make_atom(env,"false");
+ atom_true = enif_make_atom(env,"true");
atom_self = enif_make_atom(env,"self");
atom_ok = enif_make_atom(env,"ok");
atom_join = enif_make_atom(env,"join");
@@ -1464,6 +1466,18 @@ static ERL_NIF_TERM send_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
return enif_make_int(env, ret);
}
+static ERL_NIF_TERM send_copy_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifEnv* menv;
+ ErlNifPid pid;
+ int ret;
+ if (!enif_get_local_pid(env, argv[0], &pid)) {
+ return enif_make_badarg(env);
+ }
+ ret = enif_send(env, &pid, NULL, argv[1]);
+ return enif_make_int(env, ret);
+}
+
static ERL_NIF_TERM reverse_list(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {
ERL_NIF_TERM rev_list;
@@ -1978,6 +1992,123 @@ static ERL_NIF_TERM convert_time_unit(ErlNifEnv* env, int argc, const ERL_NIF_TE
return enif_make_int64(env, enif_convert_time_unit(val, from, to));
}
+static ERL_NIF_TERM now_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ return enif_now_time(env);
+}
+
+static ERL_NIF_TERM cpu_time(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ return enif_cpu_time(env);
+}
+
+static ERL_NIF_TERM unique_integer(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ERL_NIF_TERM atom_pos = enif_make_atom(env,"positive"),
+ atom_mon = enif_make_atom(env,"monotonic");
+ ERL_NIF_TERM opts = argv[0], opt;
+ ErlNifUniqueInteger properties = 0;
+
+ while (!enif_is_empty_list(env, opts)) {
+ if (!enif_get_list_cell(env, opts, &opt, &opts))
+ return enif_make_badarg(env);
+
+ if (enif_compare(opt, atom_pos) == 0)
+ properties |= ERL_NIF_UNIQUE_POSITIVE;
+ if (enif_compare(opt, atom_mon) == 0)
+ properties |= ERL_NIF_UNIQUE_MONOTONIC;
+ }
+
+ return enif_make_unique_integer(env, properties);
+}
+
+static ERL_NIF_TERM is_process_alive(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifPid pid;
+ if (!enif_get_local_pid(env, argv[0], &pid))
+ return enif_make_badarg(env);
+ if (enif_is_process_alive(env, &pid))
+ return atom_true;
+ return atom_false;
+}
+
+static ERL_NIF_TERM is_port_alive(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifPort port;
+ if (!enif_get_local_port(env, argv[0], &port))
+ return enif_make_badarg(env);
+ if (enif_is_port_alive(env, &port))
+ return atom_true;
+ return atom_false;
+}
+
+static ERL_NIF_TERM term_to_binary(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifBinary bin;
+ ErlNifPid pid;
+ ErlNifEnv *msg_env = env;
+ ERL_NIF_TERM term;
+
+ if (enif_get_local_pid(env, argv[1], &pid))
+ msg_env = enif_alloc_env();
+
+ if (!enif_term_to_binary(msg_env, argv[0], &bin))
+ return enif_make_badarg(env);
+
+ term = enif_make_binary(msg_env, &bin);
+
+ if (msg_env != env) {
+ enif_send(env, &pid, msg_env, term);
+ enif_free_env(msg_env);
+ return atom_true;
+ } else {
+ return term;
+ }
+}
+
+static ERL_NIF_TERM binary_to_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifBinary bin;
+ ERL_NIF_TERM term, ret_term;
+ ErlNifPid pid;
+ ErlNifEnv *msg_env = env;
+ unsigned int opts;
+ ErlNifUInt64 ret;
+
+ if (enif_get_local_pid(env, argv[1], &pid))
+ msg_env = enif_alloc_env();
+
+ if (!enif_inspect_binary(env, argv[0], &bin)
+ || !enif_get_uint(env, argv[2], &opts))
+ return enif_make_badarg(env);
+
+ ret = enif_binary_to_term(msg_env, bin.data, bin.size, &term,
+ (ErlNifBinaryToTerm)opts);
+ if (!ret)
+ return atom_false;
+
+ ret_term = enif_make_uint64(env, ret);
+ if (msg_env != env) {
+ enif_send(env, &pid, msg_env, term);
+ enif_free_env(msg_env);
+ return ret_term;
+ } else {
+ return enif_make_tuple2(env, ret_term, term);
+ }
+}
+
+static ERL_NIF_TERM port_command(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ ErlNifPort port;
+
+ if (!enif_get_local_port(env, argv[0], &port))
+ return enif_make_badarg(env);
+
+ if (!enif_port_command(env, &port, NULL, argv[1]))
+ return enif_make_badarg(env);
+ return atom_true;
+}
+
static ErlNifFunc nif_funcs[] =
{
{"lib_version", 0, lib_version},
@@ -2023,6 +2154,7 @@ static ErlNifFunc nif_funcs[] =
{"join_send_thread", 1, join_send_thread},
{"copy_blob", 1, copy_blob},
{"send_term", 2, send_term},
+ {"send_copy_term", 2, send_copy_term},
{"reverse_list",1, reverse_list},
{"echo_int", 1, echo_int},
{"type_sizes", 0, type_sizes},
@@ -2050,8 +2182,15 @@ static ErlNifFunc nif_funcs[] =
{"sorted_list_from_maps_nif", 1, sorted_list_from_maps_nif},
{"monotonic_time", 1, monotonic_time},
{"time_offset", 1, time_offset},
- {"convert_time_unit", 3, convert_time_unit}
+ {"convert_time_unit", 3, convert_time_unit},
+ {"now_time", 0, now_time},
+ {"cpu_time", 0, cpu_time},
+ {"unique_integer_nif", 1, unique_integer},
+ {"is_process_alive_nif", 1, is_process_alive},
+ {"is_port_alive_nif", 1, is_port_alive},
+ {"term_to_binary_nif", 2, term_to_binary},
+ {"binary_to_term_nif", 3, binary_to_term},
+ {"port_command_nif", 2, port_command}
};
ERL_NIF_INIT(nif_SUITE,nif_funcs,load,reload,upgrade,unload)
-
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.c b/erts/emulator/test/nif_SUITE_data/nif_mod.c
index f7e729e2b6..fd8a0d0595 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_mod.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2009-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.
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.erl b/erts/emulator/test/nif_SUITE_data/nif_mod.erl
index b6de046388..eec1bb8858 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_mod.erl
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/test/node_container_SUITE.erl b/erts/emulator/test/node_container_SUITE.erl
index 71400142af..536c91d4ae 100644
--- a/erts/emulator/test/node_container_SUITE.erl
+++ b/erts/emulator/test/node_container_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2002-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.
@@ -28,8 +28,6 @@
-module(node_container_SUITE).
-author('[email protected]').
-%-define(line_trace, 1).
-
-include_lib("common_test/include/ct.hrl").
-export([all/0, suite/0, init_per_suite/1, end_per_suite/1,
@@ -56,7 +54,7 @@
suite() ->
[{ct_hooks,[ts_install_cth]},
- {timetrap, {minutes, 10}}].
+ {timetrap, {minutes, 12}}].
all() ->
@@ -126,7 +124,13 @@ term_to_binary_to_term_eq(Config) when is_list(Config) ->
LHLRef = binary_to_term(term_to_binary(LHLRef)),
LSRef = binary_to_term(term_to_binary(LSRef)),
% Get remote node containers
- RNode = {get_nodename(), 3},
+ ttbtteq_do_remote({get_nodename(), 3}),
+ ttbtteq_do_remote({get_nodename(), 4}),
+ ttbtteq_do_remote({get_nodename(), 16#adec0ded}),
+ nc_refc_check(node()),
+ ok.
+
+ttbtteq_do_remote(RNode) ->
RPid = mk_pid(RNode, 4711, 1),
RXPid = mk_pid(RNode, 32767, 8191),
RPort = mk_port(RNode, 4711),
@@ -142,7 +146,6 @@ term_to_binary_to_term_eq(Config) when is_list(Config) ->
RLRef = binary_to_term(term_to_binary(RLRef)),
RHLRef = binary_to_term(term_to_binary(RHLRef)),
RSRef = binary_to_term(term_to_binary(RSRef)),
- nc_refc_check(node()),
ok.
@@ -712,7 +715,7 @@ run_otp_4715(Config) when is_list(Config) ->
pid_wrap(Config) when is_list(Config) -> pp_wrap(pid).
port_wrap(Config) when is_list(Config) ->
- case test_server:os_type() of
+ case os:type() of
{unix, _} ->
pp_wrap(port);
_ ->
@@ -807,7 +810,7 @@ bad_nc(Config) when is_list(Config) ->
= (catch mk_ref(RemNode, [(1 bsl 18), 4711, 4711])),
{'EXIT', {badarg, mk_ref, _}}
= (catch mk_ref(RemNode, [4711, 4711, 4711, 4711, 4711, 4711, 4711])),
- BadNode = {x@y, 4},
+ BadNode = {x@y, bad_creation},
{'EXIT', {badarg, mk_pid, _}}
= (catch mk_pid(BadNode, 4711, 17)),
{'EXIT', {badarg, mk_port, _}}
@@ -842,11 +845,10 @@ iter_max_procs(Config) when is_list(Config) ->
Res = chk_max_proc_line(),
Res = chk_max_proc_line(),
done = chk_max_proc_line_until(NoMoreTests, Res),
- {comment,
- io_lib:format("max processes = ~p; "
- "process line length = ~p",
- [element(2, Res), element(1, Res)])}.
-
+ Cmt = io_lib:format("max processes = ~p; "
+ "process line length = ~p",
+ [element(2, Res), element(1, Res)]),
+ {comment, lists:flatten(Cmt)}.
max_proc_line(Root, Parent, N) ->
Me = self(),
@@ -1111,6 +1113,9 @@ get_nodename() ->
-define(PORT_EXT, 102).
-define(PID_EXT, 103).
-define(NEW_REFERENCE_EXT, 114).
+-define(NEW_PID_EXT, $X).
+-define(NEW_PORT_EXT, $Y).
+-define(NEWER_REFERENCE_EXT, $Z).
uint32_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 32 ->
[(Uint bsr 24) band 16#ff,
@@ -1133,51 +1138,65 @@ uint8(Uint) ->
exit({badarg, uint8, [Uint]}).
+pid_tag(bad_creation) -> ?PID_EXT;
+pid_tag(Creation) when Creation =< 3 -> ?PID_EXT;
+pid_tag(_Creation) -> ?NEW_PID_EXT.
+
+enc_creation(bad_creation) -> uint8(4);
+enc_creation(Creation) when Creation =< 3 -> uint8(Creation);
+enc_creation(Creation) -> uint32_be(Creation).
mk_pid({NodeName, Creation}, Number, Serial) when is_atom(NodeName) ->
mk_pid({atom_to_list(NodeName), Creation}, Number, Serial);
mk_pid({NodeName, Creation}, Number, Serial) ->
case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
- ?PID_EXT,
- ?ATOM_EXT,
- uint16_be(length(NodeName)),
- NodeName,
- uint32_be(Number),
- uint32_be(Serial),
- uint8(Creation)])) of
- Pid when is_pid(Pid) ->
- Pid;
- {'EXIT', {badarg, _}} ->
- exit({badarg, mk_pid, [{NodeName, Creation}, Number, Serial]});
- Other ->
- exit({unexpected_binary_to_term_result, Other})
+ pid_tag(Creation),
+ ?ATOM_EXT,
+ uint16_be(length(NodeName)),
+ NodeName,
+ uint32_be(Number),
+ uint32_be(Serial),
+ enc_creation(Creation)])) of
+ Pid when is_pid(Pid) ->
+ Pid;
+ {'EXIT', {badarg, _}} ->
+ exit({badarg, mk_pid, [{NodeName, Creation}, Number, Serial]});
+ Other ->
+ exit({unexpected_binary_to_term_result, Other})
end.
+port_tag(bad_creation) -> ?PORT_EXT;
+port_tag(Creation) when Creation =< 3 -> ?PORT_EXT;
+port_tag(_Creation) -> ?NEW_PORT_EXT.
+
mk_port({NodeName, Creation}, Number) when is_atom(NodeName) ->
mk_port({atom_to_list(NodeName), Creation}, Number);
mk_port({NodeName, Creation}, Number) ->
case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
- ?PORT_EXT,
- ?ATOM_EXT,
- uint16_be(length(NodeName)),
- NodeName,
- uint32_be(Number),
- uint8(Creation)])) of
- Port when is_port(Port) ->
- Port;
- {'EXIT', {badarg, _}} ->
- exit({badarg, mk_port, [{NodeName, Creation}, Number]});
- Other ->
- exit({unexpected_binary_to_term_result, Other})
+ port_tag(Creation),
+ ?ATOM_EXT,
+ uint16_be(length(NodeName)),
+ NodeName,
+ uint32_be(Number),
+ enc_creation(Creation)])) of
+ Port when is_port(Port) ->
+ Port;
+ {'EXIT', {badarg, _}} ->
+ exit({badarg, mk_port, [{NodeName, Creation}, Number]});
+ Other ->
+ exit({unexpected_binary_to_term_result, Other})
end.
+ref_tag(bad_creation) -> ?NEW_REFERENCE_EXT;
+ref_tag(Creation) when Creation =< 3 -> ?NEW_REFERENCE_EXT;
+ref_tag(_Creation) -> ?NEWER_REFERENCE_EXT.
+
mk_ref({NodeName, Creation}, Numbers) when is_atom(NodeName),
- is_integer(Creation),
- is_list(Numbers) ->
+ is_list(Numbers) ->
mk_ref({atom_to_list(NodeName), Creation}, Numbers);
mk_ref({NodeName, Creation}, [Number]) when is_list(NodeName),
- is_integer(Creation),
- is_integer(Number) ->
+ Creation =< 3,
+ is_integer(Number) ->
case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
?REFERENCE_EXT,
?ATOM_EXT,
@@ -1193,25 +1212,24 @@ mk_ref({NodeName, Creation}, [Number]) when is_list(NodeName),
exit({unexpected_binary_to_term_result, Other})
end;
mk_ref({NodeName, Creation}, Numbers) when is_list(NodeName),
- is_integer(Creation),
- is_list(Numbers) ->
+ is_list(Numbers) ->
case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
- ?NEW_REFERENCE_EXT,
- uint16_be(length(Numbers)),
- ?ATOM_EXT,
- uint16_be(length(NodeName)),
- NodeName,
- uint8(Creation),
- lists:map(fun (N) ->
- uint32_be(N)
- end,
- Numbers)])) of
- Ref when is_reference(Ref) ->
- Ref;
- {'EXIT', {badarg, _}} ->
- exit({badarg, mk_ref, [{NodeName, Creation}, Numbers]});
- Other ->
- exit({unexpected_binary_to_term_result, Other})
+ ref_tag(Creation),
+ uint16_be(length(Numbers)),
+ ?ATOM_EXT,
+ uint16_be(length(NodeName)),
+ NodeName,
+ enc_creation(Creation),
+ lists:map(fun (N) ->
+ uint32_be(N)
+ end,
+ Numbers)])) of
+ Ref when is_reference(Ref) ->
+ Ref;
+ {'EXIT', {badarg, _}} ->
+ exit({badarg, mk_ref, [{NodeName, Creation}, Numbers]});
+ Other ->
+ exit({unexpected_binary_to_term_result, Other})
end.
exec_loop() ->
diff --git a/erts/emulator/test/nofrag_SUITE.erl b/erts/emulator/test/nofrag_SUITE.erl
index 9cc851f9cf..8b1519ae36 100644
--- a/erts/emulator/test/nofrag_SUITE.erl
+++ b/erts/emulator/test/nofrag_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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.
diff --git a/erts/emulator/test/num_bif_SUITE.erl b/erts/emulator/test/num_bif_SUITE.erl
index 04a6f9d18d..d1c9648017 100644
--- a/erts/emulator/test/num_bif_SUITE.erl
+++ b/erts/emulator/test/num_bif_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/old_mod.erl b/erts/emulator/test/old_mod.erl
index 0da40ec430..866aba79bb 100644
--- a/erts/emulator/test/old_mod.erl
+++ b/erts/emulator/test/old_mod.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/test/old_scheduler_SUITE.erl b/erts/emulator/test/old_scheduler_SUITE.erl
index 9d40417d0a..f91d84beea 100644
--- a/erts/emulator/test/old_scheduler_SUITE.erl
+++ b/erts/emulator/test/old_scheduler_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2004-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.
diff --git a/erts/emulator/test/op_SUITE.erl b/erts/emulator/test/op_SUITE.erl
index 562cf1c92d..08655d32a5 100644
--- a/erts/emulator/test/op_SUITE.erl
+++ b/erts/emulator/test/op_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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.
@@ -30,7 +30,7 @@
suite() ->
[{ct_hooks,[ts_install_cth]},
- {timetrap, {minutes, 3}}].
+ {timetrap, {minutes, 5}}].
all() ->
[bsl_bsr, logical, t_not, relop_simple, relop,
@@ -39,9 +39,16 @@ all() ->
%% Test the bsl and bsr operators.
bsl_bsr(Config) when is_list(Config) ->
Vs = [unvalue(V) || V <- [-16#8000009-2,-1,0,1,2,73,16#8000000,bad,[]]],
- Cases = [{Op,X,Y} || Op <- ['bsr','bsl'], X <- Vs, Y <- Vs],
- run_test_module(Cases, false),
- {comment,integer_to_list(length(Cases)) ++ " cases"}.
+ %% Try to use less memory by splitting the cases
+
+ Cases1 = [{Op,X,Y} || Op <- ['bsl'], X <- Vs, Y <- Vs],
+ N1 = length(Cases1),
+ run_test_module(Cases1, false),
+
+ Cases2 = [{Op,X,Y} || Op <- ['bsr'], X <- Vs, Y <- Vs],
+ N2 = length(Cases2),
+ run_test_module(Cases2, false),
+ {comment,integer_to_list(N1 + N2) ++ " cases"}.
%% Test the logical operators and internal BIFs.
logical(Config) when is_list(Config) ->
diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl
index 328641f5b9..79abcbde5f 100644
--- a/erts/emulator/test/port_SUITE.erl
+++ b/erts/emulator/test/port_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
@@ -87,6 +87,7 @@
name1/1,
t_binary/1, parallell/1, t_exit/1,
env/1, huge_env/1, bad_env/1, cd/1, exit_status/1,
+ bad_args/1,
tps_16_bytes/1, tps_1K/1, line/1, stderr_to_stdout/1,
otp_3906/1, otp_4389/1, win_massive/1, win_massive_client/1,
mix_up_ports/1, otp_5112/1, otp_5119/1, otp_6224/1,
@@ -115,6 +116,7 @@ all() ->
{group, multiple_packets}, parallell, dying_port,
port_program_with_path, open_input_file_port,
open_output_file_port, name1, env, huge_env, bad_env, cd,
+ bad_args,
exit_status, iter_max_ports, count_fds, t_exit, {group, tps}, line,
stderr_to_stdout, otp_3906, otp_4389, win_massive,
mix_up_ports, otp_5112, otp_5119,
@@ -901,14 +903,15 @@ bad_env(Config) when is_list(Config) ->
ok.
try_bad_env(Env) ->
- try open_port({spawn,"ls"}, [{env,Env}])
- catch
- error:badarg -> ok
- end.
+ badarg = try open_port({spawn,"ls"}, [{env,Env}])
+ catch
+ error:badarg -> badarg
+ end.
+
%% Test that we can handle a very very large environment gracefully.
huge_env(Config) when is_list(Config) ->
- ct:timetrap({seconds, 30}),
+ ct:timetrap({minutes, 2}),
Vars = case os:type() of
{win32,_} -> 500;
_ ->
@@ -940,6 +943,24 @@ huge_env(Config) when is_list(Config) ->
end.
+%% Test bad 'args' options.
+bad_args(Config) when is_list(Config) ->
+ try_bad_args({args, [self()]}),
+ try_bad_args({args, ["head" | "tail"]}),
+ try_bad_args({args, ["head", "body" | "tail"]}),
+ try_bad_args({args, [<<"head">>, <<"body">> | <<"tail">>]}),
+ try_bad_args({args, not_a_list}),
+ try_bad_args({args, ["string",<<"binary">>, 1472, "string"]}),
+ try_bad_args({args, ["string",<<"binary">>], "element #3"}),
+ ok.
+
+try_bad_args(Args) ->
+ badarg = try open_port({spawn_executable,"ls"}, [Args])
+ catch
+ error:badarg -> badarg
+ end.
+
+
%% 'cd' option
%% (Can perhaps be made smaller by calling the other utility functions
@@ -1757,7 +1778,7 @@ otp_6224_loop() ->
exit_status_multi_scheduling_block(Config) when is_list(Config) ->
Repeat = 3,
- case test_server:os_type() of
+ case os:type() of
{unix, _} ->
ct:timetrap({minutes, 2*Repeat}),
SleepSecs = 6,
diff --git a/erts/emulator/test/port_SUITE_data/dead_port.c b/erts/emulator/test/port_SUITE_data/dead_port.c
index c859dbc402..26f09f33c7 100644
--- a/erts/emulator/test/port_SUITE_data/dead_port.c
+++ b/erts/emulator/test/port_SUITE_data/dead_port.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/test/port_SUITE_data/port_test.erl b/erts/emulator/test/port_SUITE_data/port_test.erl
index b07038e73d..406d376b26 100644
--- a/erts/emulator/test/port_SUITE_data/port_test.erl
+++ b/erts/emulator/test/port_SUITE_data/port_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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.
diff --git a/erts/emulator/test/port_bif_SUITE.erl b/erts/emulator/test/port_bif_SUITE.erl
index 9b794be415..e1e1ec9fb9 100644
--- a/erts/emulator/test/port_bif_SUITE.erl
+++ b/erts/emulator/test/port_bif_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/port_trace_SUITE.erl b/erts/emulator/test/port_trace_SUITE.erl
new file mode 100644
index 0000000000..bfdea0761b
--- /dev/null
+++ b/erts/emulator/test/port_trace_SUITE.erl
@@ -0,0 +1,614 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2012. 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%
+%%
+
+
+-module(port_trace_SUITE).
+
+-export([all/0, suite/0,init_per_suite/1, end_per_suite/1,
+ init_per_group/2,end_per_group/2,
+ init_per_testcase/2,end_per_testcase/2]).
+-export([port_specs/1, ports/1, open_close/1,
+ command/1, control/1, connect/1, call/1,
+ output/1, output2/1, output_binary/1,
+ outputv/1, set_timer/1, failure_eof/1,
+ failure_atom/1, failure_posix/1,
+ failure/1, output_term/1,
+ driver_output_term/1,
+ send_term/1, driver_send_term/1]).
+
+-define(ECHO_DRV_NOOP, 0).
+-define(ECHO_DRV_OUTPUT, 1).
+-define(ECHO_DRV_OUTPUT2, 2).
+-define(ECHO_DRV_OUTPUT_BINARY, 3).
+-define(ECHO_DRV_OUTPUTV, 4).
+-define(ECHO_DRV_SET_TIMER, 5).
+-define(ECHO_DRV_FAILURE_EOF, 6).
+-define(ECHO_DRV_FAILURE_ATOM, 7).
+-define(ECHO_DRV_FAILURE_POSIX, 8).
+-define(ECHO_DRV_FAILURE, 9).
+-define(ECHO_DRV_OUTPUT_TERM, 10).
+-define(ECHO_DRV_DRIVER_OUTPUT_TERM, 11).
+-define(ECHO_DRV_SEND_TERM, 12).
+-define(ECHO_DRV_DRIVER_SEND_TERM, 13).
+-define(ECHO_DRV_SAVE_CALLER, 14).
+
+suite() -> [{ct_hooks,[ts_install_cth]},
+ {timetrap, {seconds, 30}}].
+
+all() ->
+ [port_specs, ports, open_close,
+ command, control, connect, call,
+ output, output2, output_binary,
+ outputv, set_timer, failure_eof,
+ failure_atom, failure_posix,
+ failure, output_term,
+ driver_output_term,
+ send_term, driver_send_term].
+
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+
+init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
+ erlang:trace(all, false, [all]),
+ os:unsetenv("OUTPUTV"),
+ reload_drv(Config),
+ Config.
+
+end_per_testcase(_Func, _Config) ->
+ erlang:trace(all, false, [all]),
+ ok.
+
+%% Test the first argument of trace/3
+port_specs(_Config) ->
+
+ S = self(),
+
+ Tracer = fun F() ->
+ receive
+ stop ->
+ ok;
+ M ->
+ S ! M,
+ F()
+ end
+ end,
+
+ Test = fun(TraceSpec, Info1, Info2) ->
+ {TracerPid,Ref} = spawn_monitor(Tracer),
+ Prt1 = erlang:open_port({spawn, echo_drv}, [binary]),
+ erlang:trace(TraceSpec, true, ['receive', {tracer, TracerPid}]),
+ %% We disable trace messages from the testcase process
+ erlang:trace(self(), false, ['receive']),
+ Prt2 = erlang:open_port({spawn, echo_drv}, [binary]),
+
+ InfoCheck =
+ fun(Info, Prt) ->
+ if
+ Info ->
+ {tracer, TracerPid} = erlang:trace_info(Prt, tracer),
+ {flags,['receive']} = erlang:trace_info(Prt, flags);
+ not Info ->
+ {tracer,[]} = erlang:trace_info(Prt, tracer),
+ {flags,[]} = erlang:trace_info(Prt, flags)
+ end
+ end,
+ InfoCheck(Info1, Prt1),
+ InfoCheck(Info2, Prt2),
+
+ %% These may create trace messages
+ erlang:port_command(Prt1, <<?ECHO_DRV_NOOP>>),
+ erlang:port_command(Prt2, <<?ECHO_DRV_NOOP>>),
+
+ %% Test what happens when the tracer dies
+ trace_delivered(),
+ TracerPid ! stop,
+ receive {'DOWN', Ref, process, TracerPid, normal} -> ok end,
+
+ %% These should not generate any trace messages
+ erlang:port_command(Prt1, <<?ECHO_DRV_NOOP>>),
+ erlang:port_command(Prt2, <<?ECHO_DRV_NOOP>>),
+
+ InfoCheck(false, Prt1),
+ InfoCheck(false, Prt2),
+
+ erlang:port_close(Prt1),
+ erlang:port_close(Prt2),
+ erlang:trace(all, false, [all]),
+ {Prt1, Prt2}
+ end,
+
+ {_Prt11, Prt12} = Test(new, false, true),
+ [{trace, Prt12, 'receive', {S, {command,<<?ECHO_DRV_NOOP>>}}}]
+ = flush(Prt12),
+
+ {_Prt21, Prt22} = Test(new_ports, false, true),
+ [{trace, Prt22, 'receive', {S, {command,<<?ECHO_DRV_NOOP>>}}}]
+ = flush(Prt22),
+
+ {Prt31, _Prt32} = Test(existing, true, false),
+ [{trace, Prt31, 'receive', {S, {command,<<?ECHO_DRV_NOOP>>}}}]
+ = flush(Prt31),
+
+ {Prt41, _Prt42} = Test(existing_ports, true, false),
+ [{trace, Prt41, 'receive', {S, {command,<<?ECHO_DRV_NOOP>>}}}]
+ = flush(Prt41),
+
+ {Prt51, Prt52} = Test(all, true, true),
+ [{trace, Prt51, 'receive', {S, {command,<<?ECHO_DRV_NOOP>>}}}]
+ = flush(Prt51),
+ [{trace, Prt52, 'receive', {S, {command,<<?ECHO_DRV_NOOP>>}}}]
+ = flush(Prt52),
+
+ {Prt61, Prt62} = Test(ports, true, true),
+ [{trace, Prt61, 'receive', {S, {command,<<?ECHO_DRV_NOOP>>}}}]
+ = flush(Prt61),
+ [{trace, Prt62, 'receive', {S, {command,<<?ECHO_DRV_NOOP>>}}}]
+ = flush(Prt62),
+
+ ok.
+
+%% Test that the 'ports' trace flag works
+ports(_Config) ->
+
+ {Prt, S} = trace_and_open([ports],[binary]),
+
+ [{trace, Prt, open, S, echo_drv},
+ {trace, Prt, getting_linked, S}] = flush(),
+
+ register(?MODULE, Prt),
+ unregister(?MODULE),
+ register(?MODULE, Prt),
+
+ [{trace,Prt,register,port_trace_SUITE},
+ {trace,Prt,unregister,port_trace_SUITE},
+ {trace,Prt,register,port_trace_SUITE}] = flush(),
+
+ unlink(Prt),
+ link(Prt),
+
+ [{trace,Prt,getting_unlinked,S},
+ {trace,Prt,getting_linked,S}] = flush(),
+
+ erlang:port_close(Prt),
+
+ [{trace,Prt,closed,normal},
+ {trace,Prt,unregister,port_trace_SUITE},
+ {trace,Prt,unlink,S}] = flush(),
+
+ ok.
+
+%% Test that port_close and ! close generate correct trace messages
+open_close(_Config) ->
+
+ S = trace_ports([send,'receive']),
+
+ Prt = erlang:open_port({spawn, echo_drv}, [binary]),
+ erlang:port_close(Prt),
+ [{trace, Prt, 'receive', {S, close}}] = flush(),
+
+ Prt2 = erlang:open_port({spawn, echo_drv}, [binary]),
+ Prt2 ! {S, close},
+ recv({Prt2, closed}),
+ [{trace, Prt2, 'receive', {S, close}},
+ {trace, Prt2, send, closed, S}] = flush(),
+
+ catch erlang:port_close(Prt2),
+ [] = flush(),
+
+ ok.
+
+%% Test that port_command and ! command generate correct trace messages
+command(Config) ->
+
+ Flags = [send,'receive'],
+ S = trace_ports(Flags),
+ Prt = erlang:open_port({spawn, echo_drv}, [binary]),
+
+ erlang:port_command(Prt, <<?ECHO_DRV_NOOP:8>>),
+ [{trace, Prt, 'receive', {S, {command, <<?ECHO_DRV_NOOP:8>>}}}] = flush(),
+
+ erlang:port_command(Prt, [?ECHO_DRV_NOOP, <<0:8>>]),
+ [{trace, Prt, 'receive', {S, {command, <<?ECHO_DRV_NOOP:8,0:8>>}}}] = flush(),
+
+ Prt ! {S, {command, <<?ECHO_DRV_NOOP:8>>}},
+ [{trace, Prt, 'receive', {S, {command, <<?ECHO_DRV_NOOP:8>>}}}] = flush(),
+
+ OutputMsg = <<?ECHO_DRV_NOOP:8,0:(8*512)>>,
+ Prt ! {S, {command, OutputMsg}},
+ [{trace, Prt, 'receive', {S, {command, OutputMsg}}}] = flush(),
+
+ close(Prt, Flags),
+
+ os:putenv("OUTPUTV","true"),
+ reload_drv(Config),
+
+ Prt2 = erlang:open_port({spawn, echo_drv}, [binary]),
+ OutputvMsg = [<<0:8>>,<<0:(8*512)>>,<<0:(8*256)>>,<<0:8>>],
+
+ erlang:port_command(Prt2, OutputvMsg),
+ [{trace, Prt2, 'receive', {S, {command, OutputvMsg}}}] = flush(),
+
+ Prt2 ! {S, {command, OutputvMsg}},
+ [{trace, Prt2, 'receive', {S, {command, OutputvMsg}}}] = flush(),
+
+ close(Prt2, Flags),
+
+ os:unsetenv("OUTPUTV"),
+
+ ok.
+
+%% Test that port_control generate correct trace messages
+control(_Config) ->
+
+ Flags = [send,'receive'],
+ {Prt, S} = trace_and_open(Flags,[binary]),
+
+ [0] = erlang:port_control(Prt, 1, <<?ECHO_DRV_NOOP:8, 0:8>>),
+ [{trace, Prt, 'receive', {S, {control, {1, <<?ECHO_DRV_NOOP:8, 0:8>>}}}},
+ {trace, Prt, send, {Prt, {control, <<0:8>>}}, S}] = flush(),
+
+ [0] = erlang:port_control(Prt, (1 bsl 32) - 1, <<?ECHO_DRV_NOOP:8, 0:8>>),
+ [{trace, Prt, 'receive', {S, {control, {(1 bsl 32) - 1, <<?ECHO_DRV_NOOP:8, 0:8>>}}}},
+ {trace, Prt, send, {Prt, {control, <<0:8>>}}, S}] = flush(),
+
+ Msg = <<?ECHO_DRV_NOOP:8, 0:(8*512)>>,
+ Pat = lists:duplicate(512, 0),
+ Pat = erlang:port_control(Prt, 1, Msg),
+ [{trace, Prt, 'receive', {S, {control, {1, Msg}}}},
+ {trace, Prt, send, {Prt, {control, <<0:(8*512)>>}}, S}] = flush(),
+
+ close(Prt, Flags),
+
+ ok.
+
+%% Test that port_connect and ! connect generate correct trace messages
+%% This includes that the proper getting_linked messages are sent
+connect(_Config) ->
+
+
+ {Prt, S} = trace_and_open([send, 'receive', ports],[binary]),
+
+ flush(),
+
+ {Pid,Ref} = spawn_monitor(
+ fun() ->
+ receive
+ go ->
+ Prt ! {self(), {connect, S}},
+ receive {Prt, connected} -> unlink(Prt) end
+ end
+ end),
+ erlang:trace(Pid, true, [send, 'receive', procs]),
+
+ erlang:port_connect(Prt, Pid),
+ unlink(Prt),
+
+ [{trace,Prt,getting_linked,Pid},
+ {trace,Prt,'receive',{S,{connect,Pid}}},
+ {trace,Prt,send,{Prt,connected},S},
+ {trace,Prt,getting_unlinked, S}] = flush(Prt),
+
+ [{trace,Pid,getting_linked,Prt}] = flush(),
+
+ Pid ! go,
+ recv({'DOWN',Ref,process,Pid,normal}),
+
+ [{trace,Prt,'receive',{Pid,{connect,S}}},
+ {trace,Prt,send,{Prt,connected},Pid},
+ {trace,Prt,getting_unlinked,Pid}] = flush(Prt),
+
+ [{trace,Pid,'receive',go},
+ {trace,Pid,send,{Pid,{connect,S}}, Prt},
+ {trace,Pid,'receive',{Prt,connected}},
+ {trace,Pid,unlink,Prt},
+ {trace,Pid,exit,normal}] = flush(),
+
+ erlang:port_close(Prt),
+ [{trace, Prt, 'receive', {S, close}},
+ {trace, Prt, closed, normal}] = flush(),
+ ok.
+
+%% Test that port_call generate correct trace messages
+call(_Config) ->
+
+ Flags = [send,'receive'],
+ {Prt, S} = trace_and_open(Flags,[binary]),
+
+ Test = fun(Msg) ->
+ BinMsg = term_to_binary(Msg),
+
+ Msg = erlang:port_call(Prt, 0, Msg),
+ [{trace, Prt, 'receive', {S, {call, {0, BinMsg}}}},
+ {trace, Prt, send, {Prt, {call, BinMsg}}, S}] = flush()
+ end,
+
+ Test({hello, world, make_ref()}),
+ Test({hello, world, lists:seq(1,1000)}),
+
+ close(Prt, Flags),
+
+ ok.
+
+%% Test that driver_output generate correct trace messages
+output(_Config) ->
+
+ Flags = [send],
+ {Prt, S} = trace_and_open(Flags,[binary]),
+
+ erlang:port_command(Prt, <<?ECHO_DRV_OUTPUT, 123456:32>>),
+ recv({Prt,{data,<<123456:32>>}}),
+
+ [{trace, Prt, send, {Prt, {data, <<123456:32>>}}, S}] = flush(),
+
+ close(Prt, Flags),
+
+ ok.
+
+%% Test that driver_output2 generate correct trace messages
+output2(_Config) ->
+
+ Flags = [send],
+ {Prt, S} = trace_and_open(Flags,[binary]),
+
+ erlang:port_command(Prt, <<?ECHO_DRV_OUTPUT2, 123456:32>>),
+ recv({Prt,{data,[$a|<<123456:32>>]}}),
+ [{trace, Prt, send, {Prt, {data, [$a|<<123456:32>>]}}, S}] = flush(),
+
+ close(Prt, Flags),
+
+ ok.
+
+%% Test that driver_output_binary generate correct trace messages
+output_binary(_Config) ->
+
+ Flags = [send],
+ {Prt, S} = trace_and_open(Flags,[binary]),
+
+ erlang:port_command(Prt, <<?ECHO_DRV_OUTPUT_BINARY, 0, 123456:32>>),
+ recv({Prt,{data,[$a|<<123456:32>>]}}),
+ [{trace, Prt, send, {Prt, {data, [$a|<<123456:32>>]}}, S}] = flush(),
+
+ close(Prt, Flags),
+
+ ok.
+
+%% Test that driver_outputv generate correct trace messages
+outputv(_Config) ->
+
+ Flags = [send],
+ {Prt, S} = trace_and_open(Flags,[binary]),
+
+ erlang:port_command(Prt, <<?ECHO_DRV_OUTPUTV, 123456:32>>),
+ recv({Prt,{data,[$a|<<123456:32>>]}}),
+
+ [{trace, Prt, send, {Prt, {data, [$a|<<123456:32>>]}}, S}] = flush(),
+
+ erlang:port_close(Prt),
+ [] = flush(),
+
+ ok.
+
+%% Test that driver_set_timer generate correct trace messages
+set_timer(_Config) ->
+
+ Flags = [send,'receive'],
+ {Prt, S} = trace_and_open(Flags,[binary]),
+
+ erlang:port_command(Prt, <<?ECHO_DRV_SET_TIMER>>),
+ timer:sleep(100),
+ [{trace, Prt, 'receive', {S, {command, <<?ECHO_DRV_SET_TIMER>>}}},
+ {trace, Prt, 'receive', timeout}] = flush(),
+
+ close(Prt, Flags),
+
+ ok.
+
+%% Test that driver_failure* generate correct trace messages
+failure_eof(_Config) ->
+
+ Flags = [send,'receive', ports],
+ S = trace_ports(Flags),
+
+ Prt = erlang:open_port({spawn, echo_drv}, [eof, binary]),
+ [{trace, Prt, open, S, echo_drv},
+ {trace, Prt, getting_linked, S}] = flush(),
+
+ erlang:port_command(Prt, <<?ECHO_DRV_FAILURE_EOF>>),
+ recv({Prt,eof}),
+ [{trace, Prt, 'receive', {S, {command, <<?ECHO_DRV_FAILURE_EOF>>}}},
+ {trace, Prt, send, {Prt, eof}, S}] = flush(),
+
+ close(Prt, Flags),
+
+ %% Run same test without eof option
+ failure_test(<<?ECHO_DRV_FAILURE_EOF>>, normal).
+
+failure_atom(_Config) ->
+ failure_test(<<?ECHO_DRV_FAILURE_ATOM, "failure\0">>, failure).
+failure_posix(_Config) ->
+ failure_test(<<?ECHO_DRV_FAILURE_POSIX>>, eagain).
+failure(_Config) ->
+ failure_test(<<?ECHO_DRV_FAILURE, 1>>, 1).
+
+failure_test(Failure, Reason) ->
+
+ {Prt, S} = trace_and_open([send, 'receive', ports],[binary]),
+
+ [{trace, Prt, open, S, echo_drv},
+ {trace, Prt, getting_linked, S}] = flush(),
+
+ process_flag(trap_exit, true),
+ erlang:port_command(Prt, Failure),
+ try
+ recv({'EXIT',Prt,Reason})
+ after
+ process_flag(trap_exit, false)
+ end,
+ [{trace, Prt, 'receive', {S, {command, Failure}}},
+ {trace, Prt, closed, Reason},
+ {trace, Prt, unlink, S}] = flush(),
+
+ ok.
+
+%% Test that erl_drv_output_term generate correct trace messages
+output_term(_Config) ->
+
+ Flags = [send],
+ {Prt, S} = trace_and_open(Flags,[binary]),
+
+ erlang:port_command(Prt, <<?ECHO_DRV_OUTPUT_TERM, 123456:32>>),
+ recv({echo, Prt, <<123456:32>>}),
+ [{trace, Prt, send, {echo, Prt, <<123456:32>>}, S}] = flush(),
+
+ close(Prt, Flags),
+
+ ok.
+
+%% Test that driver_output_term generate correct trace messages
+driver_output_term(_Config) ->
+
+ Flags = [send],
+ {Prt, S} = trace_and_open(Flags,[binary]),
+
+ erlang:port_command(Prt, <<?ECHO_DRV_DRIVER_OUTPUT_TERM, 123456:32>>),
+ recv({echo, Prt, <<123456:32>>}),
+ [{trace, Prt, send, {echo, Prt, <<123456:32>>}, S}] = flush(),
+
+ close(Prt, Flags),
+
+ ok.
+
+%% Test that erl_drv_send_term generate correct trace messages
+send_term(_Config) ->
+
+ Flags = [send],
+ {Prt, S} = trace_and_open(Flags,[binary]),
+
+ erlang:port_command(Prt, <<?ECHO_DRV_SEND_TERM, 123456:32>>),
+ recv({echo, Prt, <<123456:32>>}),
+ [{trace, Prt, send, {echo, Prt, <<123456:32>>}, S}] = flush(),
+
+ {Pid, Ref} = spawn_monitor(fun() -> erlang:port_command(Prt, <<?ECHO_DRV_SAVE_CALLER>>) end),
+ recv({'DOWN',Ref,process,Pid,normal}),
+ erlang:port_command(Prt, <<?ECHO_DRV_SEND_TERM, 123456:32>>),
+ [{trace, Prt, send_to_non_existing_process, {echo, Prt, <<123456:32>>}, Pid}] = flush(),
+
+ close(Prt, Flags),
+
+ ok.
+
+%% Test that driver_send_term generate correct trace messages
+driver_send_term(_Config) ->
+
+ Flags = [send],
+ {Prt, S} = trace_and_open(Flags,[binary]),
+
+ erlang:port_command(Prt, <<?ECHO_DRV_DRIVER_SEND_TERM, 123456:32>>),
+ recv({echo, Prt, <<123456:32>>}),
+ [{trace, Prt, send, {echo, Prt, <<123456:32>>}, S}] = flush(),
+
+ {Pid, Ref} = spawn_monitor(fun() -> erlang:port_command(Prt, <<?ECHO_DRV_SAVE_CALLER>>) end),
+ recv({'DOWN',Ref,process,Pid,normal}),
+ erlang:port_command(Prt, <<?ECHO_DRV_SEND_TERM, 123456:32>>),
+ [{trace, Prt, send_to_non_existing_process, {echo, Prt, <<123456:32>>}, Pid}] = flush(),
+
+ close(Prt, Flags),
+
+ ok.
+
+%%%%%%%%%%%%%%%%%%%
+%% Helper functions
+%%%%%%%%%%%%%%%%%%%
+
+trace_ports(TraceFlags) ->
+ erlang:trace(new_ports, true, TraceFlags),
+ self().
+
+trace_and_open(TraceFlags, OpenFlags) ->
+ S = self(),
+ Ports = proplists:get_value(ports, TraceFlags),
+ [trace_ports(TraceFlags) || Ports],
+ Prt = erlang:open_port({spawn, echo_drv}, OpenFlags),
+ [erlang:trace(Prt, true, TraceFlags) || Ports == undefined],
+ {Prt, S}.
+
+close(Prt, Flags) ->
+ Recv = proplists:get_value('receive', Flags),
+ Ports = proplists:get_value(ports, Flags),
+ S = self(),
+
+ erlang:port_close(Prt),
+
+ if Recv, Ports ->
+ [{trace, Prt, 'receive', {S, close}},
+ {trace, Prt, closed, normal},
+ {trace, Prt, unlink, S}] = flush();
+ Recv ->
+ [{trace, Prt, 'receive', {S, close}}] = flush();
+ Ports ->
+ [{trace, Prt, closed, normal},
+ {trace, Prt, unlink, S}] = flush();
+ true ->
+ [] = flush()
+ end.
+
+trace_delivered() ->
+ Ref = erlang:trace_delivered(all),
+ receive {trace_delivered, all, Ref} -> ok end.
+
+flush() ->
+ flush(all).
+flush(From) ->
+ trace_delivered(),
+ f(From).
+
+f(From) ->
+ receive
+ M when From =:= all; element(2, M) == From ->
+ [M | f(From)]
+ after 0 ->
+ []
+ end.
+
+recv(Msg) ->
+ receive Msg -> ok after 100 -> ct:fail({did_not_get_data,Msg,flush()}) end.
+
+load_drv(Config) ->
+ Path = proplists:get_value(data_dir, Config),
+ case erl_ddll:load_driver(Path, echo_drv) of
+ ok -> ok;
+ {error, Error} = Res ->
+ io:format("~s\n", [erl_ddll:format_error(Error)]),
+ ct:fail(Res)
+ end.
+
+reload_drv(Config) ->
+ erl_ddll:unload_driver(echo_drv),
+ load_drv(Config).
diff --git a/erts/emulator/test/port_trace_SUITE_data/Makefile.src b/erts/emulator/test/port_trace_SUITE_data/Makefile.src
new file mode 100644
index 0000000000..c1bf142ccf
--- /dev/null
+++ b/erts/emulator/test/port_trace_SUITE_data/Makefile.src
@@ -0,0 +1,3 @@
+all: echo_drv@dll@
+
+@SHLIB_RULES@
diff --git a/erts/emulator/test/port_trace_SUITE_data/echo_drv.c b/erts/emulator/test/port_trace_SUITE_data/echo_drv.c
new file mode 100644
index 0000000000..b5ae9389b4
--- /dev/null
+++ b/erts/emulator/test/port_trace_SUITE_data/echo_drv.c
@@ -0,0 +1,241 @@
+#include <stdio.h>
+#include "erl_driver.h"
+#include <errno.h>
+#include <string.h>
+
+
+/* -------------------------------------------------------------------------
+** Data types
+**/
+
+
+typedef struct _erl_drv_data {
+ ErlDrvPort erlang_port;
+ ErlDrvTermData caller;
+} EchoDrvData;
+
+#define ECHO_DRV_NOOP 0
+#define ECHO_DRV_OUTPUT 1
+#define ECHO_DRV_OUTPUT2 2
+#define ECHO_DRV_OUTPUT_BINARY 3
+#define ECHO_DRV_OUTPUTV 4
+#define ECHO_DRV_SET_TIMER 5
+#define ECHO_DRV_FAILURE_EOF 6
+#define ECHO_DRV_FAILURE_ATOM 7
+#define ECHO_DRV_FAILURE_POSIX 8
+#define ECHO_DRV_FAILURE 9
+#define ECHO_DRV_OUTPUT_TERM 10
+#define ECHO_DRV_DRIVER_OUTPUT_TERM 11
+#define ECHO_DRV_SEND_TERM 12
+#define ECHO_DRV_DRIVER_SEND_TERM 13
+#define ECHO_DRV_SAVE_CALLER 14
+
+
+/* -------------------------------------------------------------------------
+** Entry struct
+**/
+
+static EchoDrvData *echo_drv_start(ErlDrvPort port, char *command);
+static void echo_drv_stop(ErlDrvData drv_data);
+static void echo_drv_output(ErlDrvData drv_data, char *buf,
+ ErlDrvSizeT len);
+static void echo_drv_outputv(ErlDrvData drv_data, ErlIOVec *iov);
+static void echo_drv_finish(void);
+static ErlDrvSSizeT echo_drv_control(ErlDrvData drv_data,
+ unsigned int command,
+ char *buf, ErlDrvSizeT len,
+ char **rbuf, ErlDrvSizeT rlen);
+static void echo_drv_timeout(ErlDrvData drv_data);
+static ErlDrvSSizeT echo_drv_call(ErlDrvData drv_data,
+ unsigned int command,
+ char *buf, ErlDrvSizeT len,
+ char **rbuf, ErlDrvSizeT rlen,
+ unsigned int *flags);
+
+static ErlDrvEntry echo_drv_entry = {
+ NULL, /* init */
+ echo_drv_start,
+ echo_drv_stop,
+ echo_drv_output,
+ NULL, /* ready_input */
+ NULL, /* ready_output */
+ "echo_drv",
+ echo_drv_finish,
+ NULL, /* handle */
+ echo_drv_control,
+ echo_drv_timeout, /* timeout */
+ NULL, /* outputv */
+ NULL, /* ready_async */
+ NULL, /* flush */
+ echo_drv_call, /* call */
+ NULL, /* event */
+ ERL_DRV_EXTENDED_MARKER,
+ ERL_DRV_EXTENDED_MAJOR_VERSION,
+ ERL_DRV_EXTENDED_MINOR_VERSION,
+ 0,
+ NULL,
+ NULL,
+ NULL
+};
+
+/* -------------------------------------------------------------------------
+** Entry functions
+**/
+
+DRIVER_INIT(echo_drv)
+{
+ char buff[5];
+ size_t size = sizeof(buff);
+
+ if (erl_drv_getenv("OUTPUTV", buff, &size) == -1) {
+ echo_drv_entry.outputv = NULL;
+ } else {
+ echo_drv_entry.outputv = echo_drv_outputv;
+ }
+
+ return &echo_drv_entry;
+}
+
+static EchoDrvData *echo_drv_start(ErlDrvPort port, char *command)
+{
+ EchoDrvData *echo_drv_data_p = driver_alloc(sizeof(EchoDrvData));
+ echo_drv_data_p->erlang_port = port;
+ echo_drv_data_p->caller = driver_caller(port);
+ return echo_drv_data_p;
+}
+
+static void echo_drv_stop(EchoDrvData *data_p) {
+ driver_free(data_p);
+}
+
+static void echo_drv_outputv(ErlDrvData drv_data, ErlIOVec *iov)
+{
+ return;
+}
+
+static void echo_drv_output(ErlDrvData drv_data, char *buf, ErlDrvSizeT len) {
+ EchoDrvData* data_p = (EchoDrvData *) drv_data;
+ ErlDrvPort port = data_p->erlang_port;
+
+ switch (buf[0]) {
+ case ECHO_DRV_OUTPUT:
+ {
+ driver_output(port, buf+1, len-1);
+ break;
+ }
+ case ECHO_DRV_OUTPUT2:
+ {
+ driver_output2(port, "a", 1, buf+1, len-1);
+ break;
+ }
+ case ECHO_DRV_OUTPUT_BINARY:
+ {
+ ErlDrvBinary *bin = driver_alloc_binary(len-1);
+ memcpy(&bin->orig_bytes, buf+1, len-1);
+ driver_output_binary(port, "a", 1, bin, 1, len - 2);
+ driver_free_binary(bin);
+ break;
+ }
+ case ECHO_DRV_OUTPUTV:
+ {
+ ErlIOVec iov;
+ ErlDrvSizeT sz;
+ driver_enq(port, buf + 1, len - 1);
+ sz = driver_peekqv(port, &iov);
+ driver_outputv(port, "a", 1, &iov, 0);
+ driver_deq(port, sz);
+ break;
+ }
+ case ECHO_DRV_SET_TIMER:
+ {
+ driver_set_timer(port, 10);
+ break;
+ }
+ case ECHO_DRV_FAILURE_EOF:
+ {
+ driver_failure_eof(port);
+ break;
+ }
+ case ECHO_DRV_FAILURE_ATOM:
+ {
+ driver_failure_atom(port, buf+1);
+ break;
+ }
+ case ECHO_DRV_FAILURE_POSIX:
+ {
+ driver_failure_posix(port, EAGAIN);
+ break;
+ }
+ case ECHO_DRV_FAILURE:
+ {
+ driver_failure(port, buf[1]);
+ break;
+ }
+ case ECHO_DRV_OUTPUT_TERM:
+ case ECHO_DRV_DRIVER_OUTPUT_TERM:
+ case ECHO_DRV_SEND_TERM:
+ case ECHO_DRV_DRIVER_SEND_TERM:
+ {
+ ErlDrvTermData term[] = {
+ ERL_DRV_ATOM, driver_mk_atom("echo"),
+ ERL_DRV_PORT, driver_mk_port(port),
+ ERL_DRV_BUF2BINARY, (ErlDrvTermData)(buf+1),
+ (ErlDrvTermData)(len - 1),
+ ERL_DRV_TUPLE, 3};
+ switch (buf[0]) {
+ case ECHO_DRV_OUTPUT_TERM:
+ erl_drv_output_term(driver_mk_port(port), term, sizeof(term) / sizeof(ErlDrvTermData));
+ break;
+ case ECHO_DRV_DRIVER_OUTPUT_TERM:
+ driver_output_term(port, term, sizeof(term) / sizeof(ErlDrvTermData));
+ break;
+ case ECHO_DRV_SEND_TERM:
+ driver_send_term(port, data_p->caller,
+ term, sizeof(term) / sizeof(ErlDrvTermData));
+ break;
+ case ECHO_DRV_DRIVER_SEND_TERM:
+ erl_drv_send_term(driver_mk_port(port), data_p->caller,
+ term, sizeof(term) / sizeof(ErlDrvTermData));
+ break;
+ }
+ break;
+ }
+ case ECHO_DRV_SAVE_CALLER:
+ data_p->caller = driver_caller(port);
+ break;
+ default:
+ break;
+ }
+}
+
+static void echo_drv_finish() {
+
+}
+
+static ErlDrvSSizeT echo_drv_control(ErlDrvData drv_data,
+ unsigned int command,
+ char *buf, ErlDrvSizeT len,
+ char **rbuf, ErlDrvSizeT rlen)
+{
+ if ((len - 1) > rlen)
+ *rbuf = driver_alloc(len - 1);
+ memcpy(*rbuf, buf+1, len-1);
+ return len-1;
+}
+
+static void echo_drv_timeout(ErlDrvData drv_data)
+{
+
+}
+
+static ErlDrvSSizeT echo_drv_call(ErlDrvData drv_data,
+ unsigned int command,
+ char *buf, ErlDrvSizeT len,
+ char **rbuf, ErlDrvSizeT rlen,
+ unsigned int *flags)
+{
+ if ((len - command) > rlen)
+ *rbuf = driver_alloc(len - command);
+ memcpy(*rbuf, buf+command, len-command);
+ return len-command;
+}
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index 5bb216ff79..61a68f9759 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
@@ -1003,7 +1003,7 @@ low_prio_test(Config) when is_list(Config) ->
process_flag(trap_exit, true),
S = spawn_link(?MODULE, prio_server, [0, 0]),
PCs = spawn_prio_clients(S, erlang:system_info(schedulers_online)),
- timer:sleep(2000),
+ ct:sleep({seconds,3}),
lists:foreach(fun (P) -> exit(P, kill) end, PCs),
S ! exit,
receive {'EXIT', S, {A, B}} -> check_prio(A, B) end,
diff --git a/erts/emulator/test/pseudoknot_SUITE.erl b/erts/emulator/test/pseudoknot_SUITE.erl
index 58ef3cd563..ed4d40ac65 100644
--- a/erts/emulator/test/pseudoknot_SUITE.erl
+++ b/erts/emulator/test/pseudoknot_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/test/random_iolist.erl b/erts/emulator/test/random_iolist.erl
index 6da7da04de..555f063e0a 100644
--- a/erts/emulator/test/random_iolist.erl
+++ b/erts/emulator/test/random_iolist.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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.
diff --git a/erts/emulator/test/receive_SUITE.erl b/erts/emulator/test/receive_SUITE.erl
index 6097e54219..83653a7a36 100644
--- a/erts/emulator/test/receive_SUITE.erl
+++ b/erts/emulator/test/receive_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% 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.
diff --git a/erts/emulator/test/ref_SUITE.erl b/erts/emulator/test/ref_SUITE.erl
index 287a2ffb73..5f519d522e 100644
--- a/erts/emulator/test/ref_SUITE.erl
+++ b/erts/emulator/test/ref_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/test/register_SUITE.erl b/erts/emulator/test/register_SUITE.erl
index ad8a9c29f3..43ae749498 100644
--- a/erts/emulator/test/register_SUITE.erl
+++ b/erts/emulator/test/register_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% 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.
diff --git a/erts/emulator/test/save_calls_SUITE.erl b/erts/emulator/test/save_calls_SUITE.erl
index bbdc2e6688..aae7651f6d 100644
--- a/erts/emulator/test/save_calls_SUITE.erl
+++ b/erts/emulator/test/save_calls_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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.
@@ -60,7 +60,7 @@ dont_break_reductions(Config) when is_list(Config) ->
RPS1 = reds_per_sched(0),
RPS2 = reds_per_sched(20),
Diff = abs(RPS1 - RPS2),
- true = (Diff < (0.05 * RPS1)),
+ true = (Diff < (0.2 * RPS1)),
ok.
@@ -114,7 +114,7 @@ save_calls_1(Config) when is_list(Config) ->
save_calls_1() ->
erlang:process_flag(self(), save_calls, 0),
{last_calls, false} = process_info(self(), last_calls),
-
+
erlang:process_flag(self(), save_calls, 10),
{last_calls, _L1} = process_info(self(), last_calls),
?MODULE:do_bipp(),
@@ -132,11 +132,22 @@ save_calls_1() ->
X ->
ct:fail({l21, X})
end,
-
+
erlang:process_flag(self(), save_calls, 10),
{last_calls, L3} = process_info(self(), last_calls),
+ true = (L3 /= false),
L31 = lists:filter(fun is_local_function/1, L3),
[] = L31,
+ erlang:process_flag(self(), save_calls, 0),
+
+ %% Also check that it works on another process ...
+ Pid = spawn(fun () -> receive after infinity -> ok end end),
+ erlang:process_flag(Pid, save_calls, 10),
+ {last_calls, L4} = process_info(Pid, last_calls),
+ true = (L4 /= false),
+ L41 = lists:filter(fun is_local_function/1, L4),
+ [] = L41,
+ exit(Pid,kill),
ok.
do_bipp() ->
diff --git a/erts/emulator/test/scheduler_SUITE.erl b/erts/emulator/test/scheduler_SUITE.erl
index 64c280b198..6b49b68ec8 100644
--- a/erts/emulator/test/scheduler_SUITE.erl
+++ b/erts/emulator/test/scheduler_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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.
@@ -876,7 +876,7 @@ get_affinity_mask(_Port, _Status, Affinity) ->
Affinity.
get_affinity_mask() ->
- case test_server:os_type() of
+ case os:type() of
{unix, linux} ->
case catch open_port({spawn, "taskset -p " ++ os:getpid()},
[exit_status]) of
@@ -1733,7 +1733,7 @@ sched_state([], N, DC, DI) ->
{N, DC, DI}
catch
_ : _ ->
- ?t:fail({inconsisten_scheduler_state, {N, DC, DI}})
+ ct:fail({inconsisten_scheduler_state, {N, DC, DI}})
end;
sched_state([{normal, _, _, _} = S | Rest], _S, DC, DI) ->
sched_state(Rest, S, DC, DI);
diff --git a/erts/emulator/test/scheduler_SUITE_data/scheduler_SUITE.c b/erts/emulator/test/scheduler_SUITE_data/scheduler_SUITE.c
index 022858c114..ab4863337f 100644
--- a/erts/emulator/test/scheduler_SUITE_data/scheduler_SUITE.c
+++ b/erts/emulator/test/scheduler_SUITE_data/scheduler_SUITE.c
@@ -1,4 +1,6 @@
+#ifndef __WIN32__
#include <unistd.h>
+#endif
#include "erl_nif.h"
static int
@@ -15,8 +17,12 @@ static ERL_NIF_TERM
dirty_sleeper(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
#ifdef ERL_NIF_DIRTY_SCHEDULER_SUPPORT
+#ifdef __WIN32__
+ Sleep(3000);
+#else
sleep(3);
#endif
+#endif
return enif_make_atom(env, "ok");
}
diff --git a/erts/emulator/test/send_term_SUITE.erl b/erts/emulator/test/send_term_SUITE.erl
index 75161389b1..8afe4e4ac1 100644
--- a/erts/emulator/test/send_term_SUITE.erl
+++ b/erts/emulator/test/send_term_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/test/sensitive_SUITE.erl b/erts/emulator/test/sensitive_SUITE.erl
index e2236774a7..c3e303bbd1 100644
--- a/erts/emulator/test/sensitive_SUITE.erl
+++ b/erts/emulator/test/sensitive_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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.
@@ -311,7 +311,7 @@ gc_trace(Config) when is_list(Config) ->
wait_trace(Self),
{messages,Messages} = process_info(Tracer, messages),
- [{trace,Self,gc_start,_},{trace,Self,gc_end,_}] = Messages,
+ [{trace,Self,gc_major_start,_},{trace,Self,gc_major_end,_}] = Messages,
unlink(Tracer), exit(Tracer, kill),
ok.
diff --git a/erts/emulator/test/signal_SUITE.erl b/erts/emulator/test/signal_SUITE.erl
index 63397fbbb4..0b11fa13f5 100644
--- a/erts/emulator/test/signal_SUITE.erl
+++ b/erts/emulator/test/signal_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2006-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.
diff --git a/erts/emulator/test/smoke_test_SUITE.erl b/erts/emulator/test/smoke_test_SUITE.erl
index 900dd124c0..042c7225d5 100644
--- a/erts/emulator/test/smoke_test_SUITE.erl
+++ b/erts/emulator/test/smoke_test_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2011-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.
diff --git a/erts/emulator/test/statistics_SUITE.erl b/erts/emulator/test/statistics_SUITE.erl
index 7d5b07f21f..71ef003b25 100644
--- a/erts/emulator/test/statistics_SUITE.erl
+++ b/erts/emulator/test/statistics_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/system_info_SUITE.erl b/erts/emulator/test/system_info_SUITE.erl
index ffea5bc15b..f31d474c20 100644
--- a/erts/emulator/test/system_info_SUITE.erl
+++ b/erts/emulator/test/system_info_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2005-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.
diff --git a/erts/emulator/test/system_profile_SUITE.erl b/erts/emulator/test/system_profile_SUITE.erl
index 6d80d436ba..2e359b11ce 100644
--- a/erts/emulator/test/system_profile_SUITE.erl
+++ b/erts/emulator/test/system_profile_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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.
@@ -27,7 +27,7 @@
system_profile_on_and_off/1,
runnable_procs/1, runnable_ports/1,
dont_profile_profiler/1,
- scheduler/1]).
+ scheduler/1, sane_location/1]).
-export([profiler_process/1, ring_loop/1, port_echo_start/0,
list_load/0, run_load/2]).
@@ -40,7 +40,8 @@ suite() ->
all() ->
[system_profile_on_and_off, runnable_procs,
- runnable_ports, scheduler, dont_profile_profiler].
+ runnable_ports, scheduler, dont_profile_profiler,
+ sane_location].
%% No specification clause needed for an init function in a conf case!!!
@@ -183,6 +184,33 @@ dont_profile_profiler(Config) when is_list(Config) ->
exit(Pid,kill),
ok.
+%% Check sane location (of exits)
+sane_location(Config) when is_list(Config) ->
+ Check = spawn_link(fun() -> flush_sane_location() end),
+ erlang:system_profile(Check, [runnable_procs]),
+ Me = self(),
+ Pids = [spawn_link(fun() -> wat(Me) end) || _ <- lists:seq(1,100)],
+ [receive {Pid,ok} -> ok end || Pid <- Pids],
+ Check ! {Me, done},
+ receive {Check,ok} -> ok end,
+ ok.
+
+wat(Pid) ->
+ Pid ! {self(), ok}.
+
+flush_sane_location() ->
+ receive
+ {profile,_,_,{M,F,A},_} when is_atom(M), is_atom(F),
+ is_integer(A) ->
+ flush_sane_location();
+ {profile,_,_,0,_} ->
+ flush_sane_location();
+ {Pid,done} when is_pid(Pid) ->
+ Pid ! {self(), ok};
+ M ->
+ ct:fail({badness,M})
+ end.
+
%%% Check scheduler profiling
diff --git a/erts/emulator/test/time_SUITE.erl b/erts/emulator/test/time_SUITE.erl
index e6da5e89fa..76d440529f 100644
--- a/erts/emulator/test/time_SUITE.erl
+++ b/erts/emulator/test/time_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/timer_bif_SUITE.erl b/erts/emulator/test/timer_bif_SUITE.erl
index fa72700604..a5f11bd959 100644
--- a/erts/emulator/test/timer_bif_SUITE.erl
+++ b/erts/emulator/test/timer_bif_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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.
diff --git a/erts/emulator/test/trace_SUITE.erl b/erts/emulator/test/trace_SUITE.erl
index dcd5e95434..da6a6bdea4 100644
--- a/erts/emulator/test/trace_SUITE.erl
+++ b/erts/emulator/test/trace_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
@@ -24,14 +24,15 @@
%%% Tests the trace BIF.
%%%
--export([all/0, suite/0,
- receive_trace/1, self_send/1,
+-export([all/0, suite/0, link_receive_call_correlation/0,
+ receive_trace/1, link_receive_call_correlation/1, self_send/1,
timeout_trace/1, send_trace/1,
- procs_trace/1, dist_procs_trace/1,
+ procs_trace/1, dist_procs_trace/1, procs_new_trace/1,
suspend/1, mutual_suspend/1, suspend_exit/1, suspender_exit/1,
suspend_system_limit/1, suspend_opts/1, suspend_waiting/1,
new_clear/1, existing_clear/1,
set_on_spawn/1, set_on_first_spawn/1, cpu_timestamp/1,
+ set_on_link/1, set_on_first_link/1,
system_monitor_args/1, more_system_monitor_args/1,
system_monitor_long_gc_1/1, system_monitor_long_gc_2/1,
system_monitor_large_heap_1/1, system_monitor_large_heap_2/1,
@@ -48,12 +49,14 @@ suite() ->
{timetrap, {seconds, 5}}].
all() ->
- [cpu_timestamp, receive_trace, self_send, timeout_trace,
+ [cpu_timestamp, receive_trace, link_receive_call_correlation,
+ self_send, timeout_trace,
send_trace, procs_trace, dist_procs_trace, suspend,
mutual_suspend, suspend_exit, suspender_exit,
suspend_system_limit, suspend_opts, suspend_waiting,
new_clear, existing_clear, set_on_spawn,
- set_on_first_spawn, system_monitor_args,
+ set_on_first_spawn, set_on_link, set_on_first_link,
+ system_monitor_args,
more_system_monitor_args, system_monitor_long_gc_1,
system_monitor_long_gc_2, system_monitor_large_heap_1,
system_monitor_long_schedule,
@@ -81,29 +84,235 @@ cpu_timestamp(Config) when is_list(Config) ->
receive_trace(Config) when is_list(Config) ->
Receiver = fun_spawn(fun receiver/0),
- process_flag(trap_exit, true),
%% Trace the process; make sure that we receive the trace messages.
1 = erlang:trace(Receiver, true, ['receive']),
Hello = {hello, world},
Receiver ! Hello,
- {trace, Receiver, 'receive', Hello} = receive_first(),
+ {trace, Receiver, 'receive', Hello} = receive_first_trace(),
Hello2 = {hello, again, world},
Receiver ! Hello2,
- {trace, Receiver, 'receive', Hello2} = receive_first(),
+ {trace, Receiver, 'receive', Hello2} = receive_first_trace(),
receive_nothing(),
+ %% Test 'receive' with matchspec
+ F1 = fun ({Pat, IsMatching}) ->
+ set_trace_pattern('receive', Pat, []),
+ Receiver ! Hello,
+ case IsMatching of
+ true ->
+ {trace, Receiver, 'receive', Hello} = receive_first_trace();
+ false ->
+ ok
+ end,
+ receive_nothing()
+ end,
+ From = self(),
+ Node = node(),
+ lists:foreach(F1, [{no, true},
+ {[{[Node, undefined,"Unexpected"],[],[]}], false},
+ {[{[Node, From,'_'],[],[]}], true},
+ {[{[Node, '$1','_'],[{'=/=','$1',From}],[]}], false},
+ {[{['$1', '_','_'],[{'=:=','$1',Node}],[]}], true},
+ {false, false},
+ {true, true}]),
+
+ %% Remote messages
+ OtherName = atom_to_list(?MODULE)++"_receive_trace",
+ {ok, OtherNode} = start_node(OtherName),
+ RemoteProc = spawn_link(OtherNode, ?MODULE, process, [self()]),
+ io:format("RemoteProc = ~p ~n", [RemoteProc]),
+
+ RemoteProc ! {send_please, Receiver, Hello},
+ {trace, Receiver, 'receive', Hello} = receive_first_trace(),
+ RemoteProc ! {send_please, Receiver, 99},
+ {trace, Receiver, 'receive', 99} = receive_first_trace(),
+
+ %% Remote with matchspec
+ F2 = fun (To, {Pat, IsMatching}) ->
+ set_trace_pattern('receive', Pat, []),
+ RemoteProc ! {send_please, To, Hello},
+ case IsMatching of
+ true ->
+ {trace, Receiver, 'receive', Hello} = receive_first_trace();
+ false ->
+ ok
+ end,
+ receive_nothing()
+ end,
+ F2(Receiver, {no, true}),
+ F2(Receiver, {[{[OtherNode, undefined,"Unexpected"],[],[]}], false}),
+ F2(Receiver, {[{[OtherNode, RemoteProc,'_'],[],[]},
+ {[OtherNode, undefined,'_'],[],[]}], true}),
+ F2(Receiver, {[{[OtherNode, '$1','_'],
+ [{'orelse',{'=:=','$1',undefined},{'=/=',{node,'$1'},{node}}}],
+ []}], true}),
+ F2(Receiver, {[{['$1', '_','_'], [{'=:=','$1',OtherNode}], []}], true}),
+ F2(Receiver, {false, false}),
+ F2(Receiver, {true, true}),
+
+ %% Remote to named with matchspec
+ Name = trace_SUITE_receiver,
+ register(Name, Receiver),
+ NN = {Name, node()},
+ F2(NN, {no, true}),
+ F2(NN, {[{[OtherNode, undefined,"Unexpected"],[],[]}], false}),
+ F2(NN, {[{[OtherNode, RemoteProc,'_'],[],[]},
+ {[OtherNode, undefined,'_'],[],[]}], true}),
+ F2(NN, {[{[OtherNode, '$1','_'],
+ [{'orelse',{'=:=','$1',undefined},{'=/=',{node,'$1'},{node}}}],
+ []}], true}),
+ F2(NN, {[{['$1', '_','_'], [{'==','$1',OtherNode}], []}], true}),
+ F2(NN, {false, false}),
+ F2(NN, {true, true}),
+
+ unlink(RemoteProc),
+ true = stop_node(OtherNode),
+
+ %% Timeout
+ Receiver ! {set_timeout, 10},
+ {trace, Receiver, 'receive', {set_timeout, 10}} = receive_first_trace(),
+ {trace, Receiver, 'receive', timeout} = receive_first_trace(),
+ erlang:trace_pattern('receive', [{[clock_service,undefined,timeout], [], []}], []),
+ Receiver ! {set_timeout, 7},
+ {trace, Receiver, 'receive', timeout} = receive_first_trace(),
+ erlang:trace_pattern('receive', true, []),
+
%% Another process should not be able to trace Receiver.
+ process_flag(trap_exit, true),
Intruder = fun_spawn(fun() -> erlang:trace(Receiver, true, ['receive']) end),
{'EXIT', Intruder, {badarg, _}} = receive_first(),
%% Untrace the process; we should not receive anything.
- 1 = erlang:trace(Receiver, false, ['receive']),
- Receiver ! {hello, there},
- Receiver ! any_garbage,
- receive_nothing(),
+ ?line 1 = erlang:trace(Receiver, false, ['receive']),
+ ?line Receiver ! {hello, there},
+ ?line Receiver ! any_garbage,
+ ?line receive_nothing(),
+
+ %% Verify restrictions in matchspec for 'receive'
+ F3 = fun (Pat) -> {'EXIT', {badarg,_}} = (catch erlang:trace_pattern('receive', Pat, [])) end,
+ WC = ['_','_','_'],
+ F3([{WC,[],[{message, {process_dump}}]}]),
+ F3([{WC,[{is_seq_trace}],[]}]),
+ F3([{WC,[],[{set_seq_token,label,4711}]}]),
+ F3([{WC,[],[{get_seq_token}]}]),
+ F3([{WC,[],[{enable_trace,call}]}]),
+ F3([{WC,[],[{enable_trace,self(),call}]}]),
+ F3([{WC,[],[{disable_trace,call}]}]),
+ F3([{WC,[],[{disable_trace,self(),call}]}]),
+ F3([{WC,[],[{trace,[call],[]}]}]),
+ F3([{WC,[],[{trace,self(),[],[call]}]}]),
+ F3([{WC,[],[{caller}]}]),
+ F3([{WC,[],[{silent,true}]}]),
+
ok.
+%% Tests that receive of a message always happens before a call with
+%% that message and that links/unlinks are ordered together with the
+%% 'receive'.
+link_receive_call_correlation() ->
+ [{timetrap, {minutes, 5}}].
+link_receive_call_correlation(Config) when is_list(Config) ->
+ Receiver = fun_spawn(fun F() ->
+ receive
+ stop -> ok;
+ M -> receive_msg(M), F()
+ end
+ end),
+ process_flag(trap_exit, true),
+
+ %% Trace the process; make sure that we receive the trace messages.
+ 1 = erlang:trace(Receiver, true, ['receive', procs, call, timestamp, scheduler_id]),
+ 1 = erlang:trace_pattern({?MODULE, receive_msg, '_'}, [], [local]),
+
+ Num = 100000,
+
+ (fun F(0) -> [];
+ F(N) ->
+ if N rem 2 == 0 ->
+ link(Receiver);
+ true ->
+ unlink(Receiver)
+ end,
+ [Receiver ! N | F(N-1)]
+ end)(Num),
+
+ Receiver ! stop,
+ MonRef = erlang:monitor(process, Receiver),
+ receive {'DOWN', MonRef, _, _, _} -> ok end,
+ Ref = erlang:trace_delivered(Receiver),
+ receive {trace_delivered, _, Ref} -> ok end,
+
+ Msgs = (fun F() -> receive M -> [M | F()] after 1 -> [] end end)(),
+
+ case check_consistent(Receiver, Num, Num, Num, Msgs) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ ct:log("~p", [Msgs]),
+ ct:fail({error, Reason})
+ end.
+
+-define(schedid, , _).
+
+check_consistent(_Pid, Recv, Call, _LU, [Msg | _]) when Recv > Call ->
+ {error, Msg};
+check_consistent(Pid, Recv, Call, LU, [Msg | Msgs]) ->
+
+ case Msg of
+ {trace, Pid, 'receive', Recv ?schedid} ->
+ check_consistent(Pid,Recv - 1, Call, LU, Msgs);
+ {trace_ts, Pid, 'receive', Recv ?schedid, _} ->
+ check_consistent(Pid,Recv - 1, Call, LU, Msgs);
+
+ {trace, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid} ->
+ check_consistent(Pid,Recv, Call - 1, LU, Msgs);
+ {trace_ts, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid, _} ->
+ check_consistent(Pid,Recv, Call - 1, LU, Msgs);
+
+ %% We check that for each receive we have gotten a
+ %% getting_linked or getting_unlinked message. Also
+ %% if we receive a getting_linked, then the next
+ %% message we expect to receive is an even number
+ %% and odd number for getting_unlinked.
+ {trace, Pid, getting_linked, _Self ?schedid}
+ when Recv rem 2 == 0, Recv == LU ->
+ check_consistent(Pid, Recv, Call, LU - 1, Msgs);
+ {trace_ts, Pid, getting_linked, _Self ?schedid, _}
+ when Recv rem 2 == 0, Recv == LU ->
+ check_consistent(Pid, Recv, Call, LU - 1, Msgs);
+
+ {trace, Pid, getting_unlinked, _Self ?schedid}
+ when Recv rem 2 == 1, Recv == LU ->
+ check_consistent(Pid, Recv, Call, LU - 1, Msgs);
+ {trace_ts, Pid, getting_unlinked, _Self ?schedid, _}
+ when Recv rem 2 == 1, Recv == LU ->
+ check_consistent(Pid, Recv, Call, LU - 1, Msgs);
+
+ {trace,Pid,'receive',Ignore ?schedid}
+ when Ignore == stop; Ignore == timeout ->
+ check_consistent(Pid, Recv, Call, LU, Msgs);
+ {trace_ts,Pid,'receive',Ignore ?schedid,_}
+ when Ignore == stop; Ignore == timeout ->
+ check_consistent(Pid, Recv, Call, LU, Msgs);
+
+ {trace, Pid, exit, normal ?schedid} ->
+ check_consistent(Pid, Recv, Call, LU, Msgs);
+ {trace_ts, Pid, exit, normal ?schedid, _} ->
+ check_consistent(Pid, Recv, Call, LU, Msgs);
+ {'EXIT', Pid, normal} ->
+ check_consistent(Pid, Recv, Call, LU, Msgs);
+ Msg ->
+ {error, Msg}
+ end;
+check_consistent(_, 0, 0, 0, []) ->
+ ok;
+check_consistent(_, Recv, Call, LU, []) ->
+ {error,{Recv, Call, LU}}.
+
+receive_msg(M) ->
+ M.
+
%% Test that traces are generated for messages sent
%% and received to/from self().
self_send(Config) when is_list(Config) ->
@@ -134,8 +343,8 @@ timeout_trace(Config) when is_list(Config) ->
Process = fun_spawn(fun process/0),
1 = erlang:trace(Process, true, ['receive']),
Process ! timeout_please,
- {trace, Process, 'receive', timeout_please} = receive_first(),
- {trace, Process, 'receive', timeout} = receive_first(),
+ {trace, Process, 'receive', timeout_please} = receive_first_trace(),
+ {trace, Process, 'receive', timeout} = receive_first_trace(),
receive_nothing(),
ok.
@@ -148,37 +357,118 @@ send_trace(Config) when is_list(Config) ->
%% Check that a message sent to another process is traced.
1 = erlang:trace(Sender, true, [send]),
+ F1 = fun (Pat) ->
+ set_trace_pattern(send, Pat, []),
+ Sender ! {send_please, Receiver, to_receiver},
+ {trace, Sender, send, to_receiver, Receiver} = receive_first_trace(),
+ receive_nothing()
+ end,
+ lists:foreach(F1, [no,
+ [{[Receiver,to_receiver],[],[]}],
+ [{['_','_'],[],[]}],
+ [{['$1','_'],[{is_pid,'$1'}],[]}],
+ [{['_','$1'],[{is_atom,'$1'}],[]}],
+ true]),
+
+ %% Test {message, Msg}
+ F1m = fun ({Pat, Msg}) ->
+ set_trace_pattern(send, Pat, []),
+ Sender ! {send_please, Receiver, to_receiver},
+ {trace, Sender, send, to_receiver, Receiver, Msg} = receive_first_trace(),
+ receive_nothing()
+ end,
+ lists:foreach(F1m, [{[{['_','_'],[],[{message, 4711}]}], 4711},
+ {[{['_','_'],[],[{message, "4711"}]}], "4711"}
+ ]),
+
+ %% Test {message, {process_dump}}
+ set_trace_pattern(send, [{['_','_'],[],[{message, {process_dump}}]}], []),
Sender ! {send_please, Receiver, to_receiver},
- {trace, Sender, send, to_receiver, Receiver} = receive_first(),
+ {trace, Sender, send, to_receiver, Receiver, ProcDump} = receive_first_trace(),
+ true = is_binary(ProcDump),
receive_nothing(),
+ %% Same test with false match spec
+ F2 = fun (Pat) ->
+ set_trace_pattern(send, Pat, []),
+ Sender ! {send_please, Receiver, to_receiver},
+ receive_nothing()
+ end,
+ lists:foreach(F2, [[{[Sender,to_receiver],[],[]}],
+ [{[Receiver,nomatch],[],[]}],
+ [{['$1','_'],[{is_atom,'$1'}],[]}],
+ [{['_','$1'],[{is_pid,'$1'}],[]}],
+ false,
+ [{['_','_'],[],[{message,false}]}],
+ [{['_','_'],[],[{silent,true}]}]]),
+ erlang:trace_pattern(send, true, []),
+ erlang:trace(Sender, false, [silent]),
+
%% Check that a message sent to another registered process is traced.
register(?MODULE,Receiver),
- Sender ! {send_please, ?MODULE, to_receiver},
- {trace, Sender, send, to_receiver, ?MODULE} = receive_first(),
- receive_nothing(),
+ F3 = fun (Pat) ->
+ set_trace_pattern(send, Pat, []),
+ Sender ! {send_please, ?MODULE, to_receiver},
+ {trace, Sender, send, to_receiver, ?MODULE} = receive_first_trace(),
+ receive_nothing()
+ end,
+ lists:foreach(F3, [no,
+ [{[?MODULE,to_receiver],[],[]}],
+ [{['_','_'],[],[]}],
+ [{['$1','_'],[{is_atom,'$1'}],[]}],
+ [{['_','$1'],[{is_atom,'$1'}],[]}],
+ true]),
+ %% Again with false match spec
+ F4 = fun (Pat) ->
+ set_trace_pattern(send, Pat, []),
+ Sender ! {send_please, ?MODULE, to_receiver},
+ receive_nothing()
+ end,
+ lists:foreach(F4, [[{[nomatch,to_receiver],[],[]}],
+ [{[?MODULE,nomatch],[],[]}],
+ [{['$1','_'],[{is_pid,'$1'}],[]}],
+ [{['_','$1'],[{is_pid,'$1'}],[]}],
+ [{['_','_'],[],[{message,false}]}],
+ [{['_','_'],[],[{silent,true}]}]
+ ]),
unregister(?MODULE),
+ erlang:trace_pattern(send, true, []),
+ erlang:trace(Sender, false, [silent]),
%% Check that a message sent to this process is traced.
- Sender ! {send_please, self(), to_myself},
- receive to_myself -> ok end,
- Self = self(),
- {trace, Sender, send, to_myself, Self} = receive_first(),
- receive_nothing(),
+ F5 = fun (Pat) ->
+ set_trace_pattern(send, Pat, []),
+ Sender ! {send_please, self(), to_myself},
+ receive to_myself -> ok end,
+ Self = self(),
+ {trace, Sender, send, to_myself, Self} = receive_first_trace(),
+ receive_nothing()
+ end,
+ lists:foreach(F5, [no,
+ [{[self(),to_myself],[],[]}],
+ [{['_','_'],[],[]}],
+ true]),
%% Check that a message sent to dead process is traced.
{Pid,Ref} = spawn_monitor(fun() -> ok end),
receive {'DOWN',Ref,_,_,_} -> ok end,
- Sender ! {send_please, Pid, to_dead},
- {trace, Sender, send_to_non_existing_process, to_dead, Pid} = receive_first(),
- receive_nothing(),
+ F6 = fun (Pat) ->
+ set_trace_pattern(send, Pat, []),
+ Sender ! {send_please, Pid, to_dead},
+ {trace, Sender, send_to_non_existing_process, to_dead, Pid} = receive_first_trace(),
+ receive_nothing()
+ end,
+ lists:foreach(F6, [no,
+ [{[Pid,to_dead],[],[]}],
+ [{['_','_'],[],[]}],
+ true]),
%% Check that a message sent to unknown registrated process is traced.
BadargSender = fun_spawn(fun sender/0),
1 = erlang:trace(BadargSender, true, [send]),
unlink(BadargSender),
BadargSender ! {send_please, not_registered, to_unknown},
- {trace, BadargSender, send, to_unknown, not_registered} = receive_first(),
+ {trace, BadargSender, send, to_unknown, not_registered} = receive_first_trace(),
receive_nothing(),
%% Another process should not be able to trace Sender.
@@ -192,8 +482,26 @@ send_trace(Config) when is_list(Config) ->
Sender ! {send_please, self(), to_myself_again},
receive to_myself_again -> ok end,
receive_nothing(),
+
+ {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [global])),
+ {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [local])),
+ {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [meta])),
+ {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [{meta,self()}])),
+ {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [call_count])),
+ {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [call_time])),
+ {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, restart, [])),
+ {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, pause, [])),
+ {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, [{['_','_'],[],[{caller}]}], [])),
+
+ %% Done.
ok.
+set_trace_pattern(_, no, _) -> 0;
+set_trace_pattern(MFA, Pat, Flg) ->
+ R = erlang:trace_pattern(MFA, Pat, Flg),
+ {match_spec, Pat} = erlang:trace_info(MFA, match_spec),
+ R.
+
%% Test trace(Pid, How, [procs]).
procs_trace(Config) when is_list(Config) ->
Name = list_to_atom(atom_to_list(?MODULE)++"_procs_trace"),
@@ -205,15 +513,17 @@ procs_trace(Config) when is_list(Config) ->
Proc2 = spawn(?MODULE, process, [Self]),
io:format("Proc2 = ~p ~n", [Proc2]),
%%
- 1 = erlang:trace(Proc1, true, [procs]),
+ 1 = erlang:trace(Proc1, true, [procs, set_on_first_spawn]),
MFA = {?MODULE, process, [Self]},
%%
%% spawn, link
Proc1 ! {spawn_link_please, Self, MFA},
Proc3 = receive {spawned, Proc1, P3} -> P3 end,
- {trace, Proc1, spawn, Proc3, MFA} = receive_first(),
+ receive {trace, Proc3, spawned, Proc1, MFA} -> ok end,
+ receive {trace, Proc3, getting_linked, Proc1} -> ok end,
+ {trace, Proc1, spawn, Proc3, MFA} = receive_first_trace(),
io:format("Proc3 = ~p ~n", [Proc3]),
- {trace, Proc1, link, Proc3} = receive_first(),
+ {trace, Proc1, link, Proc3} = receive_first_trace(),
receive_nothing(),
%%
%% getting_unlinked by exit()
@@ -221,60 +531,61 @@ procs_trace(Config) when is_list(Config) ->
Reason3 = make_ref(),
Proc1 ! {send_please, Proc3, {exit_please, Reason3}},
receive {Proc1, {'EXIT', Proc3, Reason3}} -> ok end,
- {trace, Proc1, getting_unlinked, Proc3} = receive_first(),
+ receive {trace, Proc3, exit, Reason3} -> ok end,
+ {trace, Proc1, getting_unlinked, Proc3} = receive_first_trace(),
Proc1 ! {trap_exit_please, false},
receive_nothing(),
%%
%% link
Proc1 ! {link_please, Proc2},
- {trace, Proc1, link, Proc2} = receive_first(),
+ {trace, Proc1, link, Proc2} = receive_first_trace(),
receive_nothing(),
%%
%% unlink
Proc1 ! {unlink_please, Proc2},
- {trace, Proc1, unlink, Proc2} = receive_first(),
+ {trace, Proc1, unlink, Proc2} = receive_first_trace(),
receive_nothing(),
%%
%% getting_linked
Proc2 ! {link_please, Proc1},
- {trace, Proc1, getting_linked, Proc2} = receive_first(),
+ {trace, Proc1, getting_linked, Proc2} = receive_first_trace(),
receive_nothing(),
%%
%% getting_unlinked
Proc2 ! {unlink_please, Proc1},
- {trace, Proc1, getting_unlinked, Proc2} = receive_first(),
+ {trace, Proc1, getting_unlinked, Proc2} = receive_first_trace(),
receive_nothing(),
%%
%% register
true = register(Name, Proc1),
- {trace, Proc1, register, Name} = receive_first(),
+ {trace, Proc1, register, Name} = receive_first_trace(),
receive_nothing(),
%%
%% unregister
true = unregister(Name),
- {trace, Proc1, unregister, Name} = receive_first(),
+ {trace, Proc1, unregister, Name} = receive_first_trace(),
receive_nothing(),
%%
%% exit (with registered name, due to link)
Reason4 = make_ref(),
Proc1 ! {spawn_link_please, Self, MFA},
Proc4 = receive {spawned, Proc1, P4} -> P4 end,
- {trace, Proc1, spawn, Proc4, MFA} = receive_first(),
+ {trace, Proc1, spawn, Proc4, MFA} = receive_first_trace(),
io:format("Proc4 = ~p ~n", [Proc4]),
- {trace, Proc1, link, Proc4} = receive_first(),
+ {trace, Proc1, link, Proc4} = receive_first_trace(),
Proc1 ! {register_please, Name, Proc1},
- {trace, Proc1, register, Name} = receive_first(),
+ {trace, Proc1, register, Name} = receive_first_trace(),
Proc4 ! {exit_please, Reason4},
receive {'EXIT', Proc1, Reason4} -> ok end,
- {trace, Proc1, exit, Reason4} = receive_first(),
- {trace, Proc1, unregister, Name} = receive_first(),
+ {trace, Proc1, exit, Reason4} = receive_first_trace(),
+ {trace, Proc1, unregister, Name} = receive_first_trace(),
receive_nothing(),
%%
%% exit (not linked to tracing process)
1 = erlang:trace(Proc2, true, [procs]),
Reason2 = make_ref(),
Proc2 ! {exit_please, Reason2},
- {trace, Proc2, exit, Reason2} = receive_first(),
+ {trace, Proc2, exit, Reason2} = receive_first_trace(),
receive_nothing(),
ok.
@@ -299,51 +610,80 @@ dist_procs_trace(Config) when is_list(Config) ->
Proc1 ! {trap_exit_please, true},
Proc3 = receive {spawned, Proc1, P3} -> P3 end,
io:format("Proc3 = ~p ~n", [Proc3]),
- {trace, Proc1, getting_linked, Proc3} = receive_first(),
+ {trace, Proc1, getting_linked, Proc3} = receive_first_trace(),
Reason3 = make_ref(),
Proc1 ! {send_please, Proc3, {exit_please, Reason3}},
receive {Proc1, {'EXIT', Proc3, Reason3}} -> ok end,
- {trace, Proc1, getting_unlinked, Proc3} = receive_first(),
+ {trace, Proc1, getting_unlinked, Proc3} = receive_first_trace(),
Proc1 ! {trap_exit_please, false},
receive_nothing(),
%%
%% link
Proc1 ! {link_please, Proc2},
- {trace, Proc1, link, Proc2} = receive_first(),
+ {trace, Proc1, link, Proc2} = receive_first_trace(),
receive_nothing(),
%%
%% unlink
Proc1 ! {unlink_please, Proc2},
- {trace, Proc1, unlink, Proc2} = receive_first(),
+ {trace, Proc1, unlink, Proc2} = receive_first_trace(),
receive_nothing(),
%%
%% getting_linked
Proc2 ! {link_please, Proc1},
- {trace, Proc1, getting_linked, Proc2} = receive_first(),
+ {trace, Proc1, getting_linked, Proc2} = receive_first_trace(),
receive_nothing(),
%%
%% getting_unlinked
Proc2 ! {unlink_please, Proc1},
- {trace, Proc1, getting_unlinked, Proc2} = receive_first(),
+ {trace, Proc1, getting_unlinked, Proc2} = receive_first_trace(),
receive_nothing(),
+
%%
%% exit (with registered name, due to link)
Name = list_to_atom(OtherName),
Reason2 = make_ref(),
Proc1 ! {link_please, Proc2},
- {trace, Proc1, link, Proc2} = receive_first(),
+ {trace, Proc1, link, Proc2} = receive_first_trace(),
Proc1 ! {register_please, Name, Proc1},
- {trace, Proc1, register, Name} = receive_first(),
+ {trace, Proc1, register, Name} = receive_first_trace(),
Proc2 ! {exit_please, Reason2},
receive {'EXIT', Proc1, Reason2} -> ok end,
- {trace, Proc1, exit, Reason2} = receive_first(),
- {trace, Proc1, unregister, Name} = receive_first(),
+ {trace, Proc1, exit, Reason2} = receive_first_trace(),
+ {trace, Proc1, unregister, Name} = receive_first_trace(),
receive_nothing(),
%%
%% Done.
true = stop_node(OtherNode),
ok.
+%% Test trace(new, How, [procs]).
+procs_new_trace(Config) when is_list(Config) ->
+ Self = self(),
+ process_flag(trap_exit, true),
+ %%
+ Proc1 = spawn_link(?MODULE, process, [Self]),
+ io:format("Proc1 = ~p ~n", [Proc1]),
+ %%
+ 0 = erlang:trace(new, true, [procs]),
+
+ MFA = {?MODULE, process, [Self]},
+ %%
+ %% spawn, link
+ Proc1 ! {spawn_link_please, Self, MFA},
+ Proc3 = receive {spawned, Proc1, P3} -> P3 end,
+ receive {trace, Proc3, spawned, Proc1, MFA} -> ok end,
+ receive {trace, Proc3, getting_linked, Proc1} -> ok end,
+ io:format("Proc3 = ~p ~n", [Proc3]),
+ receive_nothing(),
+ %%
+ %%
+ %% exit (not linked to tracing process)
+ Reason1 = make_ref(),
+ Proc1 ! {exit_please, Reason1},
+ receive {'EXIT', Proc1, Reason1} -> ok end,
+ {trace, Proc3, exit, Reason1} = receive_first_trace(),
+ receive_nothing(),
+ ok.
@@ -391,6 +731,51 @@ set_on_first_spawn(Config) when is_list(Config) ->
receive_nothing(),
ok.
+%% Tests trace(Pid, How, [set_on_link]).
+
+set_on_link(Config) ->
+ Listener = fun_spawn(fun process/0),
+
+ %% Create and trace a process with the set_on_link flag.
+ %% Make sure it is traced.
+ Father_SOL = fun_spawn(fun process/0),
+ 1 = erlang:trace(Father_SOL, true, [send, set_on_link]),
+ true = is_send_traced(Father_SOL, Listener, sol_father),
+
+ %% Have the process spawn of two children and test that they
+ %% are traced.
+ [Child1, Child2] = spawn_children(Father_SOL, 2),
+ true = is_send_traced(Child1, Listener, child1),
+ true = is_send_traced(Child2, Listener, child2),
+
+ %% Second generation.
+ [Child11, Child12] = spawn_children(Child1, 2),
+ true = is_send_traced(Child11, Listener, child11),
+ true = is_send_traced(Child12, Listener, child12),
+ ok.
+
+%% Tests trace(Pid, How, [set_on_first_spawn]).
+
+set_on_first_link(Config) ->
+ ct:timetrap({seconds, 10}),
+ Listener = fun_spawn(fun process/0),
+
+ %% Create and trace a process with the set_on_first_spawn flag.
+ %% Make sure it is traced.
+ Parent = fun_spawn(fun process/0),
+ 1 = erlang:trace(Parent, true, [send, set_on_first_link]),
+ is_send_traced(Parent, Listener, sol_father),
+
+ %% Have the process spawn off three children and test that the
+ %% first is traced.
+ [Child1, Child2, Child3] = spawn_children(Parent, 3),
+ true = is_send_traced(Child1, Listener, child1),
+ false = is_send_traced(Child2, Listener, child2),
+ false = is_send_traced(Child3, Listener, child3),
+ receive_nothing(),
+ ok.
+
+
%% Tests arguments to erlang:system_monitor/0,1,2
system_monitor_args(Config) when is_list(Config) ->
@@ -1247,7 +1632,8 @@ existing_clear(Config) when is_list(Config) ->
[N, M]),
{flags, []} = erlang:trace_info(Self, flags),
{tracer, []} = erlang:trace_info(Self, tracer),
- M = N + 1, % Since trace could not be enabled on the tracer.
+ M = N, % Used to be N + 1, but from 19.0 the tracer is also traced
+
ok.
%% Test that an invalid flag cause badarg
@@ -1317,14 +1703,21 @@ receive_first() ->
Any -> Any
end.
+%% Waits for and returns the first message in the message queue.
+
+receive_first_trace() ->
+ receive
+ Any when element(1,Any) =:= trace; element(1,Any) =:= trace_ts -> Any
+ end.
+
%% Ensures that there is no message in the message queue.
receive_nothing() ->
receive
Any ->
ct:fail({unexpected_message, Any})
- after 200 ->
- ok
+ after 100 ->
+ ok
end.
@@ -1399,9 +1792,14 @@ sender() ->
%% Just consumes messages from its message queue.
receiver() ->
- receive
- _Any -> receiver()
- end.
+ receiver(infinity).
+
+receiver(Timeout) ->
+ receiver(receive
+ {set_timeout, NewTimeout} -> NewTimeout;
+ _Any -> Timeout
+ after Timeout -> infinity %% reset
+ end).
%% Works as long as it receives CPU time. Will always be RUNNABLE.
@@ -1421,7 +1819,7 @@ fun_spawn(Fun, Args) ->
start_node(Name) ->
Pa = filename:dirname(code:which(?MODULE)),
Cookie = atom_to_list(erlang:get_cookie()),
- test_server:start_node(Name, slave,
+ test_server:start_node(Name, slave,
[{args, "-setcookie " ++ Cookie ++" -pa " ++ Pa}]).
stop_node(Node) ->
diff --git a/erts/emulator/test/trace_bif_SUITE.erl b/erts/emulator/test/trace_bif_SUITE.erl
index b774210456..8c3ffccc45 100644
--- a/erts/emulator/test/trace_bif_SUITE.erl
+++ b/erts/emulator/test/trace_bif_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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.
@@ -247,7 +247,8 @@ receive_trace_msg(Mess) ->
receive_trace_msg_ts({trace_ts, Pid, call, {erlang,F,A}}, PrevTs, TsType) ->
receive
- {trace_ts, Pid, call, {erlang, F, A}, Ts} ->
+ {trace_ts, Pid, call, {erlang, F, A}, Ts} = M ->
+ io:format("~p (PrevTs: ~p)~n",[M, PrevTs]),
check_ts(TsType, PrevTs, Ts),
Ts;
Other ->
@@ -260,7 +261,8 @@ receive_trace_msg_ts({trace_ts, Pid, call, {erlang,F,A}}, PrevTs, TsType) ->
receive_trace_msg_ts_return_from({trace_ts, Pid, return_from, {erlang,F,A}}, PrevTs, TsType) ->
receive
- {trace_ts, Pid, return_from, {erlang, F, A}, _Value, Ts} ->
+ {trace_ts, Pid, return_from, {erlang, F, A}, _Value, Ts} = M ->
+ io:format("~p (PrevTs: ~p)~n",[M, PrevTs]),
check_ts(TsType, PrevTs, Ts),
Ts;
Other ->
@@ -272,7 +274,8 @@ receive_trace_msg_ts_return_from({trace_ts, Pid, return_from, {erlang,F,A}}, Pre
receive_trace_msg_ts_return_to({trace_ts, Pid, return_to, {M,F,A}}, PrevTs, TsType) ->
receive
- {trace_ts, Pid, return_to, {M, F, A}, Ts} ->
+ {trace_ts, Pid, return_to, {M, F, A}, Ts} = Msg ->
+ io:format("~p (PrevTs: ~p)~n",[Msg, PrevTs]),
check_ts(TsType, PrevTs, Ts),
Ts;
Other ->
diff --git a/erts/emulator/test/trace_call_count_SUITE.erl b/erts/emulator/test/trace_call_count_SUITE.erl
index c849668e84..5f871835bc 100644
--- a/erts/emulator/test/trace_call_count_SUITE.erl
+++ b/erts/emulator/test/trace_call_count_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2002-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.
diff --git a/erts/emulator/test/trace_call_time_SUITE.erl b/erts/emulator/test/trace_call_time_SUITE.erl
index 38972c9c02..40c8bc4340 100644
--- a/erts/emulator/test/trace_call_time_SUITE.erl
+++ b/erts/emulator/test/trace_call_time_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-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.
diff --git a/erts/emulator/test/trace_local_SUITE.erl b/erts/emulator/test/trace_local_SUITE.erl
index 24864dcbef..74c05f24e0 100644
--- a/erts/emulator/test/trace_local_SUITE.erl
+++ b/erts/emulator/test/trace_local_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2000-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.
@@ -1224,18 +1224,22 @@ setup(ProcFlags) ->
shutdown() ->
trace_off(),
- {Pid,Mref} = get(slave),
- try erlang:is_process_alive(Pid) of
- true ->
- Pid ! die,
- receive
- {'DOWN',Mref,process,Pid,Reason} ->
- Reason
+ case get(slave) of
+ {Pid,Mref} ->
+ try erlang:is_process_alive(Pid) of
+ true ->
+ Pid ! die,
+ receive
+ {'DOWN',Mref,process,Pid,Reason} ->
+ Reason
+ end;
+ _ ->
+ not_alive
+ catch _:_ ->
+ undefined
end;
_ ->
- not_alive
- catch _:_ ->
- undefined
+ undefined
end.
trace_off() ->
diff --git a/erts/emulator/test/trace_local_SUITE_data/trace_local_dummy.erl b/erts/emulator/test/trace_local_SUITE_data/trace_local_dummy.erl
index a5947de4aa..a886323302 100644
--- a/erts/emulator/test/trace_local_SUITE_data/trace_local_dummy.erl
+++ b/erts/emulator/test/trace_local_SUITE_data/trace_local_dummy.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2000-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.
diff --git a/erts/emulator/test/trace_meta_SUITE.erl b/erts/emulator/test/trace_meta_SUITE.erl
index dcc2cc807b..b6a6fd5404 100644
--- a/erts/emulator/test/trace_meta_SUITE.erl
+++ b/erts/emulator/test/trace_meta_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2002-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.
diff --git a/erts/emulator/test/trace_nif_SUITE.erl b/erts/emulator/test/trace_nif_SUITE.erl
index 49757a414d..8d5bff2a48 100644
--- a/erts/emulator/test/trace_nif_SUITE.erl
+++ b/erts/emulator/test/trace_nif_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% 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.
diff --git a/erts/emulator/test/trace_port_SUITE.erl b/erts/emulator/test/trace_port_SUITE.erl
index d33f18543a..a66563d15b 100644
--- a/erts/emulator/test/trace_port_SUITE.erl
+++ b/erts/emulator/test/trace_port_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1999-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.
@@ -28,10 +28,6 @@
receive_trace/1,
process_events/1,
schedule/1,
- fake_schedule/1,
- fake_schedule_after_register/1,
- fake_schedule_after_getting_linked/1,
- fake_schedule_after_getting_unlinked/1,
gc/1,
default_tracer/1,
tracer_port_crash/1]).
@@ -44,10 +40,7 @@ suite() ->
all() ->
[call_trace, return_trace, send, receive_trace,
- process_events, schedule, fake_schedule,
- fake_schedule_after_register,
- fake_schedule_after_getting_linked,
- fake_schedule_after_getting_unlinked, gc,
+ process_events, schedule, gc,
default_tracer, tracer_port_crash].
%% Test sending call trace messages to a port.
@@ -234,162 +227,6 @@ schedule(Config) when is_list(Config) ->
ok.
-run_fake_sched_test(Fun, Config) when is_function(Fun), is_list(Config) ->
- case catch erlang:system_info(smp_support) of
- true ->
- {skipped,
- "No need for faked schedule out/in trace messages "
- "when smp support is enabled"};
- _ ->
- Fun(Config)
- end.
-
-%% Tests time compensating fake out/in scheduling.
-fake_schedule(Config) when is_list(Config) ->
- run_fake_sched_test(fun fake_schedule_test/1, Config).
-
-fake_schedule_test(Config) when is_list(Config) ->
- Tracer = start_tracer(Config),
- Port = get(tracer_port),
- General = fun_spawn(fun general/0),
- %%
- trac(General, true, [send, running]),
- %%
- %% Test that fake out/in scheduling is not generated unless
- %% both 'running' and 'timestamp' is active.
- [] = erlang:port_control(Port, $h, []),
- General ! nop,
- expect({trace, General, in, {?MODULE, general, 0}}),
- expect({trace, General, out, {?MODULE, general, 0}}),
- expect(),
- %%
- trac(General, false, [running]),
- trac(General, true, [timestamp]),
- %%
- Ref1 = make_ref(),
- Msg1 = {Port, {data, term_to_binary(Ref1)}},
- [] = erlang:port_control(Port, $h, []),
- General ! {send, Tracer, Msg1},
- expect({trace_ts, General, send, Msg1, Tracer, ts}),
- expect(Ref1),
- expect(),
- %%
- trac(General, true, [running]),
- %%
- %% Test that fake out/in scheduling can be generated by the driver
- Ref2 = make_ref(),
- Msg2 = {Port, {data, term_to_binary(Ref2)}},
- [] = erlang:port_control(Port, $h, []),
- General ! {send, Tracer, Msg2},
- {_,_,_,_,Ts} =
- expect({trace_ts, General, in, {?MODULE, general, 0}, ts}),
- expect({trace_ts, General, out, 0, Ts}),
- expect({trace_ts, General, in, 0, ts}),
- expect({trace_ts, General, send, Msg2, Tracer, ts}),
- expect(Ref2),
- expect({trace_ts, General, out, {?MODULE, general, 0}, ts}),
- expect(),
- %%
- %% Test that fake out/in scheduling is not generated after an
- %% 'out' scheduling event
- Ref3 = make_ref(),
- Msg3 = {Port, {data, term_to_binary(Ref3)}},
- General ! {apply, {erlang, port_control, [Port, $h, []]}},
- expect({trace_ts, General, in, {?MODULE, general, 0}, ts}),
- expect({trace_ts, General, out, {?MODULE, general, 0}, ts}),
- General ! {send, Tracer, Msg3},
- expect({trace_ts, General, in, {?MODULE, general, 0}, ts}),
- expect({trace_ts, General, send, Msg3, Tracer, ts}),
- expect(Ref3),
- expect({trace_ts, General, out, {?MODULE, general, 0}, ts}),
- expect(),
- %%
- ok.
-
-%% Tests fake out/in scheduling contents.
-fake_schedule_after_register(Config) when is_list(Config) ->
- run_fake_sched_test(fun fake_schedule_after_register_test/1, Config).
-
-fake_schedule_after_register_test(Config) when is_list(Config) ->
- start_tracer(Config),
- Port = get(tracer_port),
- G1 = fun_spawn(fun general/0),
- G2 = fun_spawn(fun general/0),
- %%
- trac(G1, true, [running, timestamp, procs]),
- trac(G2, true, [running, timestamp]),
- %%
- %% Test fake out/in scheduling after certain messages
- erlang:yield(),
- G2 ! {apply, {erlang, port_control, [Port, $h, []]}},
- G2 ! {apply, {erlang, register, [fake_schedule_after_register, G1]}},
- expect({trace_ts, G2, in, {?MODULE, general, 0}, ts}),
- {_,_,_,_,Ts} =
- expect({trace_ts, G1, register, fake_schedule_after_register, ts}),
- expect({trace_ts, G2, out, 0, Ts}),
- expect({trace_ts, G2, in, 0, ts}),
- expect({trace_ts, G2, out, {?MODULE, general, 0}, ts}),
- expect(),
- %%
- ok.
-
-%% Tests fake out/in scheduling contents.
-fake_schedule_after_getting_linked(Config) when is_list(Config) ->
- run_fake_sched_test(fun fake_schedule_after_getting_linked_test/1,
- Config).
-
-fake_schedule_after_getting_linked_test(Config) when is_list(Config) ->
- start_tracer(Config),
- Port = get(tracer_port),
- G1 = fun_spawn(fun general/0),
- G2 = fun_spawn(fun general/0),
- %%
- trac(G1, true, [running, timestamp, procs]),
- trac(G2, true, [running, timestamp]),
- %%
- %% Test fake out/in scheduling after certain messages
- erlang:yield(),
- G2 ! {apply, {erlang, port_control, [Port, $h, []]}},
- G2 ! {apply, {erlang, link, [G1]}},
- expect({trace_ts, G2, in, {?MODULE, general, 0}, ts}),
- {_,_,_,_,Ts} =
- expect({trace_ts, G1, getting_linked, G2, ts}),
- expect({trace_ts, G2, out, 0, Ts}),
- expect({trace_ts, G2, in, 0, ts}),
- expect({trace_ts, G2, out, {?MODULE, general, 0}, ts}),
- expect(),
- %%
- ok.
-
-%% Tests fake out/in scheduling contents.
-fake_schedule_after_getting_unlinked(Config) when is_list(Config) ->
- run_fake_sched_test(fun fake_schedule_after_getting_unlinked_test/1,
- Config).
-
-fake_schedule_after_getting_unlinked_test(Config) when is_list(Config) ->
- start_tracer(Config),
- Port = get(tracer_port),
- G1 = fun_spawn(fun general/0),
- G2 = fun_spawn(fun general/0),
- %%
- trac(G1, true, [running, procs]),
- trac(G2, true, [running, timestamp]),
- %%
- %% Test fake out/in scheduling after certain messages
- erlang:yield(),
- G2 ! {apply, {erlang, link, [G1]}},
- G2 ! {apply, {erlang, port_control, [Port, $h, []]}},
- G2 ! {apply, {erlang, unlink, [G1]}},
- expect({trace_ts, G2, in, {?MODULE, general, 0}, ts}),
- expect({trace, G1, getting_linked, G2}),
- expect({trace, G1, getting_unlinked, G2}),
- expect({trace_ts, G2, out, 0, ts}),
- expect({trace_ts, G2, in, 0, ts}),
- expect({trace_ts, G2, out, {?MODULE, general, 0}, ts}),
- expect(),
- %%
- ok.
-
%% Test sending garbage collection events to a port.
gc(Config) when is_list(Config) ->
start_tracer(Config),
@@ -399,13 +236,13 @@ gc(Config) when is_list(Config) ->
trace_info(Garber, flags),
Garber ! hi,
- expect({trace,Garber,gc_start,info}),
- expect({trace,Garber,gc_end,info}),
+ expect({trace,Garber,gc_major_start,info}),
+ expect({trace,Garber,gc_major_end,info}),
trac(Garber, true, [garbage_collection,timestamp]),
Garber ! hi,
- expect({trace_ts,Garber,gc_start,info,ts}),
- expect({trace_ts,Garber,gc_end,info,ts}),
+ expect({trace_ts,Garber,gc_major_start,info,ts}),
+ expect({trace_ts,Garber,gc_major_end,info,ts}),
ok.
@@ -440,7 +277,7 @@ default_tracer(Config) when is_list(Config) ->
{tracer, []} = erlang:trace_info(G1, tracer),
G1 ! {apply,{erlang,exit,[normal]}},
io:format("~p = ~p.~n", [M, N]),
- M = N,
+ M = N - 1, % G1 has been started, but Tracer and Port have died
ok.
tracer_port_crash(Config) when is_list(Config) ->
diff --git a/erts/emulator/test/tracer_SUITE.erl b/erts/emulator/test/tracer_SUITE.erl
new file mode 100644
index 0000000000..de44d6656a
--- /dev/null
+++ b/erts/emulator/test/tracer_SUITE.erl
@@ -0,0 +1,627 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-2013. 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%
+%%
+
+-module(tracer_SUITE).
+
+%%%
+%%% Tests the tracer module interface
+%%%
+
+-export([all/0, suite/0,groups/0, init_per_suite/1, end_per_suite/1,
+ init_per_group/2,end_per_group/2, init_per_testcase/2,
+ end_per_testcase/2]).
+-export([load/1, unload/1, reload/1, invalid_tracers/1]).
+-export([send/1, recv/1, spawn/1, exit/1, link/1, unlink/1,
+ getting_linked/1, getting_unlinked/1, register/1, unregister/1,
+ in/1, out/1, gc_start/1, gc_end/1]).
+
+suite() -> [{ct_hooks,[ts_install_cth]},
+ {timetrap, {minutes, 1}}].
+
+all() ->
+ [load, unload, reload, invalid_tracers, {group, basic}].
+
+groups() ->
+ [{ basic, [], [send, recv, spawn, exit, link, unlink, getting_linked,
+ getting_unlinked, register, unregister, in, out,
+ gc_start, gc_end]}].
+
+init_per_suite(Config) ->
+ purge(),
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+init_per_testcase(TC, Config) when TC =:= load; TC =:= reload ->
+
+ DataDir = proplists:get_value(data_dir, Config),
+
+ Pid = erlang:spawn(fun F() ->
+ receive
+ {get, Pid} ->
+ Pid ! DataDir,
+ F()
+ end
+ end),
+ register(tracer_test_config, Pid),
+ Config;
+init_per_testcase(_, Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ case catch tracer_test:enabled(trace_status, self(), self()) of
+ discard ->
+ ok;
+ _ ->
+ tracer_test:load(DataDir)
+ end,
+ Config.
+
+end_per_testcase(TC, _Config) when TC =:= load; TC =:= reload ->
+ purge(),
+ exit(whereis(tracer_test_config), kill),
+ ok;
+end_per_testcase(_, _Config) ->
+ purge(),
+ ok.
+
+load(_Config) ->
+ purge(),
+ 1 = erlang:trace(self(), true, [{tracer, tracer_test, []}, call]),
+ purge(),
+ 1 = erlang:trace_pattern({?MODULE, all, 0}, [],
+ [{meta, tracer_test, []}]),
+ ok.
+
+unload(_Config) ->
+
+ ServerFun = fun F(0, undefined) ->
+ receive
+ {N, Pid} -> F(N, Pid)
+ end;
+ F(0, Pid) ->
+ Pid ! done,
+ F(0, undefined);
+ F(N, Pid) ->
+ ?MODULE:all(),
+ F(N-1, Pid)
+ end,
+
+ Pid = erlang:spawn_link(fun() -> ServerFun(0, undefined) end),
+
+
+ Tc = fun(N) ->
+ Pid ! {N, self()},
+ receive done -> ok after 1000 -> ct:fail(timeout) end,
+ trace_delivered(Pid)
+ end,
+
+ 1 = erlang:trace(Pid, true, [{tracer, tracer_test,
+ {#{ call => trace}, self(), []}},
+ call]),
+ 1 = erlang:trace_pattern({?MODULE, all, 0}, [], []),
+
+ Tc(1),
+ receive _ -> ok after 0 -> ct:fail(timeout) end,
+
+ code:purge(tracer_test),
+ code:delete(tracer_test),
+
+ Tc(1),
+ receive M1 -> ct:fail({unexpected_message, M1}) after 0 -> ok end,
+
+ code:purge(tracer_test),
+
+ Tc(1),
+ receive M2 -> ct:fail({unexpected_message, M2}) after 0 -> ok end,
+
+ ok.
+
+%% This testcase is here to make sure there are not
+%% segfaults when reloading the current nifs.
+reload(_Config) ->
+
+ Tracer = spawn_opt(fun F() -> receive _M -> F() end end,
+ [{message_queue_data, off_heap}]),
+ erlang:link(Tracer),
+ Tracee = spawn_link(fun reload_loop/0),
+
+ [begin
+ Ref = make_ref(),
+ State = {#{ call => trace }, Tracer, [Ref]},
+ erlang:trace(Tracee, true, [{tracer, tracer_test,State}, call]),
+ erlang:trace_pattern({?MODULE, all, 0}, []),
+
+ false = code:purge(tracer_test),
+ {module, _} = code:load_file(tracer_test),
+
+ %% There is a race involved in between when the internal nif cache
+ %% is purged and when the reload_loop needs the tracer module
+ %% so the tracer may be removed or still there.
+ case erlang:trace_info(Tracee, tracer) of
+ {tracer, []} -> ok;
+ {tracer, {tracer_test, State}} -> ok
+ end,
+
+ false = code:purge(tracer_test),
+ true = code:delete(tracer_test),
+ false = code:purge(tracer_test)
+ end || _ <- lists:seq(1,15)],
+
+ ok.
+
+reload_loop() ->
+ ?MODULE:all(),
+ reload_loop().
+
+invalid_tracers(_Config) ->
+ FailTrace = fun(A) ->
+ try erlang:trace(self(), true, A) of
+ _ -> ct:fail(A)
+ catch _:_ -> ok end
+ end,
+
+ FailTrace([{tracer, foobar}, call]),
+ FailTrace([{tracer, foobar, []}, call]),
+ FailTrace([{tracer, make_ref(), []}, call]),
+ FailTrace([{tracer, lists, []}, call]),
+
+ FailTP = fun(MS,FL) ->
+ try erlang:trace_pattern({?MODULE,all,0}, MS, FL) of
+ _ -> ct:fail({MS, FL})
+ catch _:_ -> ok end
+ end,
+
+ FailTP([],[{meta, foobar}]),
+ FailTP([],[{meta, foobar, []}]),
+ FailTP([],[{meta, make_ref(), []}]),
+ FailTP([],[{meta, lists, []}]),
+
+ ok.
+
+
+
+send(_Config) ->
+
+ Self = self(),
+ Tc = fun(Pid) ->
+ Pid ! fun() -> Self ! ok end,
+ receive ok -> ok after 100 -> ct:fail(timeout) end
+ end,
+
+ Expect = fun(Pid, State, EOpts) ->
+ receive
+ Msg ->
+ {Pid, send, State, Pid, ok, Self, Opts} = Msg,
+ check_opts(EOpts, Opts)
+ end
+ end,
+ test(send, Tc, Expect).
+
+
+recv(_Config) ->
+
+ Tc = fun(Pid) ->
+ Pid ! ok
+ end,
+
+ Expect = fun(Pid, State, EOpts) ->
+ receive
+ Msg ->
+ {undefined, 'receive', State, Pid, ok, undefined, Opts} = Msg,
+ check_opts(EOpts, Opts)
+ end
+ end,
+
+ test('receive', Tc, Expect, false).
+
+spawn(_Config) ->
+
+ Tc = fun(Pid) ->
+ Pid ! fun() -> erlang:spawn(lists,seq,[1,10]), ok end
+ end,
+
+ Expect =
+ fun(Pid, State, EOpts) ->
+ receive
+ Msg ->
+ {Pid, spawn, State, Pid, NewPid,
+ {lists,seq,[1,10]}, Opts} = Msg,
+ check_opts(EOpts, Opts),
+ true = is_pid(NewPid) andalso NewPid /= Pid
+ end
+ end,
+
+ test(spawn, procs, Tc, Expect, true).
+
+exit(_Config) ->
+ Tc = fun(Pid) ->
+ Pid ! fun() -> exit end
+ end,
+
+ Expect =
+ fun(Pid, State, EOpts) ->
+ receive
+ Msg ->
+ {Pid, exit, State, Pid, normal, undefined, Opts} = Msg,
+ check_opts(EOpts, Opts)
+ end
+ end,
+
+ test(exit, procs, Tc, Expect, true, true).
+
+link(_Config) ->
+
+ Tc = fun(Pid) ->
+ Pid ! fun() ->
+ SPid = erlang:spawn(fun() -> receive _ -> ok end end),
+ erlang:link(SPid),
+ ok
+ end
+ end,
+
+ Expect =
+ fun(Pid, State, EOpts) ->
+ receive
+ Msg ->
+ {Pid, link, State, Pid, NewPid, undefined, Opts} = Msg,
+ check_opts(EOpts, Opts),
+ true = is_pid(NewPid) andalso NewPid /= Pid
+ end
+ end,
+
+ test(link, procs, Tc, Expect, true).
+
+unlink(_Config) ->
+
+ Tc = fun(Pid) ->
+ Pid ! fun() ->
+ SPid = erlang:spawn(fun() -> receive _ -> ok end end),
+ erlang:link(SPid),
+ erlang:unlink(SPid),
+ ok
+ end
+ end,
+
+ Expect =
+ fun(Pid, State, EOpts) ->
+ receive
+ Msg ->
+ {Pid, unlink, State, Pid, NewPid, undefined, Opts} = Msg,
+ check_opts(EOpts, Opts),
+ true = is_pid(NewPid) andalso NewPid /= Pid
+ end
+ end,
+
+ test(unlink, procs, Tc, Expect, true).
+
+getting_linked(_Config) ->
+
+ Tc = fun(Pid) ->
+ Pid ! fun() ->
+ Self = self(),
+ erlang:spawn(fun() -> erlang:link(Self) end),
+ ok
+ end
+ end,
+
+ Expect =
+ fun(Pid, State, EOpts) ->
+ receive
+ Msg ->
+ {NewPid, getting_linked, State, Pid, NewPid, undefined, Opts} = Msg,
+ check_opts(EOpts, Opts),
+ true = is_pid(NewPid) andalso NewPid /= Pid
+ end
+ end,
+
+ test(getting_linked, procs, Tc, Expect, false).
+
+getting_unlinked(_Config) ->
+ Tc = fun(Pid) ->
+ Pid ! fun() ->
+ Self = self(),
+ erlang:spawn(fun() ->
+ erlang:link(Self),
+ erlang:unlink(Self)
+ end),
+ ok
+ end
+ end,
+
+ Expect =
+ fun(Pid, State, EOpts) ->
+ receive
+ Msg ->
+ {NewPid, getting_unlinked, State, Pid, NewPid, undefined, Opts} = Msg,
+ check_opts(EOpts, Opts),
+ true = is_pid(NewPid) andalso NewPid /= Pid
+ end
+ end,
+
+ test(getting_unlinked, procs, Tc, Expect, false).
+
+register(_Config) ->
+
+ Tc = fun(Pid) ->
+ Pid ! fun() ->
+ erlang:register(?MODULE, self()),
+ erlang:unregister(?MODULE),
+ ok
+ end
+ end,
+
+ Expect =
+ fun(Pid, State, EOpts) ->
+ receive
+ Msg ->
+ {Pid, register, State, Pid, ?MODULE, undefined, Opts} = Msg,
+ check_opts(EOpts, Opts)
+ end
+ end,
+
+ test(register, procs, Tc, Expect, true).
+
+unregister(_Config) ->
+
+ Tc = fun(Pid) ->
+ Pid ! fun() ->
+ erlang:register(?MODULE, self()),
+ erlang:unregister(?MODULE),
+ ok
+ end
+ end,
+
+ Expect =
+ fun(Pid, State, EOpts) ->
+ receive
+ Msg ->
+ {Pid, unregister, State, Pid, ?MODULE, undefined, Opts} = Msg,
+ check_opts(EOpts, Opts)
+ end
+ end,
+
+ test(unregister, procs, Tc, Expect, true).
+
+in(_Config) ->
+
+ Tc = fun(Pid) ->
+ Self = self(),
+ Pid ! fun() -> receive after 1 -> Self ! ok end end,
+ receive ok -> ok end
+ end,
+
+ Expect =
+ fun(Pid, State, EOpts) ->
+ N = (fun F(N) ->
+ receive
+ Msg ->
+ {Pid, in, State, Pid, _,
+ undefined, Opts} = Msg,
+ check_opts(EOpts, Opts),
+ F(N+1)
+ after 0 -> N
+ end
+ end)(0),
+ true = N > 0
+ end,
+
+ test(in, running, Tc, Expect, true).
+
+out(_Config) ->
+ Tc = fun(Pid) ->
+ Pid ! fun() -> receive after 10 -> exit end end,
+ Ref = erlang:monitor(process, Pid),
+ receive {'DOWN', Ref, _, _, _} -> ok end
+ end,
+
+ Expect =
+ fun(Pid, State, EOpts) ->
+ %% We cannot predict how many out schedules there will be
+ N = (fun F(N) ->
+ receive
+ Msg ->
+ {Pid, out, State, Pid, _,
+ undefined, Opts} = Msg,
+ check_opts(EOpts, Opts),
+ F(N+1)
+ after 0 -> N
+ end
+ end)(0),
+ true = N > 0
+ end,
+
+ test(out, running, Tc, Expect, true, true).
+
+gc_start(_Config) ->
+
+ Tc = fun(Pid) ->
+ Pid ! fun() ->
+ erlang:garbage_collect(),
+ ok
+ end
+ end,
+
+ Expect =
+ fun(Pid, State, EOpts) ->
+ receive
+ Msg ->
+ {Pid, gc_major_start, State, Pid, _, undefined, Opts} = Msg,
+ check_opts(EOpts, Opts)
+ end
+ end,
+
+ test(gc_major_start, garbage_collection, Tc, Expect, true).
+
+gc_end(_Config) ->
+
+ Tc = fun(Pid) ->
+ Pid ! fun() ->
+ erlang:garbage_collect(),
+ ok
+ end
+ end,
+
+ Expect =
+ fun(Pid, State, EOpts) ->
+ receive
+ Msg ->
+ {Pid, gc_major_end, State, Pid, _, undefined, Opts} = Msg,
+ check_opts(EOpts, Opts)
+ end
+ end,
+
+ test(gc_major_end, garbage_collection, Tc, Expect, true).
+
+test(Event, Tc, Expect) ->
+ test(Event, Tc, Expect, true).
+test(Event, Tc, Expect, Removes) ->
+ test(Event, Event, Tc, Expect, Removes).
+test(Event, TraceFlag, Tc, Expect, Removes) ->
+ test(Event, TraceFlag, Tc, Expect, Removes, false).
+test(Event, TraceFlag, Tc, Expect, Removes, Dies) ->
+
+ ComplexState = {fun() -> ok end, <<0:(128*8)>>},
+ Opts = #{ timestamp => undefined,
+ scheduler_id => undefined,
+ match_spec_result => true },
+
+ %% Test that trace works
+ State1 = {#{ Event => trace }, self(), ComplexState},
+ Pid1 = start_tracee(),
+ 1 = erlang:trace(Pid1, true, [TraceFlag, {tracer, tracer_test, State1}]),
+ Tc(Pid1),
+ ok = trace_delivered(Pid1),
+
+ Expect(Pid1, State1, Opts),
+ receive M11 -> ct:fail({unexpected, M11}) after 0 -> ok end,
+ if not Dies ->
+ {flags, [TraceFlag]} = erlang:trace_info(Pid1, flags),
+ {tracer, {tracer_test, State1}} = erlang:trace_info(Pid1, tracer),
+ erlang:trace(Pid1, false, [TraceFlag]);
+ true -> ok
+ end,
+
+ %% Test that trace works with scheduler id and timestamp
+ Pid1T = start_tracee(),
+ 1 = erlang:trace(Pid1T, true, [TraceFlag, {tracer, tracer_test, State1},
+ timestamp, scheduler_id]),
+ Tc(Pid1T),
+ ok = trace_delivered(Pid1T),
+
+ Expect(Pid1T, State1, Opts#{ scheduler_id := number,
+ timestamp := timestamp}),
+ receive M11T -> ct:fail({unexpected, M11T}) after 0 -> ok end,
+ if not Dies ->
+ {flags, [scheduler_id, TraceFlag, timestamp]}
+ = erlang:trace_info(Pid1T, flags),
+ {tracer, {tracer_test, State1}} = erlang:trace_info(Pid1T, tracer),
+ erlang:trace(Pid1T, false, [TraceFlag]);
+ true -> ok
+ end,
+
+ %% Test that discard works
+ Pid2 = start_tracee(),
+ State2 = {#{ Event => discard }, self(), ComplexState},
+ 1 = erlang:trace(Pid2, true, [TraceFlag, {tracer, tracer_test, State2}]),
+ Tc(Pid2),
+ ok = trace_delivered(Pid2),
+ receive M2 -> ct:fail({unexpected, M2}) after 0 -> ok end,
+ if not Dies ->
+ {flags, [TraceFlag]} = erlang:trace_info(Pid2, flags),
+ {tracer, {tracer_test, State2}} = erlang:trace_info(Pid2, tracer),
+ erlang:trace(Pid2, false, [TraceFlag]);
+ true ->
+ ok
+ end,
+
+ %% Test that remove works
+ Pid3 = start_tracee(),
+ State3 = {#{ Event => remove }, self(), ComplexState},
+ 1 = erlang:trace(Pid3, true, [TraceFlag, {tracer, tracer_test, State3}]),
+ Tc(Pid3),
+ ok = trace_delivered(Pid3),
+ receive M3 -> ct:fail({unexpected, M3}) after 0 -> ok end,
+ if not Dies ->
+ if Removes ->
+ {flags, []} = erlang:trace_info(Pid3, flags),
+ {tracer, []} = erlang:trace_info(Pid3, tracer);
+ true ->
+ {flags, [TraceFlag]} = erlang:trace_info(Pid3, flags),
+ {tracer, {tracer_test, State3}} = erlang:trace_info(Pid3, tracer)
+ end,
+ erlang:trace(Pid3, false, [TraceFlag]);
+ true ->
+ ok
+ end,
+ ok.
+
+check_opts(#{ scheduler_id := number } = E, #{ scheduler_id := N } = O)
+ when is_integer(N) ->
+ E1 = maps:remove(scheduler_id, E),
+ O1 = maps:remove(scheduler_id, O),
+ if E1 == O1 -> ok;
+ true -> ct:fail({invalid_opts, E, O})
+ end;
+check_opts(Opts, Opts) ->
+ ok;
+check_opts(E,O) ->
+ ct:fail({invalid_opts, E, O}).
+
+start_tracee() ->
+ spawn_link(
+ fun F() ->
+ receive
+ Action when is_function(Action) ->
+ case Action() of
+ ok ->
+ F();
+ Err ->
+ Err
+ end;
+ _ ->
+ F()
+ end
+ end).
+
+trace_delivered(Pid) ->
+ Ref = erlang:trace_delivered(Pid),
+ receive
+ {trace_delivered, Pid, Ref} ->
+ ok
+ after 1000 ->
+ timeout
+ end.
+
+purge() ->
+ %% Make sure module is not loaded
+ case erlang:module_loaded(tracer_test) of
+ true ->
+ code:purge(tracer_test),
+ true = code:delete(tracer_test),
+ code:purge(tracer_test);
+ _ ->
+ ok
+ end.
diff --git a/erts/emulator/test/tracer_SUITE_data/Makefile.src b/erts/emulator/test/tracer_SUITE_data/Makefile.src
new file mode 100644
index 0000000000..154bd70ccc
--- /dev/null
+++ b/erts/emulator/test/tracer_SUITE_data/Makefile.src
@@ -0,0 +1,8 @@
+
+NIF_LIBS = tracer_test@dll@
+
+all: $(NIF_LIBS)
+
+@SHLIB_RULES@
+
+$(NIF_LIBS): tracer_test.c
diff --git a/erts/emulator/test/tracer_SUITE_data/tracer_test.c b/erts/emulator/test/tracer_SUITE_data/tracer_test.c
new file mode 100644
index 0000000000..8b4be1345d
--- /dev/null
+++ b/erts/emulator/test/tracer_SUITE_data/tracer_test.c
@@ -0,0 +1,122 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2009-2014. 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%
+ */
+
+#include "erl_nif.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <limits.h>
+
+/* NIF interface declarations */
+static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info);
+static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info);
+static void unload(ErlNifEnv* env, void* priv_data);
+
+/* The NIFs: */
+static ERL_NIF_TERM enabled(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+static ErlNifFunc nif_funcs[] = {
+ {"enabled", 3, enabled},
+ {"trace", 6, trace}
+};
+
+ERL_NIF_INIT(tracer_test, nif_funcs, load, NULL, upgrade, unload)
+
+static ERL_NIF_TERM atom_discard;
+static ERL_NIF_TERM atom_ok;
+
+#define ASSERT(expr) assert(expr)
+
+static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
+{
+
+ atom_discard = enif_make_atom(env, "discard");
+ atom_ok = enif_make_atom(env, "ok");
+
+ *priv_data = NULL;
+
+ return 0;
+}
+
+static void unload(ErlNifEnv* env, void* priv_data)
+{
+
+}
+
+static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data,
+ ERL_NIF_TERM load_info)
+{
+ if (*old_priv_data != NULL) {
+ return -1; /* Don't know how to do that */
+ }
+ if (*priv_data != NULL) {
+ return -1; /* Don't know how to do that */
+ }
+ if (load(env, priv_data, load_info)) {
+ return -1;
+ }
+ return 0;
+}
+
+static ERL_NIF_TERM enabled(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ int state_arity;
+ const ERL_NIF_TERM *state_tuple;
+ ERL_NIF_TERM value;
+ ASSERT(argc == 3);
+
+ if (!enif_get_tuple(env, argv[1], &state_arity, &state_tuple))
+ return atom_discard;
+
+ if (enif_get_map_value(env, state_tuple[0], argv[0], &value)) {
+ return value;
+ } else {
+ return atom_discard;
+ }
+}
+
+static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ int state_arity;
+ ErlNifPid self, to;
+ ERL_NIF_TERM *tuple, msg;
+ const ERL_NIF_TERM *state_tuple;
+ ASSERT(argc == 6);
+
+ enif_get_tuple(env, argv[1], &state_arity, &state_tuple);
+
+ tuple = enif_alloc(sizeof(ERL_NIF_TERM)*(argc+1));
+ memcpy(tuple+1,argv,sizeof(ERL_NIF_TERM)*argc);
+
+ if (enif_self(env, &self)) {
+ tuple[0] = enif_make_pid(env, &self);
+ } else {
+ tuple[0] = enif_make_atom(env, "undefined");
+ }
+
+ msg = enif_make_tuple_from_array(env, tuple, argc + 1);
+ enif_get_local_pid(env, state_tuple[1], &to);
+ enif_send(env, &to, NULL, msg);
+ enif_free(tuple);
+
+ return atom_ok;
+}
diff --git a/erts/emulator/test/tracer_test.erl b/erts/emulator/test/tracer_test.erl
new file mode 100644
index 0000000000..d4778f4531
--- /dev/null
+++ b/erts/emulator/test/tracer_test.erl
@@ -0,0 +1,55 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-2013. 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%
+%%
+
+-module(tracer_test).
+
+%%%
+%%% Test tracer
+%%%
+
+-export([enabled/3, trace/6]).
+-export([load/1, load/2]).
+-on_load(load/0).
+
+enabled(_, _, _) ->
+ erlang:nif_error(nif_not_loaded).
+
+trace(_, _, _, _, _, _) ->
+ erlang:nif_error(nif_not_loaded).
+
+load() ->
+ case whereis(tracer_test_config) of
+ undefined ->
+ ok;
+ Pid ->
+ Pid ! {get, self()},
+ receive
+ {Conf, Postfix} ->
+ load(Conf, Postfix);
+ Conf ->
+ load(Conf)
+ end
+ end.
+
+load(DataDir) ->
+ load(DataDir, "").
+load(DataDir, Postfix) ->
+ SoFile = atom_to_list(?MODULE) ++ Postfix,
+ erlang:load_nif(filename:join(DataDir, SoFile) , 0).
diff --git a/erts/emulator/test/tuple_SUITE.erl b/erts/emulator/test/tuple_SUITE.erl
index d59d7d12d3..79b681b4d1 100644
--- a/erts/emulator/test/tuple_SUITE.erl
+++ b/erts/emulator/test/tuple_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/emulator/test/unique_SUITE.erl b/erts/emulator/test/unique_SUITE.erl
index e8537e6152..c5aa80c7b4 100644
--- a/erts/emulator/test/unique_SUITE.erl
+++ b/erts/emulator/test/unique_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014. All Rights Reserved.
+%% Copyright Ericsson AB 2014-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.
diff --git a/erts/emulator/test/z_SUITE.erl b/erts/emulator/test/z_SUITE.erl
index 93a03e8f91..d1085c1958 100644
--- a/erts/emulator/test/z_SUITE.erl
+++ b/erts/emulator/test/z_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2006-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.
diff --git a/erts/emulator/utils/beam_makeops b/erts/emulator/utils/beam_makeops
index f805e7cc64..4407f7e289 100755
--- a/erts/emulator/utils/beam_makeops
+++ b/erts/emulator/utils/beam_makeops
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1998-2012. All Rights Reserved.
+# Copyright Ericsson AB 1998-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.
@@ -48,7 +48,7 @@ $pack_shift[4] = ['0', 'BEAM_LOOSE_SHIFT', # Only for 64 bit wordsize
'(3*BEAM_LOOSE_SHIFT)'];
$pack_mask[2] = ['BEAM_LOOSE_MASK', $WHOLE_WORD];
-$pack_mask[3] = ['BEAM_TIGHT_MASK', 'BEAM_TIGHT_MASK', $WHOLE_WORD];
+$pack_mask[3] = ['BEAM_TIGHT_MASK', 'BEAM_TIGHT_MASK', 'BEAM_TIGHT_MASK'];
$pack_mask[4] = ['BEAM_LOOSE_MASK', # Only for 64 bit wordsize
'BEAM_LOOSE_MASK',
'BEAM_LOOSE_MASK',
@@ -113,7 +113,6 @@ my @if_line;
#
my $te_max_vars = 0; # Max number of variables ever needed.
my %gen_transform;
-my %min_window;
my %match_engine_ops; # All opcodes for the match engine.
my %gen_transform_offset;
my @transformations;
@@ -252,6 +251,7 @@ $args_per_word[5] = 3;
$args_per_word[6] = 3;
if ($wordsize == 64) {
+ $pack_mask[3] = ['BEAM_TIGHT_MASK', 'BEAM_TIGHT_MASK', $WHOLE_WORD];
$args_per_word[4] = 4;
}
@@ -382,7 +382,6 @@ while (<>) {
$gen_arity{$name} = $arity;
$gen_to_spec{"$name/$arity"} = undef;
$num_specific{"$name/$arity"} = 0;
- $min_window{"$name/$arity"} = 255;
$obsolete[$op_num] = defined $obsolete;
} else { # Unnumbered generic operation.
push(@unnumbered_generic, [$name, $arity]);
@@ -440,7 +439,6 @@ $num_file_opcodes = @gen_opname;
$gen_arity{$name} = $arity;
$gen_to_spec{"$name/$arity"} = undef;
$num_specific{"$name/$arity"} = 0;
- $min_window{"$name/$arity"} = 255;
}
}
@@ -607,7 +605,7 @@ sub emulator_output {
$is_transformed{$name,$arity} or
error("instruction $key has no specific instruction");
$spec_op = -1 unless defined $spec_op;
- &init_item($name, $arity, $spec_op, $num_specific, $tr, $min_window{$key});
+ &init_item($name, $arity, $spec_op, $num_specific, $tr);
}
}
print "};\n";
@@ -627,19 +625,25 @@ sub emulator_output {
print "#define NUM_SPECIFIC_OPS ", scalar(@op_to_name), "\n";
print "#define SCRATCH_X_REG 1023\n";
print "\n";
- print "#ifdef ARCH_64\n";
- print "# define BEAM_WIDE_MASK 0xFFFFUL\n";
- print "# define BEAM_LOOSE_MASK 0xFFFFUL\n";
- print "# define BEAM_TIGHT_MASK 0xFFFFUL\n";
- print "# define BEAM_WIDE_SHIFT 32\n";
- print "# define BEAM_LOOSE_SHIFT 16\n";
- print "# define BEAM_TIGHT_SHIFT 16\n";
- print "#else\n";
- print "# define BEAM_LOOSE_MASK 0xFFF\n";
- print "# define BEAM_TIGHT_MASK 0xFFC\n";
- print "# define BEAM_LOOSE_SHIFT 16\n";
- print "# define BEAM_TIGHT_SHIFT 10\n";
- print "#endif\n";
+ if ($wordsize == 32) {
+ print "#if defined(ARCH_64)\n";
+ print qq[ #error "32-bit architecture assumed, but ARCH_64 is defined"\n];
+ print "#endif\n";
+ print "#define BEAM_LOOSE_MASK 0xFFF\n";
+ print "#define BEAM_TIGHT_MASK 0xFFC\n";
+ print "#define BEAM_LOOSE_SHIFT 16\n";
+ print "#define BEAM_TIGHT_SHIFT 10\n";
+ } elsif ($wordsize == 64) {
+ print "#if !defined(ARCH_64)\n";
+ print qq[ #error "64-bit architecture assumed, but ARCH_64 not defined"\n];
+ print "#endif\n";
+ print "#define BEAM_WIDE_MASK 0xFFFFUL\n";
+ print "#define BEAM_LOOSE_MASK 0xFFFFUL\n";
+ print "#define BEAM_TIGHT_MASK 0xFFFFUL\n";
+ print "#define BEAM_WIDE_SHIFT 32\n";
+ print "#define BEAM_LOOSE_SHIFT 16\n";
+ print "#define BEAM_TIGHT_SHIFT 16\n";
+ }
print "\n";
#
@@ -1405,8 +1409,7 @@ sub tr_gen {
foreach $ref (@g) {
my($line, $orig_transform, $from_ref, $to_ref) = @$ref;
- my $used_ref = used_vars($from_ref, $to_ref);
- my $so_far = tr_gen_from($line, $used_ref, @$from_ref);
+ my $so_far = tr_gen_from($line, @$from_ref);
tr_gen_to($line, $orig_transform, $so_far, @$to_ref);
}
@@ -1457,58 +1460,14 @@ sub tr_gen {
print "};\n\n";
}
-sub used_vars {
- my($from_ref,$to_ref) = @_;
- my %used;
- my %seen;
-
- foreach my $ref (@$from_ref) {
- my($name,$arity,@ops) = @$ref;
- if ($name =~ /^[.]/) {
- foreach my $var (@ops) {
- $used{$var} = 1;
- }
- } else {
- # Any variable that is used at least twice on the
- # left-hand side is used. (E.g. "move R R".)
- foreach my $op (@ops) {
- my($var, $type, $type_val) = @$op;
- next if $var eq '';
- $used{$var} = 1 if $seen{$var};
- $seen{$var} = 1;
- }
- }
- }
-
- foreach my $ref (@$to_ref) {
- my($name, $arity, @ops) = @$ref;
- if ($name =~ /^[.]/) {
- foreach my $var (@ops) {
- $used{$var} = 1;
- }
- } else {
- foreach my $op (@ops) {
- my($var, $type, $type_val) = @$op;
- next if $var eq '';
- $used{$var} = 1;
- }
- }
- }
- \%used;
-}
-
sub tr_gen_from {
- my($line,$used_ref,@tr) = @_;
+ my($line,@tr) = @_;
my(%var) = ();
my(%var_type);
my($var_num) = 0;
my(@code);
- my($min_window) = 0;
- my(@fix_rest_args);
- my(@fix_pred_funcs);
my($op, $ref); # Loop variables.
my $where = "left side of transformation in line $line: ";
- my %var_used = %$used_ref;
my $may_fail = 0;
my $is_first = 1;
@@ -1530,8 +1489,20 @@ sub tr_gen_from {
my $var;
my(@args);
- push(@fix_pred_funcs, scalar(@code));
- push(@code, [$name, @ops]);
+ foreach $var (@ops) {
+ error($where, "variable '$var' unbound")
+ unless defined $var{$var};
+ if ($var_type{$var} eq 'scalar') {
+ push(@args, "var[$var{$var}]");
+ } else {
+ push(@args, "rest_args");
+ }
+ }
+ my $pi = tr_next_index(\@pred_table, \%pred_table, $name, @args);
+ my $op = make_op("$name()", 'pred', $pi);
+ my @slots = grep(/^\d+/, map { $var{$_} } @ops);
+ op_slot_usage($op, @slots);
+ push(@code, $op);
next;
}
@@ -1544,7 +1515,6 @@ sub tr_gen_from {
$opnum = $gen_opnum{$name,$arity};
push(@code, make_op("$name/$arity", 'next_instr', $opnum));
- $min_window++;
foreach $op (@ops) {
my($var, $type, $type_val, $cond, $val) = @$op;
my $ignored_var = "$var (ignored)";
@@ -1593,15 +1563,21 @@ sub tr_gen_from {
if (defined $var{$var}) {
$ignored_var = '';
$may_fail = 1;
- push(@code, &make_op($var, 'is_same_var', $var{$var}));
+ my $op = make_op($var, 'is_same_var', $var{$var});
+ op_slot_usage($op, $var{$var});
+ push(@code, $op);
} elsif ($type eq '*') {
- #
- # Reserve a hole for a 'rest_args' instruction.
- #
+ foreach my $type (values %var_type) {
+ error("only one use of a '*' variable is " .
+ "allowed on the left hand side of " .
+ "a transformation")
+ if $type eq 'array';
+ }
$ignored_var = '';
- push(@fix_rest_args, scalar(@code));
- push(@code, $var);
- } elsif ($var_used{$var}) {
+ $var{$var} = 'unnumbered';
+ $var_type{$var} = 'array';
+ push(@code, make_op($var, 'rest_args'));
+ } else {
$ignored_var = '';
$var_type{$var} = 'scalar';
$var{$var} = $var_num;
@@ -1629,46 +1605,14 @@ sub tr_gen_from {
#
push(@code, make_op($may_fail ? '' : 'always reached', 'commit'));
- #
- # If there is an rest_args instruction, we must insert its correct
- # variable number (higher than any other).
- #
- my $index;
- &error("only one use of a '*' variable is allowed on the left hand side of a transformation")
- if @fix_rest_args > 1;
- foreach $index (@fix_rest_args) {
- my $var = $code[$index];
- $var{$var} = $var_num++;
- $var_type{$var} = 'array';
- splice(@code, $index, 1, &make_op($var, 'rest_args', $var{$var}));
- }
-
- foreach $index (@fix_pred_funcs) {
- my($name, @ops) = @{$code[$index]};
- my(@args);
- my $var;
-
- foreach $var (@ops) {
- &error($where, "variable '$var' unbound")
- unless defined $var{$var};
- if ($var_type{$var} eq 'scalar') {
- push(@args, "var[$var{$var}]");
- } else {
- push(@args, "var+$var{$var}");
- }
- }
- my $pi = tr_next_index(\@pred_table, \%pred_table, $name, @args);
- splice(@code, $index, 1, make_op("$name()", 'pred', $pi));
- }
-
$te_max_vars = $var_num
if $te_max_vars < $var_num;
- [$min_window, \%var, \%var_type, \@code];
+ [\%var, \%var_type, \@code];
}
sub tr_gen_to {
my($line, $orig_transform, $so_far, @tr) = @_;
- my($min_window, $var_ref, $var_type_ref, $code_ref) = @$so_far;
+ my($var_ref, $var_type_ref, $code_ref) = @$so_far;
my(%var) = %$var_ref;
my(%var_type) = %$var_type_ref;
my(@code) = @$code_ref;
@@ -1697,13 +1641,16 @@ sub tr_gen_to {
if ($var_type{$var} eq 'scalar') {
push(@args, "var[$var{$var}]");
} else {
- push(@args, "var+$var{$var}");
+ push(@args, "rest_args");
}
}
pop(@code); # Get rid of 'commit' instruction
my $index = tr_next_index(\@call_table, \%call_table,
$name, @args);
- push(@code, make_op("$name()", 'call_end', $index));
+ my $op = make_op("$name()", 'call_end', $index);
+ my @slots = grep(/^\d+/, map { $var{$_} } @ops);
+ op_slot_usage($op, @slots);
+ push(@code, $op);
last;
}
@@ -1725,11 +1672,13 @@ sub tr_gen_to {
my($var, $type, $type_val) = @$op;
if ($type eq '*') {
- push(@code, make_op($var, 'store_rest_args', $var{$var}));
+ push(@code, make_op($var, 'store_rest_args'));
} elsif ($var ne '') {
&error($where, "variable '$var' unbound")
unless defined $var{$var};
- push(@code, &make_op($var, 'store_var_next_arg', $var{$var}));
+ my $op = make_op($var, 'store_var_next_arg', $var{$var});
+ op_slot_usage($op, $var{$var});
+ push(@code, $op);
} elsif ($type ne '') {
push(@code, &make_op('', 'store_type', "TAG_$type"));
if ($type_val) {
@@ -1744,6 +1693,10 @@ sub tr_gen_to {
push(@code, make_op('', 'end'))
unless is_instr($code[$#code], 'call_end');
+ tr_maybe_keep(\@code);
+ tr_maybe_rename(\@code);
+ tr_remove_unused(\@code);
+
#
# Chain together all codes segments having the same first operation.
#
@@ -1752,8 +1705,6 @@ sub tr_gen_to {
my($dummy, $arity);
($dummy, $op, $arity) = @$first;
my($comment) = "\n/*\n * Line $line:\n * $orig_transform\n */\n\n";
- $min_window{$key} = $min_window
- if $min_window{$key} > $min_window;
my $prev_last;
$prev_last = pop(@{$gen_transform{$key}})
@@ -1771,6 +1722,148 @@ sub tr_gen_to {
push(@{$gen_transform{$key}}, @code),
}
+sub tr_maybe_keep {
+ my($ref) = @_;
+ my @last_instr;
+ my $pos;
+ my $reused_instr;
+
+ for (my $i = 0; $i < @$ref; $i++) {
+ my $instr = $$ref[$i];
+ my($size, $instr_ref, $comment) = @$instr;
+ my($op, @args) = @$instr_ref;
+ if ($op eq 'next_instr') {
+ @last_instr = ($args[0]);
+ } elsif ($op eq 'set_var_next_arg') {
+ push @last_instr, $args[0];
+ } elsif ($op eq 'next_arg') {
+ push @last_instr, 'ignored';
+ } elsif ($op eq 'new_instr') {
+ unless (defined $pos) {
+ # 'new_instr' immediately after 'commit'.
+ $reused_instr = $args[0];
+ return unless shift(@last_instr) == $reused_instr;
+ $pos = $i - 1;
+ } else {
+ # Second 'new_instr' after 'commit'. The instructions
+ # from $pos up to and including $i - 1 rebuilds the
+ # existing instruction exactly.
+ my $name = $gen_opname[$reused_instr];
+ my $arity = $gen_arity[$reused_instr];
+ my $reuse = make_op("$name/$arity", 'keep');
+ splice @$ref, $pos, $i-$pos, ($reuse);
+ return;
+ }
+ } elsif ($op eq 'store_var_next_arg') {
+ return unless shift(@last_instr) eq $args[0];
+ } elsif (defined $pos) {
+ return;
+ }
+ }
+}
+
+sub tr_maybe_rename {
+ my($ref) = @_;
+ my $s = 'left';
+ my $a = 0;
+ my $num_args = 0;
+ my $new_instr;
+ my $first;
+ my $i;
+
+ for ($i = 1; $i < @$ref; $i++) {
+ my $instr = $$ref[$i];
+ my($size, $instr_ref, $comment) = @$instr;
+ my($op, @args) = @$instr_ref;
+
+ if ($s eq 'left') {
+ if ($op eq 'set_var_next_arg') {
+ if ($num_args == $a and $args[0] == $a) {
+ $num_args++;
+ }
+ $a++;
+ } elsif ($op eq 'next_arg') {
+ $a++;
+ } elsif ($op eq 'commit') {
+ $a = 0;
+ $first = $i;
+ $s = 'committed';
+ } elsif ($op eq 'next_instr') {
+ return;
+ }
+ } elsif ($s eq 'committed') {
+ if ($op eq 'new_instr') {
+ $new_instr = $args[0];
+ $a = 0;
+ $s = 'right';
+ } else {
+ return;
+ }
+ } elsif ($s eq 'right') {
+ if ($op eq 'store_var_next_arg' && $args[0] == $a) {
+ $a++;
+ } elsif ($op eq 'end' && $a <= $num_args) {
+ my $name = $gen_opname[$new_instr];
+ my $arity = $gen_arity[$new_instr];
+ my $new_op = make_op("$name/$arity", 'rename', $new_instr);
+ splice @$ref, $first, $i-$first+1, ($new_op);
+ return;
+ } else {
+ return;
+ }
+ }
+ }
+}
+
+sub tr_remove_unused {
+ my($ref) = @_;
+ my %used;
+
+ # Collect all used variables.
+ for my $instr (@$ref) {
+ my $uref = $$instr[3];
+ for my $slot (@$uref) {
+ $used{$slot} = 1;
+ }
+ }
+
+ # Replace 'set_var_next_arg' with 'next_arg' if the variable
+ # is never used.
+ for my $instr (@$ref) {
+ my($size, $instr_ref, $comment) = @$instr;
+ my($op, @args) = @$instr_ref;
+ if ($op eq 'set_var_next_arg') {
+ my $var = $args[0];
+ next if $used{$var};
+ $instr = make_op("$comment (ignored)", 'next_arg');
+ }
+ }
+
+ # Delete a sequence of 'next_arg' instructions when they are
+ # redundant before instructions such as 'commit'.
+ my @opcode;
+ my %ending = (call_end => 1,
+ commit => 1,
+ next_instr => 1,
+ pred => 1,
+ rename => 1,
+ keep => 1);
+ for (my $i = 0; $i < @$ref; $i++) {
+ my $instr = $$ref[$i];
+ my($size, $instr_ref, $comment) = @$instr;
+ my($opcode) = @$instr_ref;
+
+ if ($ending{$opcode}) {
+ my $first = $i;
+ $first-- while $first > 0 and $opcode[$first-1] eq 'next_arg';
+ my $n = $i - $first;
+ splice @$ref, $first, $n;
+ $i -= $n;
+ }
+ $opcode[$i] = $opcode;
+ }
+}
+
sub tr_code_len {
my($sum) = 0;
my($ref);
@@ -1783,7 +1876,12 @@ sub tr_code_len {
sub make_op {
my($comment, @op) = @_;
- [scalar(@op), [@op], $comment];
+ [scalar(@op), [@op], $comment, []];
+}
+
+sub op_slot_usage {
+ my($op_ref, @slots) = @_;
+ $$op_ref[3] = \@slots;
}
sub is_instr {
diff --git a/erts/emulator/utils/beam_strip b/erts/emulator/utils/beam_strip
index 0e7bc46b63..2a2d761940 100755
--- a/erts/emulator/utils/beam_strip
+++ b/erts/emulator/utils/beam_strip
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+# Copyright Ericsson AB 2001-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.
diff --git a/erts/emulator/utils/count b/erts/emulator/utils/count
index c4dd42c949..e0a5e8bb9a 100755
--- a/erts/emulator/utils/count
+++ b/erts/emulator/utils/count
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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.
diff --git a/erts/emulator/utils/loaded b/erts/emulator/utils/loaded
index ab77ffdb6c..5e0a29c014 100644
--- a/erts/emulator/utils/loaded
+++ b/erts/emulator/utils/loaded
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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.
diff --git a/erts/emulator/utils/make_alloc_types b/erts/emulator/utils/make_alloc_types
index 925b9d5810..33afe139a2 100755
--- a/erts/emulator/utils/make_alloc_types
+++ b/erts/emulator/utils/make_alloc_types
@@ -3,7 +3,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2009. All Rights Reserved.
+# Copyright Ericsson AB 2003-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.
diff --git a/erts/emulator/utils/make_compiler_flags b/erts/emulator/utils/make_compiler_flags
index d75ea0817e..47491a4832 100755
--- a/erts/emulator/utils/make_compiler_flags
+++ b/erts/emulator/utils/make_compiler_flags
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2009. All Rights Reserved.
+# Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/utils/make_driver_tab b/erts/emulator/utils/make_driver_tab
index 3203c7110a..ffb5f58ebf 100755
--- a/erts/emulator/utils/make_driver_tab
+++ b/erts/emulator/utils/make_driver_tab
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2013. All Rights Reserved.
+# Copyright Ericsson AB 1999-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.
@@ -31,7 +31,7 @@ my $file = "";
my $nif = "";
my @emu_drivers = ();
my @static_drivers = ();
-my @nifs = ();
+my @static_nifs = ();
my $mode = 1;
while (@ARGV) {
@@ -55,9 +55,14 @@ while (@ARGV) {
push(@static_drivers, $d);
}
if ($mode == 2) {
- push(@nifs, $d);
+ push(@static_nifs, $d);
}
next;
+ } elsif ($mode == 2) {
+ $d = basename $d;
+ $d =~ s/_nif(\..*|)$//; # strip nif.* or just nif
+ push(@static_nifs, $d);
+ next;
}
$d = basename $d;
$d =~ s/drv(\..*|)$//; # strip drv.* or just drv
@@ -120,7 +125,7 @@ typedef struct ErtsStaticNifEntry_ {
EOF
# prototypes
-foreach (@nifs) {
+foreach (@static_nifs) {
my $d = ${_};
$d =~ s/\.debug//; # strip .debug
print "void *".$d."_nif_init(void);\n";
@@ -129,7 +134,7 @@ foreach (@nifs) {
# The array itself
print "static ErtsStaticNifEntry static_nif_tab[] =\n{\n";
-foreach (@nifs) {
+foreach (@static_nifs) {
my $d = ${_};
$d =~ s/\.debug//; # strip .debug
print "{\"${_}\",&".$d."_nif_init},\n";
diff --git a/erts/emulator/utils/make_preload b/erts/emulator/utils/make_preload
index 62c4419589..f489bc2a39 100755
--- a/erts/emulator/utils/make_preload
+++ b/erts/emulator/utils/make_preload
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2012. All Rights Reserved.
+# Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/utils/make_tables b/erts/emulator/utils/make_tables
index 233e95f176..c158778f43 100755
--- a/erts/emulator/utils/make_tables
+++ b/erts/emulator/utils/make_tables
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2013. All Rights Reserved.
+# Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/utils/make_version b/erts/emulator/utils/make_version
index 37bdff181a..e02a42c66d 100755
--- a/erts/emulator/utils/make_version
+++ b/erts/emulator/utils/make_version
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2009. All Rights Reserved.
+# Copyright Ericsson AB 1999-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.
diff --git a/erts/emulator/utils/mkver.c b/erts/emulator/utils/mkver.c
index 6641873712..6183246433 100644
--- a/erts/emulator/utils/mkver.c
+++ b/erts/emulator/utils/mkver.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/emulator/zlib/zlib.mk b/erts/emulator/zlib/zlib.mk
index 53d7badd64..3f0d64d250 100644
--- a/erts/emulator/zlib/zlib.mk
+++ b/erts/emulator/zlib/zlib.mk
@@ -4,7 +4,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2011-2012. All Rights Reserved.
+# Copyright Ericsson AB 2011-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.
diff --git a/erts/epmd/Makefile b/erts/epmd/Makefile
index 25a33462ee..d3308ddedc 100644
--- a/erts/epmd/Makefile
+++ b/erts/epmd/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1998-2009. All Rights Reserved.
+# Copyright Ericsson AB 1998-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.
diff --git a/erts/epmd/epmd.mk b/erts/epmd/epmd.mk
index 08245b784e..b1fd04dc04 100644
--- a/erts/epmd/epmd.mk
+++ b/erts/epmd/epmd.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1998-2009. All Rights Reserved.
+# Copyright Ericsson AB 1998-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.
diff --git a/erts/epmd/src/Makefile b/erts/epmd/src/Makefile
index 3e09a40566..4ae13fe05a 100644
--- a/erts/epmd/src/Makefile
+++ b/erts/epmd/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1998-2009. All Rights Reserved.
+# Copyright Ericsson AB 1998-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.
diff --git a/erts/epmd/src/Makefile.in b/erts/epmd/src/Makefile.in
index 1266be44cb..da4370d5f9 100644
--- a/erts/epmd/src/Makefile.in
+++ b/erts/epmd/src/Makefile.in
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1998-2012. All Rights Reserved.
+# Copyright Ericsson AB 1998-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.
diff --git a/erts/epmd/src/epmd.c b/erts/epmd/src/epmd.c
index 324ae6ac40..44e997e609 100644
--- a/erts/epmd/src/epmd.c
+++ b/erts/epmd/src/epmd.c
@@ -2,7 +2,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
@@ -592,8 +592,10 @@ void epmd_cleanup_exit(EpmdVars *g, int exitval)
free(g->argv);
}
#ifdef HAVE_SYSTEMD_DAEMON
- sd_notifyf(0, "STATUS=Exited.\n"
- "ERRNO=%i", exitval);
+ if (g->is_systemd){
+ sd_notifyf(0, "STATUS=Exited.\n"
+ "ERRNO=%i", exitval);
+ }
#endif /* HAVE_SYSTEMD_DAEMON */
exit(exitval);
}
diff --git a/erts/epmd/src/epmd.h b/erts/epmd/src/epmd.h
index 10483bb5a2..cffcd4ae7a 100644
--- a/erts/epmd/src/epmd.h
+++ b/erts/epmd/src/epmd.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2010. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/epmd/src/epmd_cli.c b/erts/epmd/src/epmd_cli.c
index 6fc05e153e..6fd27d46ea 100644
--- a/erts/epmd/src/epmd_cli.c
+++ b/erts/epmd/src/epmd_cli.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/epmd/src/epmd_int.h b/erts/epmd/src/epmd_int.h
index e127eff097..ed9bbdb8cd 100644
--- a/erts/epmd/src/epmd_int.h
+++ b/erts/epmd/src/epmd_int.h
@@ -2,7 +2,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
@@ -237,8 +237,8 @@ static const struct in6_addr in6addr_loopback =
#define EPMD_TRUE 1
/* If no activity we let select() return every IDLE_TIMEOUT second
- A file descriptor that are idle for CLOSE_TIMEOUT seconds and
- isn't a ALIVE socket is probably hanging and we close it */
+ A file descriptor that has been idle for CLOSE_TIMEOUT seconds and
+ isn't an ALIVE socket has probably hanged and should be closed */
#define IDLE_TIMEOUT 5
#define CLOSE_TIMEOUT 60
diff --git a/erts/epmd/src/epmd_srv.c b/erts/epmd/src/epmd_srv.c
index 75a33f28cb..66c10a65bc 100644
--- a/erts/epmd/src/epmd_srv.c
+++ b/erts/epmd/src/epmd_srv.c
@@ -2,7 +2,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
@@ -447,9 +447,11 @@ void run(EpmdVars *g)
num_sockets = bound;
#ifdef HAVE_SYSTEMD_DAEMON
}
- sd_notifyf(0, "READY=1\n"
- "STATUS=Processing port mapping requests...\n"
- "MAINPID=%lu", (unsigned long) getpid());
+ if (g->is_systemd) {
+ sd_notifyf(0, "READY=1\n"
+ "STATUS=Processing port mapping requests...\n"
+ "MAINPID=%lu", (unsigned long) getpid());
+ }
#endif /* HAVE_SYSTEMD_DAEMON */
dbg_tty_printf(g,2,"entering the main select() loop");
diff --git a/erts/epmd/test/Makefile b/erts/epmd/test/Makefile
index 7c5302a2f1..ad1315440f 100644
--- a/erts/epmd/test/Makefile
+++ b/erts/epmd/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1998-2012. All Rights Reserved.
+# Copyright Ericsson AB 1998-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.
diff --git a/erts/epmd/test/epmd_SUITE.erl b/erts/epmd/test/epmd_SUITE.erl
index 44d3c5a880..763984267a 100644
--- a/erts/epmd/test/epmd_SUITE.erl
+++ b/erts/epmd/test/epmd_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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.
diff --git a/erts/etc/Makefile b/erts/etc/Makefile
index 9a14cee89c..788dfff132 100644
--- a/erts/etc/Makefile
+++ b/erts/etc/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2009. All Rights Reserved.
+# Copyright Ericsson AB 1999-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.
diff --git a/erts/etc/common/Makefile b/erts/etc/common/Makefile
index bbf51d0efd..bad1d3ddb0 100644
--- a/erts/etc/common/Makefile
+++ b/erts/etc/common/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2009. All Rights Reserved.
+# Copyright Ericsson AB 1997-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.
diff --git a/erts/etc/common/Makefile.in b/erts/etc/common/Makefile.in
index 05d925f19f..cb053a1b7c 100644
--- a/erts/etc/common/Makefile.in
+++ b/erts/etc/common/Makefile.in
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2014. All Rights Reserved.
+# Copyright Ericsson AB 1996-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.
diff --git a/erts/etc/common/ct_run.c b/erts/etc/common/ct_run.c
index 548514ee6c..acdfa8c8b8 100644
--- a/erts/etc/common/ct_run.c
+++ b/erts/etc/common/ct_run.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2013. All Rights Reserved.
+ * 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.
@@ -81,13 +81,14 @@ static int eargc; /* Number of arguments in eargv. */
*/
static void error(char* format, ...);
-static char* emalloc(size_t size);
+static void* emalloc(size_t size);
static char* strsave(char* string);
static void push_words(char* src);
static int run_erlang(char* name, char** argv);
static char* get_default_emulator(char* progname);
#ifdef __WIN32__
static char* possibly_quote(char* arg);
+static void* erealloc(void *p, size_t size);
#endif
/*
@@ -141,10 +142,10 @@ int main(int argc, char** argv)
int i;
int len;
/* Convert argv to utf8 */
- argv = malloc((argc+1) * sizeof(char*));
+ argv = emalloc((argc+1) * sizeof(char*));
for (i=0; i<argc; i++) {
len = WideCharToMultiByte(CP_UTF8, 0, wcargv[i], -1, NULL, 0, NULL, NULL);
- argv[i] = malloc(len*sizeof(char));
+ argv[i] = emalloc(len*sizeof(char));
WideCharToMultiByte(CP_UTF8, 0, wcargv[i], -1, argv[i], len, NULL, NULL);
}
argv[argc] = NULL;
@@ -334,7 +335,7 @@ wchar_t *make_commandline(char **argv)
buff = (wchar_t *) emalloc(siz*sizeof(wchar_t));
} else if (siz < num) {
siz = num;
- buff = (wchar_t *) realloc(buff,siz*sizeof(wchar_t));
+ buff = (wchar_t *) erealloc(buff,siz*sizeof(wchar_t));
}
p = buff;
num=0;
@@ -437,15 +438,26 @@ error(char* format, ...)
exit(1);
}
-static char*
+static void*
emalloc(size_t size)
{
- char *p = malloc(size);
+ void *p = malloc(size);
if (p == NULL)
error("Insufficient memory");
return p;
}
+#ifdef __WIN32__
+static void *
+erealloc(void *p, size_t size)
+{
+ void *res = realloc(p, size);
+ if (res == NULL)
+ error("Insufficient memory");
+ return res;
+}
+#endif
+
static char*
strsave(char* string)
{
diff --git a/erts/etc/common/dialyzer.c b/erts/etc/common/dialyzer.c
index c45626606c..6ba3605422 100644
--- a/erts/etc/common/dialyzer.c
+++ b/erts/etc/common/dialyzer.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
@@ -63,13 +63,14 @@ static int eargc; /* Number of arguments in eargv. */
*/
static void error(char* format, ...);
-static char* emalloc(size_t size);
+static void* emalloc(size_t size);
static char* strsave(char* string);
static void push_words(char* src);
static int run_erlang(char* name, char** argv);
static char* get_default_emulator(char* progname);
#ifdef __WIN32__
static char* possibly_quote(char* arg);
+static void* erealloc(void *p, size_t size);
#endif
/*
@@ -164,10 +165,10 @@ int main(int argc, char** argv)
#ifdef __WIN32__
int len;
/* Convert argv to utf8 */
- argv = malloc((argc+1) * sizeof(char*));
+ argv = emalloc((argc+1) * sizeof(char*));
for (i=0; i<argc; i++) {
len = WideCharToMultiByte(CP_UTF8, 0, wcargv[i], -1, NULL, 0, NULL, NULL);
- argv[i] = malloc(len*sizeof(char));
+ argv[i] = emalloc(len*sizeof(char));
WideCharToMultiByte(CP_UTF8, 0, wcargv[i], -1, argv[i], len, NULL, NULL);
}
argv[argc] = NULL;
@@ -310,7 +311,7 @@ wchar_t *make_commandline(char **argv)
buff = (wchar_t *) emalloc(siz*sizeof(wchar_t));
} else if (siz < num) {
siz = num;
- buff = (wchar_t *) realloc(buff,siz*sizeof(wchar_t));
+ buff = (wchar_t *) erealloc(buff,siz*sizeof(wchar_t));
}
p = buff;
num=0;
@@ -413,15 +414,26 @@ error(char* format, ...)
exit(1);
}
-static char*
+static void*
emalloc(size_t size)
{
- char *p = malloc(size);
+ void *p = malloc(size);
if (p == NULL)
error("Insufficient memory");
return p;
}
+#ifdef __WIN32__
+static void *
+erealloc(void *p, size_t size)
+{
+ void *res = realloc(p, size);
+ if (res == NULL)
+ error("Insufficient memory");
+ return res;
+}
+#endif
+
static char*
strsave(char* string)
{
diff --git a/erts/etc/common/erlc.c b/erts/etc/common/erlc.c
index f9d909e01c..b54cb31bef 100644
--- a/erts/etc/common/erlc.c
+++ b/erts/etc/common/erlc.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
@@ -71,13 +71,14 @@ static int pause_after_execution = 0;
static char* process_opt(int* pArgc, char*** pArgv, int offset);
static void error(char* format, ...);
-static char* emalloc(size_t size);
+static void* emalloc(size_t size);
static char* strsave(char* string);
static void push_words(char* src);
static int run_erlang(char* name, char** argv);
static char* get_default_emulator(char* progname);
#ifdef __WIN32__
static char* possibly_quote(char* arg);
+static void* erealloc(void *p, size_t size);
#endif
/*
@@ -171,10 +172,10 @@ int main(int argc, char** argv)
int i;
int len;
/* Convert argv to utf8 */
- argv = malloc((argc+1) * sizeof(char*));
+ argv = emalloc((argc+1) * sizeof(char*));
for (i=0; i<argc; i++) {
len = WideCharToMultiByte(CP_UTF8, 0, wcargv[i], -1, NULL, 0, NULL, NULL);
- argv[i] = malloc(len*sizeof(char));
+ argv[i] = emalloc(len*sizeof(char));
WideCharToMultiByte(CP_UTF8, 0, wcargv[i], -1, argv[i], len, NULL, NULL);
}
argv[argc] = NULL;
@@ -370,7 +371,7 @@ wchar_t *make_commandline(char **argv)
buff = (wchar_t *) emalloc(siz*sizeof(wchar_t));
} else if (siz < num) {
siz = num;
- buff = (wchar_t *) realloc(buff,siz*sizeof(wchar_t));
+ buff = (wchar_t *) erealloc(buff,siz*sizeof(wchar_t));
}
p = buff;
num=0;
@@ -478,15 +479,26 @@ error(char* format, ...)
exit(1);
}
-static char*
+static void*
emalloc(size_t size)
{
- char *p = malloc(size);
+ void *p = malloc(size);
if (p == NULL)
error("Insufficient memory");
return p;
}
+#ifdef __WIN32__
+static void *
+erealloc(void *p, size_t size)
+{
+ void *res = realloc(p, size);
+ if (res == NULL)
+ error("Insufficient memory");
+ return res;
+}
+#endif
+
static char*
strsave(char* string)
{
diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c
index 54da59e50d..5a5021b003 100644
--- a/erts/etc/common/erlexec.c
+++ b/erts/etc/common/erlexec.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
@@ -74,6 +74,7 @@ static const char plusM_au_allocs[]= {
'R', /* driver_alloc */
'S', /* sl_alloc */
'T', /* temp_alloc */
+ 'X', /* exec_alloc */
'Z', /* test_alloc */
'\0'
};
@@ -123,6 +124,7 @@ static char *plusM_other_switches[] = {
"Ytp",
"Ytt",
"Iscs",
+ "Xscs",
NULL
};
@@ -148,6 +150,7 @@ static char *plush_val_switches[] = {
"ms",
"mbs",
"pds",
+ "mqd",
"",
NULL
};
@@ -158,12 +161,6 @@ static char *plusr_val_switches[] = {
NULL
};
-/* +x arguments with values */
-static char *plusx_val_switches[] = {
- "mqd",
- NULL
-};
-
/* +z arguments with values */
static char *plusz_val_switches[] = {
"dbbl",
@@ -984,20 +981,6 @@ int main(int argc, char **argv)
add_Eargs(argv[i+1]);
i++;
break;
- case 'x':
- if (!is_one_of_strings(&argv[i][2], plusx_val_switches)) {
- goto the_default;
- } else {
- if (i+1 >= argc
- || argv[i+1][0] == '-'
- || argv[i+1][0] == '+')
- usage(argv[i]);
- argv[i][0] = '-';
- add_Eargs(argv[i]);
- add_Eargs(argv[i+1]);
- i++;
- }
- break;
case 'z':
if (!is_one_of_strings(&argv[i][2], plusz_val_switches)) {
goto the_default;
@@ -1198,7 +1181,7 @@ usage_aux(void)
"[+S NO_SCHEDULERS:NO_SCHEDULERS_ONLINE] "
"[+SP PERCENTAGE_SCHEDULERS:PERCENTAGE_SCHEDULERS_ONLINE] "
"[+T LEVEL] [+V] [+v] "
- "[+W<i|w|e>] [+x DEFAULT_PROC_FLAGS] [+z MISC_OPTION] [args ...]\n");
+ "[+W<i|w|e>] [+z MISC_OPTION] [args ...]\n");
exit(1);
}
diff --git a/erts/etc/common/escript.c b/erts/etc/common/escript.c
index 7fd02ed436..71c278881c 100644
--- a/erts/etc/common/escript.c
+++ b/erts/etc/common/escript.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2007-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2007-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.
@@ -71,7 +71,7 @@ static int eargc; /* Number of arguments in eargv. */
*/
static void error(char* format, ...);
-static char* emalloc(size_t size);
+static void* emalloc(size_t size);
static void efree(void *p);
static char* strsave(char* string);
static void push_words(char* src);
@@ -79,6 +79,7 @@ static int run_erlang(char* name, char** argv);
static char* get_default_emulator(char* progname);
#ifdef __WIN32__
static char* possibly_quote(char* arg);
+static void* erealloc(void *p, size_t size);
#endif
/*
@@ -418,10 +419,10 @@ main(int argc, char** argv)
int i;
int len;
/* Convert argv to utf8 */
- argv = malloc((argc+1) * sizeof(char*));
+ argv = emalloc((argc+1) * sizeof(char*));
for (i=0; i<argc; i++) {
len = WideCharToMultiByte(CP_UTF8, 0, wcargv[i], -1, NULL, 0, NULL, NULL);
- argv[i] = malloc(len*sizeof(char));
+ argv[i] = emalloc(len*sizeof(char));
WideCharToMultiByte(CP_UTF8, 0, wcargv[i], -1, argv[i], len, NULL, NULL);
}
argv[argc] = NULL;
@@ -594,7 +595,7 @@ wchar_t *make_commandline(char **argv)
buff = (wchar_t *) emalloc(siz*sizeof(wchar_t));
} else if (siz < num) {
siz = num;
- buff = (wchar_t *) realloc(buff,siz*sizeof(wchar_t));
+ buff = (wchar_t *) erealloc(buff,siz*sizeof(wchar_t));
}
p = buff;
num=0;
@@ -694,15 +695,26 @@ error(char* format, ...)
exit(1);
}
-static char*
+static void*
emalloc(size_t size)
{
- char *p = malloc(size);
+ void *p = malloc(size);
if (p == NULL)
error("Insufficient memory");
return p;
}
+#ifdef __WIN32__
+static void *
+erealloc(void *p, size_t size)
+{
+ void *res = realloc(p, size);
+ if (res == NULL)
+ error("Insufficient memory");
+ return res;
+}
+#endif
+
static void
efree(void *p)
{
diff --git a/erts/etc/common/heart.c b/erts/etc/common/heart.c
index 1a826221fb..e931ae4641 100644
--- a/erts/etc/common/heart.c
+++ b/erts/etc/common/heart.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/etc/common/inet_gethost.c b/erts/etc/common/inet_gethost.c
index e298c5e7f7..bc4893b0eb 100644
--- a/erts/etc/common/inet_gethost.c
+++ b/erts/etc/common/inet_gethost.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2012. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
@@ -2646,7 +2646,7 @@ static void *my_realloc(void *old, size_t size)
BOOL create_mesq(MesQ **q)
{
- MesQ *tmp = malloc(sizeof(MesQ));
+ MesQ *tmp = ALLOC(sizeof(MesQ));
tmp->data_present = CreateEvent(NULL, TRUE, FALSE,NULL);
if (tmp->data_present == NULL) {
free(tmp);
diff --git a/erts/etc/common/typer.c b/erts/etc/common/typer.c
index 0aa0996808..77a95ccded 100644
--- a/erts/etc/common/typer.c
+++ b/erts/etc/common/typer.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
@@ -63,13 +63,14 @@ static int eargc; /* Number of arguments in eargv. */
*/
static void error(char* format, ...);
-static char* emalloc(size_t size);
+static void* emalloc(size_t size);
static char* strsave(char* string);
static void push_words(char* src);
static int run_erlang(char* name, char** argv);
static char* get_default_emulator(char* progname);
#ifdef __WIN32__
static char* possibly_quote(char* arg);
+static void* erealloc(void *p, size_t size);
#endif
/*
@@ -118,10 +119,10 @@ main(int argc, char** argv)
int i;
int len;
/* Convert argv to utf8 */
- argv = malloc((argc+1) * sizeof(char*));
+ argv = emalloc((argc+1) * sizeof(char*));
for (i=0; i<argc; i++) {
len = WideCharToMultiByte(CP_UTF8, 0, wcargv[i], -1, NULL, 0, NULL, NULL);
- argv[i] = malloc(len*sizeof(char));
+ argv[i] = emalloc(len*sizeof(char));
WideCharToMultiByte(CP_UTF8, 0, wcargv[i], -1, argv[i], len, NULL, NULL);
}
argv[argc] = NULL;
@@ -232,7 +233,7 @@ wchar_t *make_commandline(char **argv)
buff = (wchar_t *) emalloc(siz*sizeof(wchar_t));
} else if (siz < num) {
siz = num;
- buff = (wchar_t *) realloc(buff,siz*sizeof(wchar_t));
+ buff = (wchar_t *) erealloc(buff,siz*sizeof(wchar_t));
}
p = buff;
num=0;
@@ -332,15 +333,26 @@ error(char* format, ...)
exit(1);
}
-static char*
+static void*
emalloc(size_t size)
{
- char *p = malloc(size);
+ void *p = malloc(size);
if (p == NULL)
error("Insufficient memory");
return p;
}
+#ifdef __WIN32__
+static void *
+erealloc(void *p, size_t size)
+{
+ void *res = realloc(p, size);
+ if (res == NULL)
+ error("Insufficient memory");
+ return res;
+}
+#endif
+
static char*
strsave(char* string)
{
diff --git a/erts/etc/unix/Install.src b/erts/etc/unix/Install.src
index 6634ae31d3..e71308edbe 100644
--- a/erts/etc/unix/Install.src
+++ b/erts/etc/unix/Install.src
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2013. All Rights Reserved.
+# Copyright Ericsson AB 1996-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.
diff --git a/erts/etc/unix/Makefile b/erts/etc/unix/Makefile
index 04ae11de3b..2fa9cd047b 100644
--- a/erts/etc/unix/Makefile
+++ b/erts/etc/unix/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2013. All Rights Reserved.
+# Copyright Ericsson AB 2013-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.
diff --git a/erts/etc/unix/README b/erts/etc/unix/README
index 6bda610a03..adc6db4300 100644
--- a/erts/etc/unix/README
+++ b/erts/etc/unix/README
@@ -1,7 +1,7 @@
%CopyrightBegin%
- Copyright Ericsson AB 1996-2009. All Rights Reserved.
+ Copyright Ericsson AB 1996-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.
diff --git a/erts/etc/unix/RELNOTES b/erts/etc/unix/RELNOTES
index 629867d2ae..7b4a1746fe 100644
--- a/erts/etc/unix/RELNOTES
+++ b/erts/etc/unix/RELNOTES
@@ -1,7 +1,7 @@
%CopyrightBegin%
- Copyright Ericsson AB 1996-2009. All Rights Reserved.
+ Copyright Ericsson AB 1996-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.
diff --git a/erts/etc/unix/cerl.src b/erts/etc/unix/cerl.src
index 2a806bb2f1..c5422ab2ed 100644
--- a/erts/etc/unix/cerl.src
+++ b/erts/etc/unix/cerl.src
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2013. All Rights Reserved.
+# Copyright Ericsson AB 2003-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.
diff --git a/erts/etc/unix/dyn_erl.c b/erts/etc/unix/dyn_erl.c
index 4eebfae50a..d6d2201648 100644
--- a/erts/etc/unix/dyn_erl.c
+++ b/erts/etc/unix/dyn_erl.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009. All Rights Reserved.
+ * Copyright Ericsson AB 2009-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.
diff --git a/erts/etc/unix/erl.src.src b/erts/etc/unix/erl.src.src
index 94c6f9f854..959c099e8f 100644
--- a/erts/etc/unix/erl.src.src
+++ b/erts/etc/unix/erl.src.src
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2012. All Rights Reserved.
+# Copyright Ericsson AB 1996-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.
diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in
index 7b554e71f2..4dc24d68b4 100644
--- a/erts/etc/unix/etp-commands.in
+++ b/erts/etc/unix/etp-commands.in
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2005-2014. All Rights Reserved.
+# Copyright Ericsson AB 2005-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.
@@ -776,7 +776,7 @@ define etp-pid-1
if ($etp_pid_1 & 0xF) == 0x3
if (etp_arch_bits == 64)
if (etp_big_endian)
- set $etp_pid_data = (unsigned) ((((Uint64) $etp_pid_1) >> 36) & 0x0fffffff)
+ set $etp_pid_data = (unsigned) ((((Uint64) $etp_pid_1) >> 35) & 0x0fffffff)
else
set $etp_pid_data = (unsigned) ((((Uint64) $etp_pid_1) >> 4) & 0x0fffffff)
end
diff --git a/erts/etc/unix/etp-thr.py b/erts/etc/unix/etp-thr.py
index 16bc7f4016..fb82dcaf1f 100644
--- a/erts/etc/unix/etp-thr.py
+++ b/erts/etc/unix/etp-thr.py
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2013. All Rights Reserved.
+# Copyright Ericsson AB 2013-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.
diff --git a/erts/etc/unix/etp_commands.erl b/erts/etc/unix/etp_commands.erl
index fe16a71876..fe8f2dd556 100644
--- a/erts/etc/unix/etp_commands.erl
+++ b/erts/etc/unix/etp_commands.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2005-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.
diff --git a/erts/etc/unix/etp_commands.mk b/erts/etc/unix/etp_commands.mk
index def6f7bda0..983ee9f919 100644
--- a/erts/etc/unix/etp_commands.mk
+++ b/erts/etc/unix/etp_commands.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2005-2009. All Rights Reserved.
+# Copyright Ericsson AB 2005-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.
diff --git a/erts/etc/unix/format_man_pages b/erts/etc/unix/format_man_pages
index 7abe65cecb..54f2d90c28 100644
--- a/erts/etc/unix/format_man_pages
+++ b/erts/etc/unix/format_man_pages
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2010. All Rights Reserved.
+# Copyright Ericsson AB 1996-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.
diff --git a/erts/etc/unix/run_erl.c b/erts/etc/unix/run_erl.c
index 44efb975ba..30210ac172 100644
--- a/erts/etc/unix/run_erl.c
+++ b/erts/etc/unix/run_erl.c
@@ -42,9 +42,14 @@
# include "config.h"
#endif
#ifdef HAVE_WORKING_POSIX_OPENPT
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 600
-#endif
+# ifndef _XOPEN_SOURCE
+ /* On OS X and BSD, we must leave _XOPEN_SOURCE undefined in order for
+ * the prototype of vsyslog() to be included.
+ */
+# if !(defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__))
+# define _XOPEN_SOURCE 600
+# endif
+# endif
#endif
#include <sys/types.h>
#include <sys/wait.h>
@@ -64,10 +69,6 @@
#include <termios.h>
#include <time.h>
-#ifdef __ANDROID__
-# include <termios.h>
-#endif
-
#ifdef HAVE_SYSLOG_H
# include <syslog.h>
#endif
@@ -77,6 +78,9 @@
#ifdef HAVE_UTMP_H
# include <utmp.h>
#endif
+#ifdef HAVE_LIBUTIL_H
+# include <libutil.h>
+#endif
#ifdef HAVE_UTIL_H
# include <util.h>
#endif
diff --git a/erts/etc/unix/run_erl.h b/erts/etc/unix/run_erl.h
index cc70a98e52..83bdfdfb19 100644
--- a/erts/etc/unix/run_erl.h
+++ b/erts/etc/unix/run_erl.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/etc/unix/safe_string.c b/erts/etc/unix/safe_string.c
index a5c11d41d8..666022dc61 100644
--- a/erts/etc/unix/safe_string.c
+++ b/erts/etc/unix/safe_string.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/etc/unix/safe_string.h b/erts/etc/unix/safe_string.h
index 5a471f10de..cafd3fc71a 100644
--- a/erts/etc/unix/safe_string.h
+++ b/erts/etc/unix/safe_string.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/etc/unix/setuid_socket_wrap.c b/erts/etc/unix/setuid_socket_wrap.c
index 59ed8eae6f..461c69ee3e 100644
--- a/erts/etc/unix/setuid_socket_wrap.c
+++ b/erts/etc/unix/setuid_socket_wrap.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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.
diff --git a/erts/etc/unix/start.src b/erts/etc/unix/start.src
index 377f5e85c8..bdd146951f 100644
--- a/erts/etc/unix/start.src
+++ b/erts/etc/unix/start.src
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2009. All Rights Reserved.
+# Copyright Ericsson AB 1996-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.
diff --git a/erts/etc/unix/start_erl.src b/erts/etc/unix/start_erl.src
index b889101783..34e0369710 100644
--- a/erts/etc/unix/start_erl.src
+++ b/erts/etc/unix/start_erl.src
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2009. All Rights Reserved.
+# Copyright Ericsson AB 1997-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.
diff --git a/erts/etc/win32/Install.c b/erts/etc/win32/Install.c
index 82bae947d4..43930ff284 100644
--- a/erts/etc/win32/Install.c
+++ b/erts/etc/win32/Install.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/etc/win32/Makefile b/erts/etc/win32/Makefile
index 12c04fc9a5..c6376ebe74 100644
--- a/erts/etc/win32/Makefile
+++ b/erts/etc/win32/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2012. All Rights Reserved.
+# Copyright Ericsson AB 1996-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.
diff --git a/erts/etc/win32/Nmakefile.start_erl b/erts/etc/win32/Nmakefile.start_erl
index cf83713bab..00d22461fb 100644
--- a/erts/etc/win32/Nmakefile.start_erl
+++ b/erts/etc/win32/Nmakefile.start_erl
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1998-2009. All Rights Reserved.
+# Copyright Ericsson AB 1998-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.
diff --git a/erts/etc/win32/beam.rc b/erts/etc/win32/beam.rc
index 9e137ecd62..0aaabf1097 100644
--- a/erts/etc/win32/beam.rc
+++ b/erts/etc/win32/beam.rc
@@ -1,7 +1,7 @@
//
// %CopyrightBegin%
//
-// Copyright Ericsson AB 1997-2009. All Rights Reserved.
+// Copyright Ericsson AB 1997-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.
diff --git a/erts/etc/win32/cygwin_tools/erl b/erts/etc/win32/cygwin_tools/erl
index 51a7be5584..897bbfac87 100755
--- a/erts/etc/win32/cygwin_tools/erl
+++ b/erts/etc/win32/cygwin_tools/erl
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2009. All Rights Reserved.
+# Copyright Ericsson AB 2002-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.
diff --git a/erts/etc/win32/cygwin_tools/erlc b/erts/etc/win32/cygwin_tools/erlc
index 588b53b1be..eda9fdb7fc 100755
--- a/erts/etc/win32/cygwin_tools/erlc
+++ b/erts/etc/win32/cygwin_tools/erlc
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2009. All Rights Reserved.
+# Copyright Ericsson AB 2002-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.
diff --git a/erts/etc/win32/cygwin_tools/javac.sh b/erts/etc/win32/cygwin_tools/javac.sh
index f2f97ef152..f53e5a3cc6 100755
--- a/erts/etc/win32/cygwin_tools/javac.sh
+++ b/erts/etc/win32/cygwin_tools/javac.sh
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2009. All Rights Reserved.
+# Copyright Ericsson AB 2002-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.
diff --git a/erts/etc/win32/cygwin_tools/make_bootstrap_ini.sh b/erts/etc/win32/cygwin_tools/make_bootstrap_ini.sh
index 0f87f3d077..377c0dda6c 100755
--- a/erts/etc/win32/cygwin_tools/make_bootstrap_ini.sh
+++ b/erts/etc/win32/cygwin_tools/make_bootstrap_ini.sh
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2009. All Rights Reserved.
+# Copyright Ericsson AB 2003-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.
diff --git a/erts/etc/win32/cygwin_tools/make_local_ini.sh b/erts/etc/win32/cygwin_tools/make_local_ini.sh
index 0bcb362ffe..e5db98468b 100755
--- a/erts/etc/win32/cygwin_tools/make_local_ini.sh
+++ b/erts/etc/win32/cygwin_tools/make_local_ini.sh
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2009. All Rights Reserved.
+# Copyright Ericsson AB 2003-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.
diff --git a/erts/etc/win32/cygwin_tools/mingw/ar.sh b/erts/etc/win32/cygwin_tools/mingw/ar.sh
index 2ebfe4e435..de166284d8 100755
--- a/erts/etc/win32/cygwin_tools/mingw/ar.sh
+++ b/erts/etc/win32/cygwin_tools/mingw/ar.sh
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2006-2009. All Rights Reserved.
+# Copyright Ericsson AB 2006-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.
diff --git a/erts/etc/win32/cygwin_tools/mingw/cc.sh b/erts/etc/win32/cygwin_tools/mingw/cc.sh
index 5993f70686..0b321a5099 100755
--- a/erts/etc/win32/cygwin_tools/mingw/cc.sh
+++ b/erts/etc/win32/cygwin_tools/mingw/cc.sh
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2006-2009. All Rights Reserved.
+# Copyright Ericsson AB 2006-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.
diff --git a/erts/etc/win32/cygwin_tools/mingw/coffix.c b/erts/etc/win32/cygwin_tools/mingw/coffix.c
index 383c422008..ff3f3de3d1 100644
--- a/erts/etc/win32/cygwin_tools/mingw/coffix.c
+++ b/erts/etc/win32/cygwin_tools/mingw/coffix.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
diff --git a/erts/etc/win32/cygwin_tools/mingw/emu_cc.sh b/erts/etc/win32/cygwin_tools/mingw/emu_cc.sh
index 8da91dd0ef..5f510467fe 100755
--- a/erts/etc/win32/cygwin_tools/mingw/emu_cc.sh
+++ b/erts/etc/win32/cygwin_tools/mingw/emu_cc.sh
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2006-2009. All Rights Reserved.
+# Copyright Ericsson AB 2006-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.
diff --git a/erts/etc/win32/cygwin_tools/mingw/ld.sh b/erts/etc/win32/cygwin_tools/mingw/ld.sh
index 16caf0b6d2..8b7e1a54c4 100755
--- a/erts/etc/win32/cygwin_tools/mingw/ld.sh
+++ b/erts/etc/win32/cygwin_tools/mingw/ld.sh
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2006-2009. All Rights Reserved.
+# Copyright Ericsson AB 2006-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.
diff --git a/erts/etc/win32/cygwin_tools/mingw/mc.sh b/erts/etc/win32/cygwin_tools/mingw/mc.sh
index 4462bfc5d3..8228f8699e 100755
--- a/erts/etc/win32/cygwin_tools/mingw/mc.sh
+++ b/erts/etc/win32/cygwin_tools/mingw/mc.sh
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2006-2009. All Rights Reserved.
+# Copyright Ericsson AB 2006-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.
diff --git a/erts/etc/win32/cygwin_tools/mingw/rc.sh b/erts/etc/win32/cygwin_tools/mingw/rc.sh
index b8a2d2fbcf..de1b15a432 100755
--- a/erts/etc/win32/cygwin_tools/mingw/rc.sh
+++ b/erts/etc/win32/cygwin_tools/mingw/rc.sh
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2006-2009. All Rights Reserved.
+# Copyright Ericsson AB 2006-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.
diff --git a/erts/etc/win32/cygwin_tools/vc/ar.sh b/erts/etc/win32/cygwin_tools/vc/ar.sh
index e0bd1bd5ca..0989cc878b 100755
--- a/erts/etc/win32/cygwin_tools/vc/ar.sh
+++ b/erts/etc/win32/cygwin_tools/vc/ar.sh
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2009. All Rights Reserved.
+# Copyright Ericsson AB 2002-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.
diff --git a/erts/etc/win32/cygwin_tools/vc/cc.sh b/erts/etc/win32/cygwin_tools/vc/cc.sh
index 651b6e098d..9eeb004f0e 100755
--- a/erts/etc/win32/cygwin_tools/vc/cc.sh
+++ b/erts/etc/win32/cygwin_tools/vc/cc.sh
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2009. All Rights Reserved.
+# Copyright Ericsson AB 2002-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.
diff --git a/erts/etc/win32/cygwin_tools/vc/cc_wrap.c b/erts/etc/win32/cygwin_tools/vc/cc_wrap.c
index b42e0e1037..198f3b5649 100644
--- a/erts/etc/win32/cygwin_tools/vc/cc_wrap.c
+++ b/erts/etc/win32/cygwin_tools/vc/cc_wrap.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/etc/win32/cygwin_tools/vc/coffix.c b/erts/etc/win32/cygwin_tools/vc/coffix.c
index 0633c6ddea..bf1096c425 100644
--- a/erts/etc/win32/cygwin_tools/vc/coffix.c
+++ b/erts/etc/win32/cygwin_tools/vc/coffix.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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.
diff --git a/erts/etc/win32/cygwin_tools/vc/emu_cc.sh b/erts/etc/win32/cygwin_tools/vc/emu_cc.sh
index fb6ee2d7a2..343cd366a6 100755
--- a/erts/etc/win32/cygwin_tools/vc/emu_cc.sh
+++ b/erts/etc/win32/cygwin_tools/vc/emu_cc.sh
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2011. All Rights Reserved.
+# Copyright Ericsson AB 2002-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.
diff --git a/erts/etc/win32/cygwin_tools/vc/ld.sh b/erts/etc/win32/cygwin_tools/vc/ld.sh
index ff538122b2..2b7d7c6694 100755
--- a/erts/etc/win32/cygwin_tools/vc/ld.sh
+++ b/erts/etc/win32/cygwin_tools/vc/ld.sh
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2010. All Rights Reserved.
+# Copyright Ericsson AB 2002-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.
diff --git a/erts/etc/win32/cygwin_tools/vc/ld_wrap.c b/erts/etc/win32/cygwin_tools/vc/ld_wrap.c
index 000c13befd..94b5c38751 100644
--- a/erts/etc/win32/cygwin_tools/vc/ld_wrap.c
+++ b/erts/etc/win32/cygwin_tools/vc/ld_wrap.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/etc/win32/cygwin_tools/vc/mc.sh b/erts/etc/win32/cygwin_tools/vc/mc.sh
index 2de5cbba9b..c88f2ff1a7 100755
--- a/erts/etc/win32/cygwin_tools/vc/mc.sh
+++ b/erts/etc/win32/cygwin_tools/vc/mc.sh
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2009. All Rights Reserved.
+# Copyright Ericsson AB 2002-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.
diff --git a/erts/etc/win32/cygwin_tools/vc/rc.sh b/erts/etc/win32/cygwin_tools/vc/rc.sh
index 414ffa0448..286ebb03f0 100755
--- a/erts/etc/win32/cygwin_tools/vc/rc.sh
+++ b/erts/etc/win32/cygwin_tools/vc/rc.sh
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2010. All Rights Reserved.
+# Copyright Ericsson AB 2002-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.
diff --git a/erts/etc/win32/erl.c b/erts/etc/win32/erl.c
index 59693955a5..b230aa6a40 100644
--- a/erts/etc/win32/erl.c
+++ b/erts/etc/win32/erl.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/etc/win32/erl.rc b/erts/etc/win32/erl.rc
index e8848e7969..772213ac86 100644
--- a/erts/etc/win32/erl.rc
+++ b/erts/etc/win32/erl.rc
@@ -1,7 +1,7 @@
//
// %CopyrightBegin%
//
-// Copyright Ericsson AB 1998-2009. All Rights Reserved.
+// Copyright Ericsson AB 1998-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.
diff --git a/erts/etc/win32/erl_log.c b/erts/etc/win32/erl_log.c
index 2a873dffac..de0d8e39f0 100644
--- a/erts/etc/win32/erl_log.c
+++ b/erts/etc/win32/erl_log.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1996-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.
diff --git a/erts/etc/win32/erlsrv/erlsrv_global.h b/erts/etc/win32/erlsrv/erlsrv_global.h
index f535599cf1..fc6166fc7c 100644
--- a/erts/etc/win32/erlsrv/erlsrv_global.h
+++ b/erts/etc/win32/erlsrv/erlsrv_global.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/etc/win32/erlsrv/erlsrv_interactive.c b/erts/etc/win32/erlsrv/erlsrv_interactive.c
index d2236ac9f7..c616ef86e3 100644
--- a/erts/etc/win32/erlsrv/erlsrv_interactive.c
+++ b/erts/etc/win32/erlsrv/erlsrv_interactive.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/etc/win32/erlsrv/erlsrv_interactive.h b/erts/etc/win32/erlsrv/erlsrv_interactive.h
index a83f5a4b85..03cf4b3339 100644
--- a/erts/etc/win32/erlsrv/erlsrv_interactive.h
+++ b/erts/etc/win32/erlsrv/erlsrv_interactive.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2011. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/etc/win32/erlsrv/erlsrv_main.c b/erts/etc/win32/erlsrv/erlsrv_main.c
index caca18de00..521e7687f4 100644
--- a/erts/etc/win32/erlsrv/erlsrv_main.c
+++ b/erts/etc/win32/erlsrv/erlsrv_main.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/etc/win32/erlsrv/erlsrv_registry.c b/erts/etc/win32/erlsrv/erlsrv_registry.c
index f95f4ef074..eb2a8c567c 100644
--- a/erts/etc/win32/erlsrv/erlsrv_registry.c
+++ b/erts/etc/win32/erlsrv/erlsrv_registry.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/etc/win32/erlsrv/erlsrv_registry.h b/erts/etc/win32/erlsrv/erlsrv_registry.h
index 3aa265686a..885d021497 100644
--- a/erts/etc/win32/erlsrv/erlsrv_registry.h
+++ b/erts/etc/win32/erlsrv/erlsrv_registry.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/etc/win32/erlsrv/erlsrv_service.c b/erts/etc/win32/erlsrv/erlsrv_service.c
index d9fa165355..f5d5c0b174 100644
--- a/erts/etc/win32/erlsrv/erlsrv_service.c
+++ b/erts/etc/win32/erlsrv/erlsrv_service.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/etc/win32/erlsrv/erlsrv_service.h b/erts/etc/win32/erlsrv/erlsrv_service.h
index c87292325c..4e1148cac2 100644
--- a/erts/etc/win32/erlsrv/erlsrv_service.h
+++ b/erts/etc/win32/erlsrv/erlsrv_service.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/etc/win32/erlsrv/erlsrv_util.c b/erts/etc/win32/erlsrv/erlsrv_util.c
index 800395ff12..f719082d37 100644
--- a/erts/etc/win32/erlsrv/erlsrv_util.c
+++ b/erts/etc/win32/erlsrv/erlsrv_util.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/etc/win32/erlsrv/erlsrv_util.h b/erts/etc/win32/erlsrv/erlsrv_util.h
index 1afcd1dd7e..97cc91834f 100644
--- a/erts/etc/win32/erlsrv/erlsrv_util.h
+++ b/erts/etc/win32/erlsrv/erlsrv_util.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/etc/win32/init_file.c b/erts/etc/win32/init_file.c
index 93d82b1823..147e299798 100644
--- a/erts/etc/win32/init_file.c
+++ b/erts/etc/win32/init_file.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/etc/win32/init_file.h b/erts/etc/win32/init_file.h
index 404b5fd03b..df33d23a35 100644
--- a/erts/etc/win32/init_file.h
+++ b/erts/etc/win32/init_file.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2003-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.
diff --git a/erts/etc/win32/msys_tools/erl b/erts/etc/win32/msys_tools/erl
index 110d48c769..a2fe924e78 100644
--- a/erts/etc/win32/msys_tools/erl
+++ b/erts/etc/win32/msys_tools/erl
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2011. All Rights Reserved.
+# Copyright Ericsson AB 2002-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.
diff --git a/erts/etc/win32/msys_tools/erlc b/erts/etc/win32/msys_tools/erlc
index b50090b6de..45d466743e 100644
--- a/erts/etc/win32/msys_tools/erlc
+++ b/erts/etc/win32/msys_tools/erlc
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2011. All Rights Reserved.
+# Copyright Ericsson AB 2002-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.
diff --git a/erts/etc/win32/msys_tools/javac.sh b/erts/etc/win32/msys_tools/javac.sh
index 5b51648a19..6a8b245601 100644
--- a/erts/etc/win32/msys_tools/javac.sh
+++ b/erts/etc/win32/msys_tools/javac.sh
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2011. All Rights Reserved.
+# Copyright Ericsson AB 2002-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.
diff --git a/erts/etc/win32/msys_tools/make_bootstrap_ini.sh b/erts/etc/win32/msys_tools/make_bootstrap_ini.sh
index 1797f67c78..59fc6fc09a 100644
--- a/erts/etc/win32/msys_tools/make_bootstrap_ini.sh
+++ b/erts/etc/win32/msys_tools/make_bootstrap_ini.sh
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2011. All Rights Reserved.
+# Copyright Ericsson AB 2003-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.
diff --git a/erts/etc/win32/msys_tools/make_local_ini.sh b/erts/etc/win32/msys_tools/make_local_ini.sh
index 11f722e7f8..046b3e9d00 100644
--- a/erts/etc/win32/msys_tools/make_local_ini.sh
+++ b/erts/etc/win32/msys_tools/make_local_ini.sh
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2011. All Rights Reserved.
+# Copyright Ericsson AB 2003-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.
diff --git a/erts/etc/win32/msys_tools/vc/ar.sh b/erts/etc/win32/msys_tools/vc/ar.sh
index 4c98e3cc29..a33c954c0f 100644
--- a/erts/etc/win32/msys_tools/vc/ar.sh
+++ b/erts/etc/win32/msys_tools/vc/ar.sh
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2011. All Rights Reserved.
+# Copyright Ericsson AB 2002-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.
diff --git a/erts/etc/win32/msys_tools/vc/cc.sh b/erts/etc/win32/msys_tools/vc/cc.sh
index 72005862ed..2b0482e876 100644
--- a/erts/etc/win32/msys_tools/vc/cc.sh
+++ b/erts/etc/win32/msys_tools/vc/cc.sh
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2011. All Rights Reserved.
+# Copyright Ericsson AB 2002-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.
diff --git a/erts/etc/win32/msys_tools/vc/coffix.c b/erts/etc/win32/msys_tools/vc/coffix.c
index 4f21cfc389..bf1096c425 100644
--- a/erts/etc/win32/msys_tools/vc/coffix.c
+++ b/erts/etc/win32/msys_tools/vc/coffix.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2011. All Rights Reserved.
+ * Copyright Ericsson AB 1999-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.
diff --git a/erts/etc/win32/msys_tools/vc/emu_cc.sh b/erts/etc/win32/msys_tools/vc/emu_cc.sh
index 10d59214ea..2de3a07aca 100644
--- a/erts/etc/win32/msys_tools/vc/emu_cc.sh
+++ b/erts/etc/win32/msys_tools/vc/emu_cc.sh
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2011. All Rights Reserved.
+# Copyright Ericsson AB 2002-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.
diff --git a/erts/etc/win32/msys_tools/vc/ld.sh b/erts/etc/win32/msys_tools/vc/ld.sh
index 11b2fc077b..8917251f51 100644
--- a/erts/etc/win32/msys_tools/vc/ld.sh
+++ b/erts/etc/win32/msys_tools/vc/ld.sh
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2011. All Rights Reserved.
+# Copyright Ericsson AB 2002-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.
diff --git a/erts/etc/win32/msys_tools/vc/mc.sh b/erts/etc/win32/msys_tools/vc/mc.sh
index 14b5ebaa8f..a074a1a89f 100644
--- a/erts/etc/win32/msys_tools/vc/mc.sh
+++ b/erts/etc/win32/msys_tools/vc/mc.sh
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2011. All Rights Reserved.
+# Copyright Ericsson AB 2002-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.
diff --git a/erts/etc/win32/msys_tools/vc/rc.sh b/erts/etc/win32/msys_tools/vc/rc.sh
index 1f8ade17cb..3d1186ca91 100644
--- a/erts/etc/win32/msys_tools/vc/rc.sh
+++ b/erts/etc/win32/msys_tools/vc/rc.sh
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2011. All Rights Reserved.
+# Copyright Ericsson AB 2002-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.
diff --git a/erts/etc/win32/nsis/Makefile b/erts/etc/win32/nsis/Makefile
index 64f44ff86d..0b4e0d0359 100644
--- a/erts/etc/win32/nsis/Makefile
+++ b/erts/etc/win32/nsis/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2012. All Rights Reserved.
+# Copyright Ericsson AB 2003-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.
diff --git a/erts/etc/win32/nsis/dll_version_helper.sh b/erts/etc/win32/nsis/dll_version_helper.sh
index 86e36f62c9..9eafb6ce0e 100755
--- a/erts/etc/win32/nsis/dll_version_helper.sh
+++ b/erts/etc/win32/nsis/dll_version_helper.sh
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2007-2013. All Rights Reserved.
+# Copyright Ericsson AB 2007-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.
diff --git a/erts/etc/win32/nsis/erlang20.nsi b/erts/etc/win32/nsis/erlang20.nsi
index bf6ba0b9a6..66746b684d 100644
--- a/erts/etc/win32/nsis/erlang20.nsi
+++ b/erts/etc/win32/nsis/erlang20.nsi
@@ -7,7 +7,7 @@
;
; %CopyrightBegin%
;
-; Copyright Ericsson AB 2012. All Rights Reserved.
+; Copyright Ericsson AB 2012-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.
diff --git a/erts/etc/win32/nsis/find_redist.sh b/erts/etc/win32/nsis/find_redist.sh
index 03e92b21c7..c070ad469a 100755
--- a/erts/etc/win32/nsis/find_redist.sh
+++ b/erts/etc/win32/nsis/find_redist.sh
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2007-2011. All Rights Reserved.
+# Copyright Ericsson AB 2007-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.
diff --git a/erts/etc/win32/port_entry.c b/erts/etc/win32/port_entry.c
index 5681a2a548..8b1d3a44b8 100644
--- a/erts/etc/win32/port_entry.c
+++ b/erts/etc/win32/port_entry.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2012. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/etc/win32/resource.h b/erts/etc/win32/resource.h
index 32d8b8885d..e59baadb50 100644
--- a/erts/etc/win32/resource.h
+++ b/erts/etc/win32/resource.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
diff --git a/erts/etc/win32/start_erl.c b/erts/etc/win32/start_erl.c
index a4437c2f6b..07bcd19b81 100644
--- a/erts/etc/win32/start_erl.c
+++ b/erts/etc/win32/start_erl.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2012. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/etc/win32/win_erlexec.c b/erts/etc/win32/win_erlexec.c
index f2460197e6..39dac358e9 100644
--- a/erts/etc/win32/win_erlexec.c
+++ b/erts/etc/win32/win_erlexec.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2011. All Rights Reserved.
+ * Copyright Ericsson AB 1997-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.
diff --git a/erts/example/Makefile b/erts/example/Makefile
index cc5bcce191..f00321ac45 100644
--- a/erts/example/Makefile
+++ b/erts/example/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2006-2009. All Rights Reserved.
+# Copyright Ericsson AB 2006-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.
diff --git a/erts/example/matrix_nif.c b/erts/example/matrix_nif.c
index dfe446e879..6452084eb7 100644
--- a/erts/example/matrix_nif.c
+++ b/erts/example/matrix_nif.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2011. All Rights Reserved.
+ * 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.
diff --git a/erts/example/matrix_nif.erl b/erts/example/matrix_nif.erl
index d56b358247..bdc7228ac0 100644
--- a/erts/example/matrix_nif.erl
+++ b/erts/example/matrix_nif.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010. All Rights Reserved.
+%% 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.
diff --git a/erts/example/next_perm.cc b/erts/example/next_perm.cc
index c7b7096e7b..882af4cd1e 100644
--- a/erts/example/next_perm.cc
+++ b/erts/example/next_perm.cc
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
diff --git a/erts/example/next_perm.erl b/erts/example/next_perm.erl
index d414470f3a..b6f47b975c 100644
--- a/erts/example/next_perm.erl
+++ b/erts/example/next_perm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2006-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.
diff --git a/erts/example/pg_async.c b/erts/example/pg_async.c
index cd6bc9e0c2..3167ce5227 100644
--- a/erts/example/pg_async.c
+++ b/erts/example/pg_async.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
diff --git a/erts/example/pg_async.erl b/erts/example/pg_async.erl
index 20ee94f61a..d34d03cf09 100644
--- a/erts/example/pg_async.erl
+++ b/erts/example/pg_async.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2006-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.
diff --git a/erts/example/pg_async2.c b/erts/example/pg_async2.c
index 9eb3ec9d54..ee772f4447 100644
--- a/erts/example/pg_async2.c
+++ b/erts/example/pg_async2.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
diff --git a/erts/example/pg_async2.erl b/erts/example/pg_async2.erl
index 082852f617..9398f4ccbe 100644
--- a/erts/example/pg_async2.erl
+++ b/erts/example/pg_async2.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2006-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.
diff --git a/erts/example/pg_encode.c b/erts/example/pg_encode.c
index e1ec4abb1d..1efc4c1eaf 100644
--- a/erts/example/pg_encode.c
+++ b/erts/example/pg_encode.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
diff --git a/erts/example/pg_encode.h b/erts/example/pg_encode.h
index df3f8fcaaa..213e20198e 100644
--- a/erts/example/pg_encode.h
+++ b/erts/example/pg_encode.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
diff --git a/erts/example/pg_encode2.c b/erts/example/pg_encode2.c
index cdf8e71e44..df5ec9771b 100644
--- a/erts/example/pg_encode2.c
+++ b/erts/example/pg_encode2.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
diff --git a/erts/example/pg_encode2.h b/erts/example/pg_encode2.h
index df3f8fcaaa..213e20198e 100644
--- a/erts/example/pg_encode2.h
+++ b/erts/example/pg_encode2.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
diff --git a/erts/example/pg_sync.c b/erts/example/pg_sync.c
index 88096671a5..81b99f98d3 100644
--- a/erts/example/pg_sync.c
+++ b/erts/example/pg_sync.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
diff --git a/erts/example/pg_sync.erl b/erts/example/pg_sync.erl
index 76fb27332e..29a975727a 100644
--- a/erts/example/pg_sync.erl
+++ b/erts/example/pg_sync.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2006-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.
diff --git a/erts/include/erl_fixed_size_int_types.h b/erts/include/erl_fixed_size_int_types.h
index dfaea5650b..9f47bdd797 100644
--- a/erts/include/erl_fixed_size_int_types.h
+++ b/erts/include/erl_fixed_size_int_types.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/include/erl_int_sizes_config.h.in b/erts/include/erl_int_sizes_config.h.in
index 88c74cdeff..e0e60f0e2f 100644
--- a/erts/include/erl_int_sizes_config.h.in
+++ b/erts/include/erl_int_sizes_config.h.in
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/include/erl_memory_trace_parser.h b/erts/include/erl_memory_trace_parser.h
index 426ff05061..3170ebc0d0 100644
--- a/erts/include/erl_memory_trace_parser.h
+++ b/erts/include/erl_memory_trace_parser.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/include/erl_native_features_config.h.in b/erts/include/erl_native_features_config.h.in
index 2bd1d96229..59a5dde09e 100644
--- a/erts/include/erl_native_features_config.h.in
+++ b/erts/include/erl_native_features_config.h.in
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/include/internal/README b/erts/include/internal/README
index fca0c5e489..a79b241556 100644
--- a/erts/include/internal/README
+++ b/erts/include/internal/README
@@ -1,7 +1,7 @@
%CopyrightBegin%
- Copyright Ericsson AB 2004-2009. All Rights Reserved.
+ Copyright Ericsson AB 2004-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.
diff --git a/erts/include/internal/erl_errno.h b/erts/include/internal/erl_errno.h
index 33bfbe3d51..1ae045805e 100644
--- a/erts/include/internal/erl_errno.h
+++ b/erts/include/internal/erl_errno.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009. All Rights Reserved.
+ * Copyright Ericsson AB 2009-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.
diff --git a/erts/include/internal/erl_memory_trace_protocol.h b/erts/include/internal/erl_memory_trace_protocol.h
index b86e2de278..d3e0bcc1f4 100644
--- a/erts/include/internal/erl_memory_trace_protocol.h
+++ b/erts/include/internal/erl_memory_trace_protocol.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/include/internal/erl_misc_utils.h b/erts/include/internal/erl_misc_utils.h
index 7ab7a26838..a4a5d1d510 100644
--- a/erts/include/internal/erl_misc_utils.h
+++ b/erts/include/internal/erl_misc_utils.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2010. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
diff --git a/erts/include/internal/erl_printf.h b/erts/include/internal/erl_printf.h
index 3846828fb9..c4565dfafc 100644
--- a/erts/include/internal/erl_printf.h
+++ b/erts/include/internal/erl_printf.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/include/internal/erl_printf_format.h b/erts/include/internal/erl_printf_format.h
index 953022017a..4f969bdbcb 100644
--- a/erts/include/internal/erl_printf_format.h
+++ b/erts/include/internal/erl_printf_format.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/include/internal/erts_internal.mk.in b/erts/include/internal/erts_internal.mk.in
index 76aab59c38..8faa33135e 100644
--- a/erts/include/internal/erts_internal.mk.in
+++ b/erts/include/internal/erts_internal.mk.in
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009. All Rights Reserved.
+# Copyright Ericsson AB 2009-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.
diff --git a/erts/include/internal/ethr_atomics.h b/erts/include/internal/ethr_atomics.h
index f366c2d0ad..06568201ad 100644
--- a/erts/include/internal/ethr_atomics.h
+++ b/erts/include/internal/ethr_atomics.h
@@ -10,7 +10,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
diff --git a/erts/include/internal/ethr_internal.h b/erts/include/internal/ethr_internal.h
index 693b34df61..6657c8affc 100644
--- a/erts/include/internal/ethr_internal.h
+++ b/erts/include/internal/ethr_internal.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2011. All Rights Reserved.
+ * 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.
diff --git a/erts/include/internal/ethr_mutex.h b/erts/include/internal/ethr_mutex.h
index b402a139f5..a510a2c97f 100644
--- a/erts/include/internal/ethr_mutex.h
+++ b/erts/include/internal/ethr_mutex.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2011. All Rights Reserved.
+ * 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.
diff --git a/erts/include/internal/ethr_optimized_fallbacks.h b/erts/include/internal/ethr_optimized_fallbacks.h
index 6ef4e2bace..8c27a9ba5b 100644
--- a/erts/include/internal/ethr_optimized_fallbacks.h
+++ b/erts/include/internal/ethr_optimized_fallbacks.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2011. All Rights Reserved.
+ * 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.
diff --git a/erts/include/internal/ethread.h b/erts/include/internal/ethread.h
index e5c5cdfa33..b23644d361 100644
--- a/erts/include/internal/ethread.h
+++ b/erts/include/internal/ethread.h
@@ -112,6 +112,10 @@ int ethr_assert_failed(const char *file, int line, const char *func, char *a);
#error "_GNU_SOURCE not defined. Please, compile all files with -D_GNU_SOURCE."
#endif
+#ifdef ETHR_HAVE_PTHREAD_SETNAME_NP_1
+#define _DARWIN_C_SOURCE
+#endif
+
#if defined(ETHR_NEED_NPTL_PTHREAD_H)
#include <nptl/pthread.h>
#elif defined(ETHR_HAVE_MIT_PTHREAD_H)
diff --git a/erts/include/internal/ethread.mk.in b/erts/include/internal/ethread.mk.in
index 89924a3215..486a7a9401 100644
--- a/erts/include/internal/ethread.mk.in
+++ b/erts/include/internal/ethread.mk.in
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2009. All Rights Reserved.
+# Copyright Ericsson AB 2004-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.
diff --git a/erts/include/internal/ethread_header_config.h.in b/erts/include/internal/ethread_header_config.h.in
index f4b08cfced..6309f10439 100644
--- a/erts/include/internal/ethread_header_config.h.in
+++ b/erts/include/internal/ethread_header_config.h.in
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2015. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/include/internal/ethread_inline.h b/erts/include/internal/ethread_inline.h
index 3ba910d993..8e6bcfc4a8 100644
--- a/erts/include/internal/ethread_inline.h
+++ b/erts/include/internal/ethread_inline.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2014. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/include/internal/i386/atomic.h b/erts/include/internal/i386/atomic.h
index 6a6435e58d..52ef1762d5 100644
--- a/erts/include/internal/i386/atomic.h
+++ b/erts/include/internal/i386/atomic.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/include/internal/i386/ethr_dw_atomic.h b/erts/include/internal/i386/ethr_dw_atomic.h
index 5444a6345c..91acdb0483 100644
--- a/erts/include/internal/i386/ethr_dw_atomic.h
+++ b/erts/include/internal/i386/ethr_dw_atomic.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
diff --git a/erts/include/internal/i386/ethr_membar.h b/erts/include/internal/i386/ethr_membar.h
index 97ae5eda2c..d1b72cd538 100644
--- a/erts/include/internal/i386/ethr_membar.h
+++ b/erts/include/internal/i386/ethr_membar.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
diff --git a/erts/include/internal/i386/ethread.h b/erts/include/internal/i386/ethread.h
index 23dcd1dc19..fef1674c7e 100644
--- a/erts/include/internal/i386/ethread.h
+++ b/erts/include/internal/i386/ethread.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/include/internal/i386/rwlock.h b/erts/include/internal/i386/rwlock.h
index 9859338eab..8d22bac7e9 100644
--- a/erts/include/internal/i386/rwlock.h
+++ b/erts/include/internal/i386/rwlock.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/include/internal/i386/spinlock.h b/erts/include/internal/i386/spinlock.h
index e010684d14..1a8e359981 100644
--- a/erts/include/internal/i386/spinlock.h
+++ b/erts/include/internal/i386/spinlock.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/include/internal/libatomic_ops/ethr_atomic.h b/erts/include/internal/libatomic_ops/ethr_atomic.h
index 828210036c..da3b15a878 100644
--- a/erts/include/internal/libatomic_ops/ethr_atomic.h
+++ b/erts/include/internal/libatomic_ops/ethr_atomic.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2014. All Rights Reserved.
+ * 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.
diff --git a/erts/include/internal/libatomic_ops/ethr_dw_atomic.h b/erts/include/internal/libatomic_ops/ethr_dw_atomic.h
index ce9b251cbe..8643600fa5 100644
--- a/erts/include/internal/libatomic_ops/ethr_dw_atomic.h
+++ b/erts/include/internal/libatomic_ops/ethr_dw_atomic.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2014. All Rights Reserved.
+ * Copyright Ericsson AB 2014-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.
diff --git a/erts/include/internal/libatomic_ops/ethr_membar.h b/erts/include/internal/libatomic_ops/ethr_membar.h
index 7d2b807586..1d3d332c90 100644
--- a/erts/include/internal/libatomic_ops/ethr_membar.h
+++ b/erts/include/internal/libatomic_ops/ethr_membar.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
diff --git a/erts/include/internal/libatomic_ops/ethread.h b/erts/include/internal/libatomic_ops/ethread.h
index e34f43bb46..4adc31ed2a 100644
--- a/erts/include/internal/libatomic_ops/ethread.h
+++ b/erts/include/internal/libatomic_ops/ethread.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2011. All Rights Reserved.
+ * 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.
diff --git a/erts/include/internal/ppc32/atomic.h b/erts/include/internal/ppc32/atomic.h
index 572b0e5191..198f057b3f 100644
--- a/erts/include/internal/ppc32/atomic.h
+++ b/erts/include/internal/ppc32/atomic.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/include/internal/ppc32/ethr_membar.h b/erts/include/internal/ppc32/ethr_membar.h
index fe77721cd9..88ba4a2ea5 100644
--- a/erts/include/internal/ppc32/ethr_membar.h
+++ b/erts/include/internal/ppc32/ethr_membar.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
diff --git a/erts/include/internal/ppc32/ethread.h b/erts/include/internal/ppc32/ethread.h
index 25e85c58bd..bead019f41 100644
--- a/erts/include/internal/ppc32/ethread.h
+++ b/erts/include/internal/ppc32/ethread.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/include/internal/ppc32/rwlock.h b/erts/include/internal/ppc32/rwlock.h
index aee232f79d..6493629e49 100644
--- a/erts/include/internal/ppc32/rwlock.h
+++ b/erts/include/internal/ppc32/rwlock.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/include/internal/ppc32/spinlock.h b/erts/include/internal/ppc32/spinlock.h
index 829db6a135..3b35cafcb2 100644
--- a/erts/include/internal/ppc32/spinlock.h
+++ b/erts/include/internal/ppc32/spinlock.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/include/internal/pthread/ethr_event.h b/erts/include/internal/pthread/ethr_event.h
index deb4b29686..6e470bf6cf 100644
--- a/erts/include/internal/pthread/ethr_event.h
+++ b/erts/include/internal/pthread/ethr_event.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2009-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.
diff --git a/erts/include/internal/sparc32/atomic.h b/erts/include/internal/sparc32/atomic.h
index 0b535242ad..032943817d 100644
--- a/erts/include/internal/sparc32/atomic.h
+++ b/erts/include/internal/sparc32/atomic.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/include/internal/sparc32/ethr_membar.h b/erts/include/internal/sparc32/ethr_membar.h
index 6133de5eb7..fb8ceef12b 100644
--- a/erts/include/internal/sparc32/ethr_membar.h
+++ b/erts/include/internal/sparc32/ethr_membar.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
diff --git a/erts/include/internal/sparc32/ethread.h b/erts/include/internal/sparc32/ethread.h
index 513d9f8773..8d49465008 100644
--- a/erts/include/internal/sparc32/ethread.h
+++ b/erts/include/internal/sparc32/ethread.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/include/internal/sparc32/rwlock.h b/erts/include/internal/sparc32/rwlock.h
index 44de6113b7..1cc516cdad 100644
--- a/erts/include/internal/sparc32/rwlock.h
+++ b/erts/include/internal/sparc32/rwlock.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/include/internal/sparc32/spinlock.h b/erts/include/internal/sparc32/spinlock.h
index 695fa112b6..ae3b1c9dee 100644
--- a/erts/include/internal/sparc32/spinlock.h
+++ b/erts/include/internal/sparc32/spinlock.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/include/internal/sparc64/ethread.h b/erts/include/internal/sparc64/ethread.h
index 5f518e5596..6018e738b5 100644
--- a/erts/include/internal/sparc64/ethread.h
+++ b/erts/include/internal/sparc64/ethread.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2007-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2007-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.
diff --git a/erts/include/internal/tile/atomic.h b/erts/include/internal/tile/atomic.h
index 1a2881442e..7f5f83bcc7 100644
--- a/erts/include/internal/tile/atomic.h
+++ b/erts/include/internal/tile/atomic.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/include/internal/tile/ethr_membar.h b/erts/include/internal/tile/ethr_membar.h
index ccb420d558..50ea2c0265 100644
--- a/erts/include/internal/tile/ethr_membar.h
+++ b/erts/include/internal/tile/ethr_membar.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
diff --git a/erts/include/internal/tile/ethread.h b/erts/include/internal/tile/ethread.h
index 577d275965..0d69673a1c 100644
--- a/erts/include/internal/tile/ethread.h
+++ b/erts/include/internal/tile/ethread.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/include/internal/win/ethr_atomic.h b/erts/include/internal/win/ethr_atomic.h
index f17526a94d..32c28f692d 100644
--- a/erts/include/internal/win/ethr_atomic.h
+++ b/erts/include/internal/win/ethr_atomic.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2011. All Rights Reserved.
+ * 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.
diff --git a/erts/include/internal/win/ethr_dw_atomic.h b/erts/include/internal/win/ethr_dw_atomic.h
index 8bed4fb26e..a6b26ab7bb 100644
--- a/erts/include/internal/win/ethr_dw_atomic.h
+++ b/erts/include/internal/win/ethr_dw_atomic.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
diff --git a/erts/include/internal/win/ethr_event.h b/erts/include/internal/win/ethr_event.h
index 458565b9ea..9ee78183ab 100644
--- a/erts/include/internal/win/ethr_event.h
+++ b/erts/include/internal/win/ethr_event.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2009-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.
diff --git a/erts/include/internal/win/ethr_membar.h b/erts/include/internal/win/ethr_membar.h
index 9cba6b605d..c018f6d869 100644
--- a/erts/include/internal/win/ethr_membar.h
+++ b/erts/include/internal/win/ethr_membar.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
diff --git a/erts/include/internal/win/ethread.h b/erts/include/internal/win/ethread.h
index 2fda028825..773be08a9b 100644
--- a/erts/include/internal/win/ethread.h
+++ b/erts/include/internal/win/ethread.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2011. All Rights Reserved.
+ * 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.
diff --git a/erts/include/internal/x86_64/ethread.h b/erts/include/internal/x86_64/ethread.h
index 8887b8d77f..7fc5481629 100644
--- a/erts/include/internal/x86_64/ethread.h
+++ b/erts/include/internal/x86_64/ethread.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/lib/internal/README b/erts/lib/internal/README
index 9beba10bc2..9e5cab26d3 100644
--- a/erts/lib/internal/README
+++ b/erts/lib/internal/README
@@ -1,7 +1,7 @@
%CopyrightBegin%
- Copyright Ericsson AB 2004-2009. All Rights Reserved.
+ Copyright Ericsson AB 2004-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.
diff --git a/erts/lib_src/Makefile b/erts/lib_src/Makefile
index 632b8a0b09..882a050ffd 100644
--- a/erts/lib_src/Makefile
+++ b/erts/lib_src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2009. All Rights Reserved.
+# Copyright Ericsson AB 2004-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.
diff --git a/erts/lib_src/Makefile.in b/erts/lib_src/Makefile.in
index 74e32ccdce..6e2f236bdf 100644
--- a/erts/lib_src/Makefile.in
+++ b/erts/lib_src/Makefile.in
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2013. All Rights Reserved.
+# Copyright Ericsson AB 2004-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.
diff --git a/erts/lib_src/common/erl_memory_trace_parser.c b/erts/lib_src/common/erl_memory_trace_parser.c
index a81068089e..0232708ad1 100644
--- a/erts/lib_src/common/erl_memory_trace_parser.c
+++ b/erts/lib_src/common/erl_memory_trace_parser.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/lib_src/common/erl_misc_utils.c b/erts/lib_src/common/erl_misc_utils.c
index 053217304b..8186463b9c 100644
--- a/erts/lib_src/common/erl_misc_utils.c
+++ b/erts/lib_src/common/erl_misc_utils.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2006-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.
diff --git a/erts/lib_src/common/erl_printf.c b/erts/lib_src/common/erl_printf.c
index 387a104a7a..b5e90dfeef 100644
--- a/erts/lib_src/common/erl_printf.c
+++ b/erts/lib_src/common/erl_printf.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/lib_src/common/erl_printf_format.c b/erts/lib_src/common/erl_printf_format.c
index e7d5d4413e..3daa066fd3 100644
--- a/erts/lib_src/common/erl_printf_format.c
+++ b/erts/lib_src/common/erl_printf_format.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/lib_src/common/ethr_atomics.c b/erts/lib_src/common/ethr_atomics.c
index 42c078377d..1594d78f5e 100644
--- a/erts/lib_src/common/ethr_atomics.c
+++ b/erts/lib_src/common/ethr_atomics.c
@@ -10,7 +10,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
diff --git a/erts/lib_src/common/ethr_aux.c b/erts/lib_src/common/ethr_aux.c
index 3e7aad16c7..420efd725f 100644
--- a/erts/lib_src/common/ethr_aux.c
+++ b/erts/lib_src/common/ethr_aux.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2014. All Rights Reserved.
+ * 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.
diff --git a/erts/lib_src/common/ethr_cbf.c b/erts/lib_src/common/ethr_cbf.c
index e79ec2b40c..037559be22 100644
--- a/erts/lib_src/common/ethr_cbf.c
+++ b/erts/lib_src/common/ethr_cbf.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010. All Rights Reserved.
+ * 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.
diff --git a/erts/lib_src/common/ethr_mutex.c b/erts/lib_src/common/ethr_mutex.c
index a596e6c31c..5e7e7b2f32 100644
--- a/erts/lib_src/common/ethr_mutex.c
+++ b/erts/lib_src/common/ethr_mutex.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2013. All Rights Reserved.
+ * 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.
diff --git a/erts/lib_src/pthread/ethr_event.c b/erts/lib_src/pthread/ethr_event.c
index 0629b4dfcd..eef88d5002 100644
--- a/erts/lib_src/pthread/ethr_event.c
+++ b/erts/lib_src/pthread/ethr_event.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009-2010. All Rights Reserved.
+ * Copyright Ericsson AB 2009-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.
@@ -94,6 +94,9 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout)
tsp = NULL;
}
else {
+#ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME
+ start = ethr_get_monotonic_time();
+#endif
tsp = &ts;
time = timeout;
if (spincount == 0) {
@@ -102,9 +105,6 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout)
goto return_event_on;
goto set_timeout;
}
-#ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME
- start = ethr_get_monotonic_time();
-#endif
}
while (1) {
diff --git a/erts/lib_src/pthread/ethr_x86_sse2_asm.c b/erts/lib_src/pthread/ethr_x86_sse2_asm.c
index 7ce5a6d98a..bdcf3ac1c3 100644
--- a/erts/lib_src/pthread/ethr_x86_sse2_asm.c
+++ b/erts/lib_src/pthread/ethr_x86_sse2_asm.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2011. All Rights Reserved.
+ * Copyright Ericsson AB 2011-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.
diff --git a/erts/lib_src/pthread/ethread.c b/erts/lib_src/pthread/ethread.c
index ef11559654..29bffa7e12 100644
--- a/erts/lib_src/pthread/ethread.c
+++ b/erts/lib_src/pthread/ethread.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2011. All Rights Reserved.
+ * 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.
diff --git a/erts/lib_src/utils/make_atomics_api b/erts/lib_src/utils/make_atomics_api
index 4b37e3fa74..f960b97c87 100755
--- a/erts/lib_src/utils/make_atomics_api
+++ b/erts/lib_src/utils/make_atomics_api
@@ -4,7 +4,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2011-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.
diff --git a/erts/lib_src/win/ethr_event.c b/erts/lib_src/win/ethr_event.c
index 6951a216c5..383f7c876e 100644
--- a/erts/lib_src/win/ethr_event.c
+++ b/erts/lib_src/win/ethr_event.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2009-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.
diff --git a/erts/lib_src/win/ethread.c b/erts/lib_src/win/ethread.c
index 22b0b4040c..e0f19f7ba1 100644
--- a/erts/lib_src/win/ethread.c
+++ b/erts/lib_src/win/ethread.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2011. All Rights Reserved.
+ * 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.
diff --git a/erts/preloaded/Makefile b/erts/preloaded/Makefile
index fbe62d57bb..e8935d4410 100644
--- a/erts/preloaded/Makefile
+++ b/erts/preloaded/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2008-2009. All Rights Reserved.
+# Copyright Ericsson AB 2008-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.
diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam
index 6d777fa811..3e82b8e20e 100644
--- a/erts/preloaded/ebin/erl_prim_loader.beam
+++ b/erts/preloaded/ebin/erl_prim_loader.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erl_tracer.beam b/erts/preloaded/ebin/erl_tracer.beam
new file mode 100644
index 0000000000..67d96d0f0d
--- /dev/null
+++ b/erts/preloaded/ebin/erl_tracer.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index 2ea2de4c70..321e4e7e1b 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_code_purger.beam b/erts/preloaded/ebin/erts_code_purger.beam
index 4188e5fd9b..0c667663fd 100644
--- a/erts/preloaded/ebin/erts_code_purger.beam
+++ b/erts/preloaded/ebin/erts_code_purger.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam
index 88da34b192..ed2e328f5b 100644
--- a/erts/preloaded/ebin/erts_internal.beam
+++ b/erts/preloaded/ebin/erts_internal.beam
Binary files differ
diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam
index 8ac7f5b471..23ebd2cad9 100644
--- a/erts/preloaded/ebin/init.beam
+++ b/erts/preloaded/ebin/init.beam
Binary files differ
diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam
index 3cd2515ba8..b63fa24848 100644
--- a/erts/preloaded/ebin/otp_ring0.beam
+++ b/erts/preloaded/ebin/otp_ring0.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam
index 9a208d1545..7c8fdc82c0 100644
--- a/erts/preloaded/ebin/prim_eval.beam
+++ b/erts/preloaded/ebin/prim_eval.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam
index 426e764127..d4559bc9ed 100644
--- a/erts/preloaded/ebin/prim_file.beam
+++ b/erts/preloaded/ebin/prim_file.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index d68d18ecba..5a0678632e 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam
index 01b3b1feb8..3d32dd8449 100644
--- a/erts/preloaded/ebin/prim_zip.beam
+++ b/erts/preloaded/ebin/prim_zip.beam
Binary files differ
diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam
index 7252d866bb..ced9f9c952 100644
--- a/erts/preloaded/ebin/zlib.beam
+++ b/erts/preloaded/ebin/zlib.beam
Binary files differ
diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile
index 31383dda83..4a447d3a09 100644
--- a/erts/preloaded/src/Makefile
+++ b/erts/preloaded/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2008-2013. All Rights Reserved.
+# Copyright Ericsson AB 2008-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.
@@ -43,7 +43,8 @@ PRE_LOADED_ERL_MODULES = \
otp_ring0 \
erts_code_purger \
erlang \
- erts_internal
+ erts_internal \
+ erl_tracer
PRE_LOADED_BEAM_MODULES = \
prim_eval
diff --git a/erts/preloaded/src/add_abstract_code b/erts/preloaded/src/add_abstract_code
index 4f479db2e8..943987872e 100644
--- a/erts/preloaded/src/add_abstract_code
+++ b/erts/preloaded/src/add_abstract_code
@@ -4,7 +4,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-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.
diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl
index cbcced5512..e18e187cb7 100644
--- a/erts/preloaded/src/erl_prim_loader.erl
+++ b/erts/preloaded/src/erl_prim_loader.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-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.
@@ -56,7 +56,7 @@
-export([purge_archive_cache/0]).
%% Used by init and the code server.
--export([get_modules/3]).
+-export([get_modules/2,get_modules/3]).
-include_lib("kernel/include/file.hrl").
@@ -239,6 +239,13 @@ set_primary_archive(File, ArchiveBin, FileInfo, ParserFun)
purge_archive_cache() ->
request(purge_archive_cache).
+-spec get_modules([module()],
+ fun((atom(), string(), binary()) ->
+ {'ok',any()} | {'error',any()})) ->
+ {'ok',{[any()],[any()]}}.
+
+get_modules(Modules, Fun) ->
+ request({get_modules,{Modules,Fun}}).
-spec get_modules([module()],
fun((atom(), string(), binary()) ->
@@ -338,6 +345,8 @@ handle_request(Req, Paths, St0) ->
{{ok,Paths},St0};
{get_file,File} ->
handle_get_file(St0, Paths, File);
+ {get_modules,{Modules,Fun}} ->
+ handle_get_modules(St0, Modules, Fun, Paths);
{get_modules,{Modules,Fun,ModPaths}} ->
handle_get_modules(St0, Modules, Fun, ModPaths);
{list_dir,Dir} ->
diff --git a/erts/preloaded/src/erl_tracer.erl b/erts/preloaded/src/erl_tracer.erl
new file mode 100644
index 0000000000..de1e9ca01e
--- /dev/null
+++ b/erts/preloaded/src/erl_tracer.erl
@@ -0,0 +1,59 @@
+-module(erl_tracer).
+
+-export([enabled/3, trace/6, on_load/0]).
+
+-type tracee() :: port() | pid() | undefined.
+
+-type trace_tag_running_ports() :: in | out | in_exiting | out_exiting | out_exited.
+-type trace_tag_running_procs() :: in | out | in_exiting | out_exiting | out_exited.
+-type trace_tag_send() :: send | send_to_non_existing_process.
+-type trace_tag_receive() :: 'receive'.
+-type trace_tag_call() :: call | return_to | return_from | exception_from.
+-type trace_tag_procs() :: spawn | spawned | exit | link | unlink
+ | getting_linked | getting_unlinked
+ | register | unregister.
+-type trace_tag_ports() :: open | closed | link | unlink
+ | getting_linked | getting_unlinked.
+-type trace_tag_gc() :: gc_minor_start | gc_minor_end
+ | gc_major_start | gc_major_end.
+
+-type trace_tag() :: trace_tag_send()
+ | trace_tag_receive()
+ | trace_tag_call()
+ | trace_tag_procs()
+ | trace_tag_ports()
+ | trace_tag_running_procs()
+ | trace_tag_running_ports()
+ | trace_tag_gc().
+
+-type trace_opts() :: #{ match_spec_result => true | term(),
+ scheduler_id => undefined | non_neg_integer(),
+ timestamp => undefined | timestamp | cpu_timestamp |
+ monotonic | strict_monotonic }.
+-type tracer_state() :: term().
+
+on_load() ->
+ case erlang:load_nif(atom_to_list(?MODULE), 0) of
+ ok -> ok
+ end.
+
+%%%
+%%% NIF placeholders
+%%%
+
+-spec enabled(Tag :: trace_tag() | seq_trace | trace_status,
+ TracerState :: tracer_state(),
+ Tracee :: tracee()) ->
+ trace | discard | remove.
+enabled(_, _, _) ->
+ erlang:nif_error(nif_not_loaded).
+
+-spec trace(Tag :: trace_tag() | seq_trace,
+ TracerState :: tracer_state(),
+ Tracee :: tracee(),
+ Msg :: term(),
+ Extra :: term(),
+ Opts :: trace_opts()) -> any().
+
+trace(_, _, _, _, _, _) ->
+ erlang:nif_error(nif_not_loaded).
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index dfbd116d6e..90fd536b15 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-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.
@@ -230,27 +230,32 @@
send |
'receive' |
procs |
+ ports |
call |
- silent |
+ arity |
return_to |
+ silent |
running |
exiting |
+ running_procs |
+ running_ports |
garbage_collection |
timestamp |
cpu_timestamp |
monotonic_timestamp |
strict_monotonic_timestamp |
- arity |
set_on_spawn |
set_on_first_spawn |
set_on_link |
set_on_first_link |
- {tracer, pid() | port()}.
+ {tracer, pid() | port()} |
+ {tracer, module(), term()}.
-type trace_info_item_result() ::
{traced, global | local | false | undefined} |
{match_spec, trace_match_spec() | false | undefined} |
{meta, pid() | port() | false | undefined | []} |
+ {meta, module(), term() } |
{meta_match_spec, trace_match_spec() | false | undefined} |
{call_count, non_neg_integer() | boolean() | undefined} |
{call_time, [{pid(), non_neg_integer(),
@@ -276,6 +281,7 @@
undefined |
{flags, [trace_info_flag()]} |
{tracer, pid() | port() | []} |
+ {tracer, module(), term()} |
trace_info_item_result() |
{all, [ trace_info_item_result() ] | false | undefined}.
@@ -1157,10 +1163,10 @@ map_size(_Map) ->
erlang:nif_error(undefined).
%% match_spec_test/3
--spec erlang:match_spec_test(P1, P2, P3) -> TestResult when
- P1 :: [term()] | tuple(),
- P2 :: term(),
- P3 :: table | trace,
+-spec erlang:match_spec_test(MatchAgainst, MatchSpec, Type) -> TestResult when
+ MatchAgainst :: [term()] | tuple(),
+ MatchSpec :: term(),
+ Type :: table | trace,
TestResult :: {ok, term(), [return_trace], [ {error | warning, string()} ]} | {error, [ {error | warning, string()} ]}.
match_spec_test(_P1, _P2, _P3) ->
erlang:nif_error(undefined).
@@ -1705,12 +1711,35 @@ time() ->
erlang:nif_error(undefined).
%% trace/3
--spec erlang:trace(PidSpec, How, FlagList) -> integer() when
- PidSpec :: pid() | existing | new | all,
+-spec erlang:trace(PidPortSpec, How, FlagList) -> integer() when
+ PidPortSpec :: pid() | port()
+ | all | processes | ports
+ | existing | existing_processes | existing_ports
+ | new | new_processes | new_ports,
How :: boolean(),
FlagList :: [trace_flag()].
-trace(_PidSpec, _How, _FlagList) ->
- erlang:nif_error(undefined).
+trace(PidPortSpec, How, FlagList) ->
+ %% Make sure that we have loaded the tracer module
+ case lists:keyfind(tracer, 1, FlagList) of
+ {tracer, Module, State} when erlang:is_atom(Module) ->
+ case erlang:module_loaded(Module) of
+ false ->
+ Module:enabled(trace_status, erlang:self(), State);
+ true ->
+ ok
+ end;
+ _ ->
+ ignore
+ end,
+
+ try erts_internal:trace(PidPortSpec, How, FlagList) of
+ Res -> Res
+ catch E:R ->
+ {_, [_ | CST]} = erlang:process_info(
+ erlang:self(), current_stacktrace),
+ erlang:raise(
+ E, R, [{?MODULE, trace, [PidPortSpec, How, FlagList], []} | CST])
+ end.
%% trace_delivered/1
-spec erlang:trace_delivered(Tracee) -> Ref when
@@ -1720,14 +1749,16 @@ trace_delivered(_Tracee) ->
erlang:nif_error(undefined).
%% trace_info/2
--spec erlang:trace_info(PidOrFunc, Item) -> Res when
- PidOrFunc :: pid() | new | {Module, Function, Arity} | on_load,
+-spec erlang:trace_info(PidPortFuncEvent, Item) -> Res when
+ PidPortFuncEvent :: pid() | port() | new | new_processes | new_ports
+ | {Module, Function, Arity} | on_load | send | 'receive',
Module :: module(),
Function :: atom(),
Arity :: arity(),
- Item :: flags | tracer | traced | match_spec | meta | meta_match_spec | call_count | call_time | all,
+ Item :: flags | tracer | traced | match_spec
+ | meta | meta_match_spec | call_count | call_time | all,
Res :: trace_info_return().
-trace_info(_PidOrFunc, _Item) ->
+trace_info(_PidPortFuncEvent, _Item) ->
erlang:nif_error(undefined).
%% trunc/1
@@ -2130,7 +2161,7 @@ process_flag(_Flag, _Value) ->
{message_queue_data, MQD :: message_queue_data()} |
{priority, Level :: priority_level()} |
{reductions, Number :: non_neg_integer()} |
- {registered_name, Atom :: atom()} |
+ {registered_name, [] | (Atom :: atom())} |
{sequential_trace_token, [] | (SequentialTraceToken :: term())} |
{stack_size, Size :: non_neg_integer()} |
{status, Status :: exiting | garbage_collecting | waiting | running | runnable | suspended} |
@@ -2226,9 +2257,9 @@ spawn_opt(_Tuple) ->
Input :: non_neg_integer(),
Output :: non_neg_integer();
(microstate_accounting) -> [MSAcc_Thread] | undefined when
- MSAcc_Thread :: #{ type => MSAcc_Thread_Type,
- id => MSAcc_Thread_Id,
- counters => MSAcc_Counters},
+ MSAcc_Thread :: #{ type := MSAcc_Thread_Type,
+ id := MSAcc_Thread_Id,
+ counters := MSAcc_Counters},
MSAcc_Thread_Type :: scheduler | async | aux,
MSAcc_Thread_Id :: non_neg_integer(),
MSAcc_Counters :: #{ MSAcc_Thread_State => non_neg_integer() },
@@ -2319,7 +2350,7 @@ subtract(_,_) ->
OldState :: preliminary | final | volatile;
%% These are deliberately not documented
(internal_cpu_topology, term()) -> term();
- (sequential_tracer, pid() | port() | false) -> pid() | port() | false;
+ (sequential_tracer, pid() | port() | {module(), term()} | false) -> pid() | port() | false;
(1,0) -> true.
system_flag(_Flag, _Value) ->
@@ -2350,29 +2381,63 @@ tl(_List) ->
[{[term()] | '_' ,[term()],[term()]}].
-spec erlang:trace_pattern(MFA, MatchSpec) -> non_neg_integer() when
- MFA :: trace_pattern_mfa(),
+ MFA :: trace_pattern_mfa() | send | 'receive',
MatchSpec :: (MatchSpecList :: trace_match_spec())
| boolean()
| restart
| pause.
-trace_pattern(_MFA, _MatchSpec) ->
- erlang:nif_error(undefined).
+trace_pattern(MFA, MatchSpec) ->
+ try erts_internal:trace_pattern(MFA, MatchSpec, []) of
+ Res -> Res
+ catch E:R ->
+ {_, [_ | CST]} = erlang:process_info(
+ erlang:self(), current_stacktrace),
+ erlang:raise(
+ E, R, [{?MODULE, trace_pattern, [MFA, MatchSpec], []} | CST])
+ end.
-type trace_pattern_flag() ::
global | local |
meta | {meta, Pid :: pid()} |
+ {meta, TracerModule :: module(), TracerState :: term()} |
call_count |
call_time.
--spec erlang:trace_pattern(MFA, MatchSpec, FlagList) -> non_neg_integer() when
+-spec erlang:trace_pattern(send, MatchSpec, []) -> non_neg_integer() when
+ MatchSpec :: (MatchSpecList :: trace_match_spec())
+ | boolean();
+ ('receive', MatchSpec, []) -> non_neg_integer() when
+ MatchSpec :: (MatchSpecList :: trace_match_spec())
+ | boolean();
+ (MFA, MatchSpec, FlagList) -> non_neg_integer() when
MFA :: trace_pattern_mfa(),
MatchSpec :: (MatchSpecList :: trace_match_spec())
| boolean()
| restart
| pause,
FlagList :: [ trace_pattern_flag() ].
-trace_pattern(_MFA, _MatchSpec, _FlagList) ->
- erlang:nif_error(undefined).
+trace_pattern(MFA, MatchSpec, FlagList) ->
+ %% Make sure that we have loaded the tracer module
+ case lists:keyfind(meta, 1, FlagList) of
+ {meta, Module, State} when erlang:is_atom(Module) ->
+ case erlang:module_loaded(Module) of
+ false ->
+ Module:enabled(trace_status, erlang:self(), State);
+ true ->
+ ok
+ end;
+ _ ->
+ ignore
+ end,
+
+ try erts_internal:trace_pattern(MFA, MatchSpec, FlagList) of
+ Res -> Res
+ catch E:R ->
+ {_, [_ | CST]} = erlang:process_info(
+ erlang:self(), current_stacktrace),
+ erlang:raise(
+ E, R, [{?MODULE, trace_pattern, [MFA, MatchSpec, FlagList], []} | CST])
+ end.
%% Shadowed by erl_bif_types: erlang:tuple_to_list/1
-spec tuple_to_list(Tuple) -> [term()] when
diff --git a/erts/preloaded/src/erts.app.src b/erts/preloaded/src/erts.app.src
index e53b6e5bab..98e0224a5f 100644
--- a/erts/preloaded/src/erts.app.src
+++ b/erts/preloaded/src/erts.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-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.
diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl
index 330fcc4a9c..2459ea2a2c 100644
--- a/erts/preloaded/src/erts_internal.erl
+++ b/erts/preloaded/src/erts_internal.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2012-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.
@@ -55,7 +55,9 @@
-export([await_microstate_accounting_modifications/3,
gather_microstate_accounting_result/2]).
-%% Auto-import name clash
+-export([trace/3, trace_pattern/3]).
+
+%% Auto import name clash
-export([check_process_code/2]).
%%
@@ -403,3 +405,28 @@ microstate_accounting(Ref, Threads) ->
{Ref, Res} ->
[Res | microstate_accounting(Ref, Threads - 1)]
end.
+
+-spec trace(PidPortSpec, How, FlagList) -> integer() when
+ PidPortSpec :: pid() | port()
+ | all | processes | ports
+ | existing | existing_processes | existing_ports
+ | new | new_processes | new_ports,
+ How :: boolean(),
+ FlagList :: [].
+trace(_PidSpec, _How, _FlagList) ->
+ erlang:nif_error(undefined).
+
+-type trace_pattern_mfa() ::
+ {atom(),atom(),arity() | '_'} | on_load.
+-type trace_match_spec() ::
+ [{[term()] | '_' ,[term()],[term()]}].
+
+-spec trace_pattern(MFA, MatchSpec, FlagList) -> non_neg_integer() when
+ MFA :: trace_pattern_mfa(),
+ MatchSpec :: (MatchSpecList :: trace_match_spec())
+ | boolean()
+ | restart
+ | pause,
+ FlagList :: [ ].
+trace_pattern(_MFA, _MatchSpec, _FlagList) ->
+ erlang:nif_error(undefined).
diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl
index ed65c57c0d..618b53f6bb 100644
--- a/erts/preloaded/src/init.erl
+++ b/erts/preloaded/src/init.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-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.
@@ -41,6 +41,7 @@
%% -s : Start own processes.
%%
%% Experimental flags:
+%% -profile_boot : Use an 'eprof light' to profile boot sequence
%% -init_debug : Activate debug printouts in init
%% -loader_debug : Activate debug printouts in erl_prim_loader
%% -code_path_choice : strict | relaxed
@@ -129,7 +130,7 @@ bs2ss(L) ->
get_status() ->
request(get_status).
--spec fetch_loaded() -> [atom()].
+-spec fetch_loaded() -> [{module(),file:filename()}].
fetch_loaded() ->
request(fetch_loaded).
@@ -179,7 +180,16 @@ stop(Status) -> init ! {stop,{stop,Status}}, ok.
boot(BootArgs) ->
register(init, self()),
process_flag(trap_exit, true),
+
+ %% Load the tracer nif
+ erl_tracer:on_load(),
+
{Start0,Flags,Args} = parse_boot_args(BootArgs),
+ %% We don't get to profile parsing of BootArgs
+ case get_flag(profile_boot, Flags, false) of
+ false -> ok;
+ true -> debug_profile_start()
+ end,
Start = map(fun prepare_run_args/1, Start0),
boot(Start, Flags, Args).
@@ -297,9 +307,9 @@ crash(String, List) ->
-spec boot_loop(pid(), state()) -> no_return().
boot_loop(BootPid, State) ->
receive
- {BootPid,loaded,ModLoaded} ->
- Loaded = State#state.loaded,
- boot_loop(BootPid,State#state{loaded = [ModLoaded|Loaded]});
+ {BootPid,loaded,NewlyLoaded} ->
+ Loaded = NewlyLoaded ++ State#state.loaded,
+ boot_loop(BootPid, State#state{loaded = Loaded});
{BootPid,started,KernelPid} ->
boot_loop(BootPid, new_kernelpid(KernelPid, BootPid, State));
{BootPid,progress,started} ->
@@ -338,12 +348,25 @@ boot_loop(BootPid, State) ->
end.
ensure_loaded(Module, Loaded) ->
+ case erlang:module_loaded(Module) of
+ true ->
+ {{module, Module}, Loaded};
+ false ->
+ do_ensure_loaded(Module, Loaded)
+ end.
+
+do_ensure_loaded(Module, Loaded) ->
File = atom_to_list(Module) ++ objfile_extension(),
- case catch load_mod(Module,File) of
- {ok, FullName} ->
- {{module, Module}, [{Module, FullName}|Loaded]};
- Res ->
- {Res, Loaded}
+ case erl_prim_loader:get_file(File) of
+ {ok,BinCode,FullName} ->
+ case do_load_module(Module, BinCode) of
+ ok ->
+ {{module, Module}, [{Module, FullName}|Loaded]};
+ error ->
+ {error, [{Module, FullName}|Loaded]}
+ end;
+ Error ->
+ {Error, Loaded}
end.
%% Tell subscribed processes the system has started.
@@ -748,7 +771,14 @@ do_boot(Init,Flags,Start) ->
%% print the node name into the Purify log.
(catch erlang:system_info({purify, "Node: " ++ atom_to_list(node())})),
- start_em(Start).
+ start_em(Start),
+ case get_flag(profile_boot,Flags,false) of
+ false -> ok;
+ true ->
+ debug_profile_format_mfas(debug_profile_mfas()),
+ debug_profile_stop()
+ end,
+ ok.
get_root(Flags) ->
case get_argument(root, Flags) of
@@ -842,13 +872,6 @@ eval_script([{kernel_load_completed}|T], #es{load_mode=Mode}=Es0) ->
_ -> Es0#es{prim_load=false}
end,
eval_script(T, Es);
-eval_script([{primLoad,[Mod]}|T], #es{prim_load=true}=Es) ->
- %% Common special case (loading of error_handler). Nothing
- %% to gain by parallel loading.
- File = atom_to_list(Mod) ++ objfile_extension(),
- {ok,Full} = load_mod(Mod, File),
- init ! {self(),loaded,{Mod,Full}}, % Tell init about loaded module
- eval_script(T, Es);
eval_script([{primLoad,Mods}|T], #es{init=Init,prim_load=PrimLoad}=Es)
when is_list(Mods) ->
case PrimLoad of
@@ -873,14 +896,44 @@ eval_script([], #es{}) ->
eval_script(What, #es{}) ->
exit({'unexpected command in bootfile',What}).
-load_modules([Mod|Mods], Init) ->
- File = atom_to_list(Mod) ++ objfile_extension(),
- {ok,Full} = load_mod(Mod,File),
- Init ! {self(),loaded,{Mod,Full}}, %Tell init about loaded module
- load_modules(Mods, Init);
-load_modules([], _) ->
+load_modules(Mods0, Init) ->
+ Mods = [M || M <- Mods0, not erlang:module_loaded(M)],
+ F = prepare_loading_fun(),
+ case erl_prim_loader:get_modules(Mods, F) of
+ {ok,{Prep0,[]}} ->
+ Prep = [Code || {_,{prepared,Code,_}} <- Prep0],
+ ok = erlang:finish_loading(Prep),
+ Loaded = [{Mod,Full} || {Mod,{_,_,Full}} <- Prep0],
+ Init ! {self(),loaded,Loaded},
+ Beams = [{M,Beam,Full} || {M,{on_load,Beam,Full}} <- Prep0],
+ load_rest(Beams, Init);
+ {ok,{_,[_|_]=Errors}} ->
+ Ms = [M || {M,_} <- Errors],
+ exit({load_failed,Ms})
+ end.
+
+load_rest([{Mod,Beam,Full}|T], Init) ->
+ do_load_module(Mod, Beam),
+ Init ! {self(),loaded,[{Mod,Full}]},
+ load_rest(T, Init);
+load_rest([], _) ->
ok.
+prepare_loading_fun() ->
+ fun(Mod, FullName, Beam) ->
+ case erlang:prepare_loading(Mod, Beam) of
+ Prepared when is_binary(Prepared) ->
+ case erlang:has_prepared_code_on_load(Prepared) of
+ true ->
+ {ok,{on_load,Beam,FullName}};
+ false ->
+ {ok,{prepared,Prepared,FullName}}
+ end;
+ {error,_}=Error ->
+ Error
+ end
+ end.
+
make_path(Pa, Pz, Path, Vars) ->
append([Pa,append([fix_path(Path,Vars),Pz])]).
@@ -1033,35 +1086,17 @@ start_it([_|_]=MFA) ->
[M,F|Args] -> M:F(Args) % Args is a list
end.
-%%
-%% Fetch a module and load it into the system.
-%%
-load_mod(Mod, File) ->
- case erlang:module_loaded(Mod) of
- false ->
- case erl_prim_loader:get_file(File) of
- {ok,BinCode,FullName} ->
- load_mod_code(Mod, BinCode, FullName);
- _ ->
- exit({'cannot load',Mod,get_file})
- end;
- _ -> % Already loaded.
- {ok,File}
- end.
+%% Load a module.
-load_mod_code(Mod, BinCode, FullName) ->
- case erlang:module_loaded(Mod) of
- false ->
- case erlang:load_module(Mod, BinCode) of
- {module,Mod} -> {ok,FullName};
- {error,on_load} ->
- ?ON_LOAD_HANDLER ! {loaded,Mod},
- {ok,FullName};
- Other ->
- exit({'cannot load',Mod,Other})
- end;
- _ -> % Already loaded.
- {ok,FullName}
+do_load_module(Mod, BinCode) ->
+ case erlang:load_module(Mod, BinCode) of
+ {module,Mod} ->
+ ok;
+ {error,on_load} ->
+ ?ON_LOAD_HANDLER ! {loaded,Mod},
+ ok;
+ _ ->
+ error
end.
%% --------------------------------------------------------
@@ -1317,3 +1352,64 @@ run_on_load_handlers([M|Ms], Debug) ->
end
end;
run_on_load_handlers([], _) -> ok.
+
+
+%% debug profile (light variant of eprof)
+debug_profile_start() ->
+ _ = erlang:trace_pattern({'_','_','_'},true,[call_time]),
+ _ = erlang:trace_pattern(on_load,true,[call_time]),
+ _ = erlang:trace(all,true,[call]),
+ ok.
+
+debug_profile_stop() ->
+ _ = erlang:trace_pattern({'_','_','_'},false,[call_time]),
+ _ = erlang:trace_pattern(on_load,false,[call_time]),
+ _ = erlang:trace(all,false,[call]),
+ ok.
+
+debug_profile_mfas() ->
+ _ = erlang:trace_pattern({'_','_','_'},pause,[call_time]),
+ _ = erlang:trace_pattern(on_load,pause,[call_time]),
+ MFAs = collect_loaded_mfas() ++ erlang:system_info(snifs),
+ collect_mfas(MFAs,[]).
+
+%% debug_profile_format_mfas should be called at the end of the boot phase
+%% so all pertinent modules should be loaded at that point.
+debug_profile_format_mfas(MFAs0) ->
+ MFAs = lists:sort(MFAs0),
+ lists:foreach(fun({{Us,C},{M,F,A}}) ->
+ Str = io_lib:format("~w:~w/~w", [M,F,A]),
+ io:format(standard_error,"~55s - ~6w : ~w us~n", [Str,C,Us])
+ end, MFAs),
+ ok.
+
+collect_loaded_mfas() ->
+ Ms = [M || M <- [element(1, Mi) || Mi <- code:all_loaded()]],
+ collect_loaded_mfas(Ms,[]).
+
+collect_loaded_mfas([],MFAs) -> MFAs;
+collect_loaded_mfas([M|Ms],MFAs0) ->
+ MFAs = [{M,F,A} || {F,A} <- M:module_info(functions)],
+ collect_loaded_mfas(Ms,MFAs ++ MFAs0).
+
+
+collect_mfas([], Info) -> Info;
+collect_mfas([MFA|MFAs],Info) ->
+ case erlang:trace_info(MFA,call_time) of
+ {call_time, []} ->
+ collect_mfas(MFAs,Info);
+ {call_time, false} ->
+ collect_mfas(MFAs,Info);
+ {call_time, Data} ->
+ case collect_mfa(MFA,Data,0,0) of
+ {{0,_},_} ->
+ %% ignore mfas with zero time
+ collect_mfas(MFAs,Info);
+ MfaData ->
+ collect_mfas(MFAs,[MfaData|Info])
+ end
+ end.
+
+collect_mfa(Mfa,[],Count,Time) -> {{Time,Count},Mfa};
+collect_mfa(Mfa,[{_Pid,C,S,Us}|Data],Count,Time) ->
+ collect_mfa(Mfa,Data,Count + C,Time + S * 1000000 + Us).
diff --git a/erts/preloaded/src/otp_ring0.erl b/erts/preloaded/src/otp_ring0.erl
index 3158fc7d21..62a60fffe2 100644
--- a/erts/preloaded/src/otp_ring0.erl
+++ b/erts/preloaded/src/otp_ring0.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2000-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.
diff --git a/erts/preloaded/src/prim_eval.S b/erts/preloaded/src/prim_eval.S
index 1b7b00a7c9..e7f09a870c 100644
--- a/erts/preloaded/src/prim_eval.S
+++ b/erts/preloaded/src/prim_eval.S
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-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.
diff --git a/erts/preloaded/src/prim_eval.erl b/erts/preloaded/src/prim_eval.erl
index 732e22468e..22e924f9e9 100644
--- a/erts/preloaded/src/prim_eval.erl
+++ b/erts/preloaded/src/prim_eval.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-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.
diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl
index bd74831bb7..4872ffd00c 100644
--- a/erts/preloaded/src/prim_inet.erl
+++ b/erts/preloaded/src/prim_inet.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2000-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.
diff --git a/erts/preloaded/src/prim_zip.erl b/erts/preloaded/src/prim_zip.erl
index c4b949afcb..b1ddbbe173 100644
--- a/erts/preloaded/src/prim_zip.erl
+++ b/erts/preloaded/src/prim_zip.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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.
diff --git a/erts/preloaded/src/zip_internal.hrl b/erts/preloaded/src/zip_internal.hrl
index d5cf52fae4..2769ca152d 100644
--- a/erts/preloaded/src/zip_internal.hrl
+++ b/erts/preloaded/src/zip_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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.
diff --git a/erts/preloaded/src/zlib.erl b/erts/preloaded/src/zlib.erl
index 473ad649c7..fa0f28c5c3 100644
--- a/erts/preloaded/src/zlib.erl
+++ b/erts/preloaded/src/zlib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2003-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.
diff --git a/erts/start_scripts/Makefile b/erts/start_scripts/Makefile
index 8025681924..dfd8153f32 100644
--- a/erts/start_scripts/Makefile
+++ b/erts/start_scripts/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2013. All Rights Reserved.
+# Copyright Ericsson AB 1997-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.
diff --git a/erts/start_scripts/no_dot_erlang.rel.src b/erts/start_scripts/no_dot_erlang.rel.src
index bcc9fa9e8a..04e5fbf741 100644
--- a/erts/start_scripts/no_dot_erlang.rel.src
+++ b/erts/start_scripts/no_dot_erlang.rel.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
+%% Copyright Ericsson AB 2013-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.
diff --git a/erts/start_scripts/start_all_example.rel.src b/erts/start_scripts/start_all_example.rel.src
index 2c4deb4485..a44f3e2925 100644
--- a/erts/start_scripts/start_all_example.rel.src
+++ b/erts/start_scripts/start_all_example.rel.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1996-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.
diff --git a/erts/start_scripts/start_clean.rel.src b/erts/start_scripts/start_clean.rel.src
index 25519deb17..ad468aa9df 100644
--- a/erts/start_scripts/start_clean.rel.src
+++ b/erts/start_scripts/start_clean.rel.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1996-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.
diff --git a/erts/start_scripts/start_sasl.rel.src b/erts/start_scripts/start_sasl.rel.src
index 9cf417ade5..23b6a89e1d 100644
--- a/erts/start_scripts/start_sasl.rel.src
+++ b/erts/start_scripts/start_sasl.rel.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
+%% Copyright Ericsson AB 1996-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.
diff --git a/erts/test/Makefile b/erts/test/Makefile
index a01d67e34f..1fe230adaf 100644
--- a/erts/test/Makefile
+++ b/erts/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2014. All Rights Reserved.
+# Copyright Ericsson AB 1997-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.
diff --git a/erts/test/erl_print_SUITE.erl b/erts/test/erl_print_SUITE.erl
index f0fee49024..463d890688 100644
--- a/erts/test/erl_print_SUITE.erl
+++ b/erts/test/erl_print_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2005-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.
@@ -28,153 +28,133 @@
-module(erl_print_SUITE).
-author('[email protected]').
+-export([all/0, suite/0, init_per_testcase/2, end_per_testcase/2]).
-%-define(line_trace, 1).
-
--define(DEFAULT_TIMEOUT, ?t:minutes(10)).
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- init_per_testcase/2, end_per_testcase/2]).
-
--export([erlang_display/1, integer/1, float/1,
- string/1, character/1, snprintf/1, quote/1]).
+-export([erlang_display/1, integer/1, float/1,
+ string/1, character/1, snprintf/1, quote/1]).
-include_lib("common_test/include/ct.hrl").
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap, {minutes, 10}}].
all() ->
- test_cases().
-
-groups() ->
- [].
+ [erlang_display, integer, float, string, character,
+ snprintf, quote].
-init_per_suite(Config) ->
- Config.
+init_per_testcase(Case, Config) ->
+ [{testcase, Case}|Config].
-end_per_suite(_Config) ->
+end_per_testcase(_Case, _Config) ->
ok.
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
%%
%%
%% Test cases
%%
%%
-test_cases() ->
- [erlang_display, integer, float, string, character,
- snprintf, quote].
-
-erlang_display(doc) -> [];
-erlang_display(suite) -> [];
erlang_display(Config) when is_list(Config) ->
- ?line put(erlang_display_test, ok),
+ put(erlang_display_test, ok),
OAIS = erts_debug:set_internal_state(available_internal_state, true),
%% atoms
- ?line chk_display(atom, "atom"),
- ?line chk_display(true, "true"),
- ?line chk_display(false, "false"),
- ?line chk_display('DOWN', "'DOWN'"),
- ?line chk_display('EXIT', "'EXIT'"),
- ?line chk_display('asdDofw $@{}][', "'asdDofw $@{}]['"),
+ chk_display(atom, "atom"),
+ chk_display(true, "true"),
+ chk_display(false, "false"),
+ chk_display('DOWN', "'DOWN'"),
+ chk_display('EXIT', "'EXIT'"),
+ chk_display('asdDofw $@{}][', "'asdDofw $@{}]['"),
%% integers
- ?line chk_display(0, "0"),
- ?line chk_display(1, "1"),
- ?line chk_display(4711, "4711"),
- ?line chk_display(((1 bsl 27) - 1), "134217727"),
- ?line chk_display((1 bsl 27), "134217728"),
- ?line chk_display((1 bsl 32), "4294967296"),
- ?line chk_display(11111111111, "11111111111"),
- ?line chk_display((1 bsl 59) - 1, "576460752303423487"),
- ?line chk_display(1 bsl 59, "576460752303423488"),
- ?line chk_display(111111111111111111111, "111111111111111111111"),
- ?line chk_display(123456789012345678901234567890,
- "123456789012345678901234567890"),
- ?line chk_display(1 bsl 10000, str_1_bsl_10000()),
- ?line chk_display(-1, "-1"),
- ?line chk_display(-4711, "-4711"),
- ?line chk_display(-(1 bsl 27), "-134217728"),
- ?line chk_display(-((1 bsl 27) + 1), "-134217729"),
- ?line chk_display(-(1 bsl 32), "-4294967296"),
- ?line chk_display(-11111111111, "-11111111111"),
- ?line chk_display(-(1 bsl 59), "-576460752303423488"),
- ?line chk_display(-((1 bsl 59) + 1), "-576460752303423489"),
- ?line chk_display(-111111111111111111111, "-111111111111111111111"),
- ?line chk_display(-123456789012345678901234567890,
- "-123456789012345678901234567890"),
- ?line chk_display(-(1 bsl 10000), [$- | str_1_bsl_10000()]),
-
- ?line MyCre = my_cre(),
+ chk_display(0, "0"),
+ chk_display(1, "1"),
+ chk_display(4711, "4711"),
+ chk_display(((1 bsl 27) - 1), "134217727"),
+ chk_display((1 bsl 27), "134217728"),
+ chk_display((1 bsl 32), "4294967296"),
+ chk_display(11111111111, "11111111111"),
+ chk_display((1 bsl 59) - 1, "576460752303423487"),
+ chk_display(1 bsl 59, "576460752303423488"),
+ chk_display(111111111111111111111, "111111111111111111111"),
+ chk_display(123456789012345678901234567890,
+ "123456789012345678901234567890"),
+ chk_display(1 bsl 10000, str_1_bsl_10000()),
+ chk_display(-1, "-1"),
+ chk_display(-4711, "-4711"),
+ chk_display(-(1 bsl 27), "-134217728"),
+ chk_display(-((1 bsl 27) + 1), "-134217729"),
+ chk_display(-(1 bsl 32), "-4294967296"),
+ chk_display(-11111111111, "-11111111111"),
+ chk_display(-(1 bsl 59), "-576460752303423488"),
+ chk_display(-((1 bsl 59) + 1), "-576460752303423489"),
+ chk_display(-111111111111111111111, "-111111111111111111111"),
+ chk_display(-123456789012345678901234567890,
+ "-123456789012345678901234567890"),
+ chk_display(-(1 bsl 10000), [$- | str_1_bsl_10000()]),
+
+ MyCre = my_cre(),
%% pids
- ?line chk_display(mk_pid_xstr({node(), MyCre}, 4711, 42)),
- ?line chk_display(mk_pid_xstr({node(), oth_cre(MyCre)}, 4711, 42)),
- ?line chk_display(mk_pid_xstr({node(), oth_cre(oth_cre(MyCre))}, 4711, 42)),
+ chk_display(mk_pid_xstr({node(), MyCre}, 4711, 42)),
+ chk_display(mk_pid_xstr({node(), oth_cre(MyCre)}, 4711, 42)),
+ chk_display(mk_pid_xstr({node(), oth_cre(oth_cre(MyCre))}, 4711, 42)),
- ?line chk_display(mk_pid_xstr({a@b, MyCre}, 4711, 42)),
- ?line chk_display(mk_pid_xstr({a@b, oth_cre(MyCre)}, 4711, 42)),
- ?line chk_display(mk_pid_xstr({a@b, oth_cre(oth_cre(MyCre))}, 4711, 42)),
+ chk_display(mk_pid_xstr({a@b, MyCre}, 4711, 42)),
+ chk_display(mk_pid_xstr({a@b, oth_cre(MyCre)}, 4711, 42)),
+ chk_display(mk_pid_xstr({a@b, oth_cre(oth_cre(MyCre))}, 4711, 42)),
%% ports
- ?line chk_display(mk_port_xstr({node(), MyCre}, 4711)),
- ?line chk_display(mk_port_xstr({node(), oth_cre(MyCre)}, 4711)),
- ?line chk_display(mk_port_xstr({node(), oth_cre(oth_cre(MyCre))}, 4711)),
+ chk_display(mk_port_xstr({node(), MyCre}, 4711)),
+ chk_display(mk_port_xstr({node(), oth_cre(MyCre)}, 4711)),
+ chk_display(mk_port_xstr({node(), oth_cre(oth_cre(MyCre))}, 4711)),
- ?line chk_display(mk_port_xstr({c@d, MyCre}, 4711)),
- ?line chk_display(mk_port_xstr({c@d, oth_cre(MyCre)}, 4711)),
- ?line chk_display(mk_port_xstr({c@d, oth_cre(oth_cre(MyCre))}, 4711)),
+ chk_display(mk_port_xstr({c@d, MyCre}, 4711)),
+ chk_display(mk_port_xstr({c@d, oth_cre(MyCre)}, 4711)),
+ chk_display(mk_port_xstr({c@d, oth_cre(oth_cre(MyCre))}, 4711)),
%% refs
- ?line chk_display(mk_ref_xstr({node(), MyCre}, [1,2,3])),
- ?line chk_display(mk_ref_xstr({node(), oth_cre(MyCre)}, [1,2,3])),
- ?line chk_display(mk_ref_xstr({node(), oth_cre(oth_cre(MyCre))}, [1,2,3])),
+ chk_display(mk_ref_xstr({node(), MyCre}, [1,2,3])),
+ chk_display(mk_ref_xstr({node(), oth_cre(MyCre)}, [1,2,3])),
+ chk_display(mk_ref_xstr({node(), oth_cre(oth_cre(MyCre))}, [1,2,3])),
- ?line chk_display(mk_ref_xstr({e@f, MyCre},[1,2,3] )),
- ?line chk_display(mk_ref_xstr({e@f, oth_cre(MyCre)}, [1,2,3])),
- ?line chk_display(mk_ref_xstr({e@f, oth_cre(oth_cre(MyCre))}, [1,2,3])),
+ chk_display(mk_ref_xstr({e@f, MyCre},[1,2,3] )),
+ chk_display(mk_ref_xstr({e@f, oth_cre(MyCre)}, [1,2,3])),
+ chk_display(mk_ref_xstr({e@f, oth_cre(oth_cre(MyCre))}, [1,2,3])),
%% Compund terms
- ?line {Pid, PidStr} = mk_pid_xstr({x@y, oth_cre(MyCre)}, 4712, 41),
- ?line {Port, PortStr} = mk_port_xstr({x@y, oth_cre(MyCre)}, 4712),
- ?line {Ref, RefStr} = mk_ref_xstr({e@f, oth_cre(MyCre)}, [11,12,13]),
-
- ?line chk_display({atom,-4711,Ref,{"hej",[Pid,222222222222222222222222,Port,4711]}},
- "{atom,-4711,"++RefStr++",{\"hej\",["++PidStr++",222222222222222222222222,"++PortStr++",4711]}}"),
- ?line chk_display({{{{{{{{{{{{{{{{{{{{{{{hi}}}}}}}}}}}}}}}}}}}}}}},
- "{{{{{{{{{{{{{{{{{{{{{{{hi}}}}}}}}}}}}}}}}}}}}}}}"),
- ?line chk_display([[[[[[[[[[[[[[[[[[[[[[[yo]]]]]]]]]]]]]]]]]]]]]]],
- "[[[[[[[[[[[[[[[[[[[[[[[yo]]]]]]]]]]]]]]]]]]]]]]]"),
- ?line chk_display({[{[{[{[{[{[{[{[{[{[{[{[ii]}]}]}]}]}]}]}]}]}]}]}]},
- "{[{[{[{[{[{[{[{[{[{[{[{[ii]}]}]}]}]}]}]}]}]}]}]}]}"),
- ?line chk_display([], "[]"), % Not really a compound term :)
- ?line chk_display([a|b], "[a|b]"),
- ?line chk_display([a,b,c|z], "[a,b,c|z]"),
- ?line chk_display([a,b,c], "[a,b,c]"),
- ?line chk_display([Pid,Port,Ref],
- "["++PidStr++","++PortStr++","++RefStr++"]"),
- ?line chk_display("abcdefghijklmnopqrstuvwxyz",
- "\"abcdefghijklmnopqrstuvwxyz\""),
- ?line chk_display("ABCDEFGHIJKLMNOPQRSTUVWXYZ",
- "\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\""),
- ?line chk_display("H E J", "\"H E J\""),
- ?line chk_display("asdDofw $@{}][", "\"asdDofw $@{}][\""),
-
+ {Pid, PidStr} = mk_pid_xstr({x@y, oth_cre(MyCre)}, 4712, 41),
+ {Port, PortStr} = mk_port_xstr({x@y, oth_cre(MyCre)}, 4712),
+ {Ref, RefStr} = mk_ref_xstr({e@f, oth_cre(MyCre)}, [11,12,13]),
+
+ chk_display({atom,-4711,Ref,{"hej",[Pid,222222222222222222222222,Port,4711]}},
+ "{atom,-4711,"++RefStr++",{\"hej\",["++PidStr++",222222222222222222222222,"++PortStr++",4711]}}"),
+ chk_display({{{{{{{{{{{{{{{{{{{{{{{hi}}}}}}}}}}}}}}}}}}}}}}},
+ "{{{{{{{{{{{{{{{{{{{{{{{hi}}}}}}}}}}}}}}}}}}}}}}}"),
+ chk_display([[[[[[[[[[[[[[[[[[[[[[[yo]]]]]]]]]]]]]]]]]]]]]]],
+ "[[[[[[[[[[[[[[[[[[[[[[[yo]]]]]]]]]]]]]]]]]]]]]]]"),
+ chk_display({[{[{[{[{[{[{[{[{[{[{[{[ii]}]}]}]}]}]}]}]}]}]}]}]},
+ "{[{[{[{[{[{[{[{[{[{[{[{[ii]}]}]}]}]}]}]}]}]}]}]}]}"),
+ chk_display([], "[]"), % Not really a compound term :)
+ chk_display([a|b], "[a|b]"),
+ chk_display([a,b,c|z], "[a,b,c|z]"),
+ chk_display([a,b,c], "[a,b,c]"),
+ chk_display([Pid,Port,Ref],
+ "["++PidStr++","++PortStr++","++RefStr++"]"),
+ chk_display("abcdefghijklmnopqrstuvwxyz",
+ "\"abcdefghijklmnopqrstuvwxyz\""),
+ chk_display("ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ "\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\""),
+ chk_display("H E J", "\"H E J\""),
+ chk_display("asdDofw $@{}][", "\"asdDofw $@{}][\""),
+
%%
%% TODO: Check binaries, fun and floats...
%%
erts_debug:set_internal_state(available_internal_state, OAIS),
- ?line ok = get(erlang_display_test).
+ ok = get(erlang_display_test).
get_chnl_no(NodeName) when is_atom(NodeName) ->
erts_debug:get_internal_state({channel_number, NodeName}).
@@ -182,20 +162,20 @@ get_chnl_no(NodeName) when is_atom(NodeName) ->
chk_display(Term, Expect) when is_list(Expect) ->
Dstr = erts_debug:display(Term),
case Expect ++ io_lib:nl() of
- Dstr ->
- ?t:format("Test of \"~p\" succeeded.~n"
- " Expected and got: ~s~n",
- [Term, io_lib:write_string(Dstr)]);
- DoExpect ->
- ?t:format("***~n"
- "*** Test of \"~p\" failed!~n"
- "*** Expected: ~s~n"
- "*** Got: ~s~n"
- "***~n",
- [Term,
- io_lib:write_string(DoExpect),
- io_lib:write_string(Dstr)]),
- put(erlang_display_test, failed)
+ Dstr ->
+ io:format("Test of \"~p\" succeeded.~n"
+ " Expected and got: ~s~n",
+ [Term, io_lib:write_string(Dstr)]);
+ DoExpect ->
+ io:format("***~n"
+ "*** Test of \"~p\" failed!~n"
+ "*** Expected: ~s~n"
+ "*** Got: ~s~n"
+ "***~n",
+ [Term,
+ io_lib:write_string(DoExpect),
+ io_lib:write_string(Dstr)]),
+ put(erlang_display_test, failed)
end.
chk_display({Term, Expect}) ->
@@ -204,20 +184,20 @@ chk_display({Term, Expect}) ->
mk_pid_xstr({NodeName, Creation}, Number, Serial) ->
Pid = mk_pid({NodeName, Creation}, Number, Serial),
XStr = "<" ++ integer_to_list(get_chnl_no(NodeName))
- ++ "." ++ integer_to_list(Number)
- ++ "." ++ integer_to_list(Serial) ++ ">",
+ ++ "." ++ integer_to_list(Number)
+ ++ "." ++ integer_to_list(Serial) ++ ">",
{Pid, XStr}.
mk_port_xstr({NodeName, Creation}, Number) ->
Port = mk_port({NodeName, Creation}, Number),
XStr = "#Port<" ++ integer_to_list(get_chnl_no(NodeName))
- ++ "." ++ integer_to_list(Number) ++ ">",
+ ++ "." ++ integer_to_list(Number) ++ ">",
{Port, XStr}.
mk_ref_xstr({NodeName, Creation}, Numbers) ->
Ref = mk_ref({NodeName, Creation}, Numbers),
XStr = "#Ref<" ++ integer_to_list(get_chnl_no(NodeName))
- ++ ref_numbers_xstr(Numbers) ++ ">",
+ ++ ref_numbers_xstr(Numbers) ++ ">",
{Ref, XStr}.
ref_numbers_xstr([]) ->
@@ -240,18 +220,7 @@ ref_numbers_xstr([N | Ns]) ->
%%
%%
-default_testcase_impl(doc) -> [];
-default_testcase_impl(suite) -> [];
-default_testcase_impl(Config) when is_list(Config) -> ?line run_case(Config).
-
-init_per_testcase(Case, Config) ->
- Dog = ?t:timetrap(?DEFAULT_TIMEOUT),
- [{testcase, Case}, {watchdog, Dog} |Config].
-
-end_per_testcase(_Case, Config) ->
- Dog = ?config(watchdog, Config),
- ?t:timetrap_cancel(Dog),
- ok.
+default_testcase_impl(Config) when is_list(Config) -> run_case(Config).
-define(TESTPROG, "erl_print_tests").
-define(FAILED_MARKER, $E,$P,$-,$T,$E,$S,$T,$-,$F,$A,$I,$L,$U,$R,$E).
@@ -260,62 +229,62 @@ end_per_testcase(_Case, Config) ->
-define(PID_MARKER, $E,$P,$-,$T,$E,$S,$T,$-,$P,$I,$D).
port_prog_killer(EProc, OSProc) when is_pid(EProc), is_list(OSProc) ->
- ?line process_flag(trap_exit, true),
- ?line Ref = erlang:monitor(process, EProc),
- ?line receive
- {'DOWN', Ref, _, _, Reason} when is_tuple(Reason),
- element(1, Reason)
- == timetrap_timeout ->
- ?line Cmd = "kill -9 " ++ OSProc,
- ?line ?t:format("Test case timed out. "
- "Trying to kill port program.~n"
- " Executing: ~p~n", [Cmd]),
- ?line case os:cmd(Cmd) of
- [] ->
- ok;
- OsCmdRes ->
- ?line ?t:format(" ~s", [OsCmdRes])
- end;
- {'DOWN', Ref, _, _, _} ->
- %% OSProc is assumed to have terminated by itself
- ?line ok
- end.
+ process_flag(trap_exit, true),
+ Ref = erlang:monitor(process, EProc),
+ receive
+ {'DOWN', Ref, _, _, Reason} when is_tuple(Reason),
+ element(1, Reason)
+ == timetrap_timeout ->
+ Cmd = "kill -9 " ++ OSProc,
+ io:format("Test case timed out. "
+ "Trying to kill port program.~n"
+ " Executing: ~p~n", [Cmd]),
+ case os:cmd(Cmd) of
+ [] ->
+ ok;
+ OsCmdRes ->
+ io:format(" ~s", [OsCmdRes])
+ end;
+ {'DOWN', Ref, _, _, _} ->
+ %% OSProc is assumed to have terminated by itself
+ ok
+ end.
get_line(_Port, eol, Data) ->
- ?line Data;
+ Data;
get_line(Port, noeol, Data) ->
- ?line receive
- {Port, {data, {Flag, NextData}}} ->
- ?line get_line(Port, Flag, Data ++ NextData);
- {Port, eof} ->
- ?line ?t:fail(port_prog_unexpectedly_closed)
- end.
+ receive
+ {Port, {data, {Flag, NextData}}} ->
+ get_line(Port, Flag, Data ++ NextData);
+ {Port, eof} ->
+ ct:fail(port_prog_unexpectedly_closed)
+ end.
read_case_data(Port, TestCase) ->
- ?line receive
- {Port, {data, {eol, [?SUCCESS_MARKER]}}} ->
- ?line ok;
- {Port, {data, {Flag, [?SUCCESS_MARKER | CommentStart]}}} ->
- ?line {comment, get_line(Port, Flag, CommentStart)};
- {Port, {data, {Flag, [?SKIPPED_MARKER | CommentStart]}}} ->
- ?line {skipped, get_line(Port, Flag, CommentStart)};
- {Port, {data, {Flag, [?FAILED_MARKER | ReasonStart]}}} ->
- ?line ?t:fail(get_line(Port, Flag, ReasonStart));
- {Port, {data, {eol, [?PID_MARKER | PidStr]}}} ->
- ?line ?t:format("Port program pid: ~s~n", [PidStr]),
- ?line CaseProc = self(),
- ?line _ = list_to_integer(PidStr), % Sanity check
- spawn_opt(fun () ->
- port_prog_killer(CaseProc, PidStr)
- end,
- [{priority, max}, link]),
- read_case_data(Port, TestCase);
- {Port, {data, {Flag, LineStart}}} ->
- ?line ?t:format("~s~n", [get_line(Port, Flag, LineStart)]),
- read_case_data(Port, TestCase);
- {Port, eof} ->
- ?line ?t:fail(port_prog_unexpectedly_closed)
- end.
+ receive
+ {Port, {data, {eol, [?SUCCESS_MARKER]}}} ->
+ ok;
+ {Port, {data, {Flag, [?SUCCESS_MARKER | CommentStart]}}} ->
+ {comment, get_line(Port, Flag, CommentStart)};
+ {Port, {data, {Flag, [?SKIPPED_MARKER | CommentStart]}}} ->
+ {skipped, get_line(Port, Flag, CommentStart)};
+ {Port, {data, {Flag, [?FAILED_MARKER | ReasonStart]}}} ->
+ ct:fail(get_line(Port, Flag, ReasonStart));
+ {Port, {data, {eol, [?PID_MARKER | PidStr]}}} ->
+ io:format("Port program pid: ~s~n", [PidStr]),
+ CaseProc = self(),
+ _ = list_to_integer(PidStr), % Sanity check
+ spawn_opt(fun () ->
+ port_prog_killer(CaseProc, PidStr)
+ end,
+ [{priority, max}, link]),
+ read_case_data(Port, TestCase);
+ {Port, {data, {Flag, LineStart}}} ->
+ io:format("~s~n", [get_line(Port, Flag, LineStart)]),
+ read_case_data(Port, TestCase);
+ {Port, eof} ->
+ ct:fail(port_prog_unexpectedly_closed)
+ end.
run_case(Config) ->
run_case(Config, "").
@@ -324,27 +293,27 @@ run_case(Config, TestArgs) ->
run_case(Config, TestArgs, fun (_Port) -> ok end).
run_case(Config, TestArgs, Fun) ->
- Test = atom_to_list(?config(testcase, Config)),
- TestProg = filename:join([?config(data_dir, Config),
- ?TESTPROG
- ++ "."
- ++ atom_to_list(erlang:system_info(threads))]),
+ Test = atom_to_list(proplists:get_value(testcase, Config)),
+ TestProg = filename:join([proplists:get_value(data_dir, Config),
+ ?TESTPROG
+ ++ "."
+ ++ atom_to_list(erlang:system_info(threads))]),
Cmd = TestProg ++ " " ++ Test ++ " " ++ TestArgs,
case catch open_port({spawn, Cmd}, [stream,
- use_stdio,
- stderr_to_stdout,
- eof,
- {line, 1024}]) of
- Port when is_port(Port) ->
- ?line Fun(Port),
- ?line CaseResult = read_case_data(Port, Test),
- ?line receive
- {Port, eof} ->
- ?line ok
- end,
- ?line CaseResult;
- Error ->
- ?line ?t:fail({open_port_failed, Error})
+ use_stdio,
+ stderr_to_stdout,
+ eof,
+ {line, 1024}]) of
+ Port when is_port(Port) ->
+ Fun(Port),
+ CaseResult = read_case_data(Port, Test),
+ receive
+ {Port, eof} ->
+ ok
+ end,
+ CaseResult;
+ Error ->
+ ct:fail({open_port_failed, Error})
end.
@@ -382,80 +351,80 @@ mk_pid({NodeName, Creation}, Number, Serial) when is_atom(NodeName) ->
mk_pid({atom_to_list(NodeName), Creation}, Number, Serial);
mk_pid({NodeName, Creation}, Number, Serial) ->
case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
- ?PID_EXT,
- ?ATOM_EXT,
- uint16_be(length(NodeName)),
- NodeName,
- uint32_be(Number),
- uint32_be(Serial),
- uint8(Creation)])) of
- Pid when is_pid(Pid) ->
- Pid;
- {'EXIT', {badarg, _}} ->
- exit({badarg, mk_pid, [{NodeName, Creation}, Number, Serial]});
- Other ->
- exit({unexpected_binary_to_term_result, Other})
+ ?PID_EXT,
+ ?ATOM_EXT,
+ uint16_be(length(NodeName)),
+ NodeName,
+ uint32_be(Number),
+ uint32_be(Serial),
+ uint8(Creation)])) of
+ Pid when is_pid(Pid) ->
+ Pid;
+ {'EXIT', {badarg, _}} ->
+ exit({badarg, mk_pid, [{NodeName, Creation}, Number, Serial]});
+ Other ->
+ exit({unexpected_binary_to_term_result, Other})
end.
mk_port({NodeName, Creation}, Number) when is_atom(NodeName) ->
mk_port({atom_to_list(NodeName), Creation}, Number);
mk_port({NodeName, Creation}, Number) ->
case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
- ?PORT_EXT,
- ?ATOM_EXT,
- uint16_be(length(NodeName)),
- NodeName,
- uint32_be(Number),
- uint8(Creation)])) of
- Port when is_port(Port) ->
- Port;
- {'EXIT', {badarg, _}} ->
- exit({badarg, mk_port, [{NodeName, Creation}, Number]});
- Other ->
- exit({unexpected_binary_to_term_result, Other})
+ ?PORT_EXT,
+ ?ATOM_EXT,
+ uint16_be(length(NodeName)),
+ NodeName,
+ uint32_be(Number),
+ uint8(Creation)])) of
+ Port when is_port(Port) ->
+ Port;
+ {'EXIT', {badarg, _}} ->
+ exit({badarg, mk_port, [{NodeName, Creation}, Number]});
+ Other ->
+ exit({unexpected_binary_to_term_result, Other})
end.
mk_ref({NodeName, Creation}, Numbers) when is_atom(NodeName),
- is_integer(Creation),
- is_list(Numbers) ->
+ is_integer(Creation),
+ is_list(Numbers) ->
mk_ref({atom_to_list(NodeName), Creation}, Numbers);
mk_ref({NodeName, Creation}, [Number]) when is_list(NodeName),
- is_integer(Creation),
- is_integer(Number) ->
+ is_integer(Creation),
+ is_integer(Number) ->
case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
- ?REFERENCE_EXT,
- ?ATOM_EXT,
- uint16_be(length(NodeName)),
- NodeName,
- uint32_be(Number),
- uint8(Creation)])) of
- Ref when is_reference(Ref) ->
- Ref;
- {'EXIT', {badarg, _}} ->
- exit({badarg, mk_ref, [{NodeName, Creation}, [Number]]});
- Other ->
- exit({unexpected_binary_to_term_result, Other})
+ ?REFERENCE_EXT,
+ ?ATOM_EXT,
+ uint16_be(length(NodeName)),
+ NodeName,
+ uint32_be(Number),
+ uint8(Creation)])) of
+ Ref when is_reference(Ref) ->
+ Ref;
+ {'EXIT', {badarg, _}} ->
+ exit({badarg, mk_ref, [{NodeName, Creation}, [Number]]});
+ Other ->
+ exit({unexpected_binary_to_term_result, Other})
end;
mk_ref({NodeName, Creation}, Numbers) when is_list(NodeName),
- is_integer(Creation),
- is_list(Numbers) ->
+ is_integer(Creation),
+ is_list(Numbers) ->
case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
- ?NEW_REFERENCE_EXT,
- uint16_be(length(Numbers)),
- ?ATOM_EXT,
- uint16_be(length(NodeName)),
- NodeName,
- uint8(Creation),
- lists:map(fun (N) ->
- uint32_be(N)
- end,
- Numbers)])) of
- Ref when is_reference(Ref) ->
- Ref;
- {'EXIT', {badarg, _}} ->
- exit({badarg, mk_ref, [{NodeName, Creation}, Numbers]});
- Other ->
- exit({unexpected_binary_to_term_result, Other})
+ ?NEW_REFERENCE_EXT,
+ uint16_be(length(Numbers)),
+ ?ATOM_EXT,
+ uint16_be(length(NodeName)),
+ NodeName,
+ uint8(Creation),
+ lists:map(fun (N) ->
+ uint32_be(N)
+ end,
+ Numbers)])) of
+ Ref when is_reference(Ref) ->
+ Ref;
+ {'EXIT', {badarg, _}} ->
+ exit({badarg, mk_ref, [{NodeName, Creation}, Numbers]});
+ Other ->
+ exit({unexpected_binary_to_term_result, Other})
end.
my_cre() -> erlang:system_info(creation).
diff --git a/erts/test/erl_print_SUITE_data/Makefile.src b/erts/test/erl_print_SUITE_data/Makefile.src
index e6ea5cc6b9..69ff434c56 100644
--- a/erts/test/erl_print_SUITE_data/Makefile.src
+++ b/erts/test/erl_print_SUITE_data/Makefile.src
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2005-2012. All Rights Reserved.
+# Copyright Ericsson AB 2005-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.
diff --git a/erts/test/erl_print_SUITE_data/character_test.h b/erts/test/erl_print_SUITE_data/character_test.h
index 9ff032cb07..82310ee8e7 100644
--- a/erts/test/erl_print_SUITE_data/character_test.h
+++ b/erts/test/erl_print_SUITE_data/character_test.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/test/erl_print_SUITE_data/erl_print_tests.c b/erts/test/erl_print_SUITE_data/erl_print_tests.c
index fb23dc35a6..2fb7d1ff25 100644
--- a/erts/test/erl_print_SUITE_data/erl_print_tests.c
+++ b/erts/test/erl_print_SUITE_data/erl_print_tests.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/test/erl_print_SUITE_data/integer_64_test.h b/erts/test/erl_print_SUITE_data/integer_64_test.h
index 0c3e7b98a8..4bfc91334d 100644
--- a/erts/test/erl_print_SUITE_data/integer_64_test.h
+++ b/erts/test/erl_print_SUITE_data/integer_64_test.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/test/erl_print_SUITE_data/integer_test.h b/erts/test/erl_print_SUITE_data/integer_test.h
index b91f3622d6..b3744928b7 100644
--- a/erts/test/erl_print_SUITE_data/integer_test.h
+++ b/erts/test/erl_print_SUITE_data/integer_test.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/test/erl_print_SUITE_data/snprintf_test.h b/erts/test/erl_print_SUITE_data/snprintf_test.h
index c612a65521..77692304a3 100644
--- a/erts/test/erl_print_SUITE_data/snprintf_test.h
+++ b/erts/test/erl_print_SUITE_data/snprintf_test.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/test/erl_print_SUITE_data/string_test.h b/erts/test/erl_print_SUITE_data/string_test.h
index 0e257888e6..bfe4215d8a 100644
--- a/erts/test/erl_print_SUITE_data/string_test.h
+++ b/erts/test/erl_print_SUITE_data/string_test.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2009. All Rights Reserved.
+ * Copyright Ericsson AB 2005-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.
diff --git a/erts/test/erlc_SUITE.erl b/erts/test/erlc_SUITE.erl
index 7e44be1fe0..237558a129 100644
--- a/erts/test/erlc_SUITE.erl
+++ b/erts/test/erlc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
@@ -22,10 +22,10 @@
%% Tests the erlc command by compiling various types of files.
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2, compile_erl/1,
- compile_yecc/1, compile_script/1,
- compile_mib/1, good_citizen/1, deep_cwd/1, arg_overflow/1,
- make_dep_options/1]).
+ init_per_group/2,end_per_group/2, compile_erl/1,
+ compile_yecc/1, compile_script/1,
+ compile_mib/1, good_citizen/1, deep_cwd/1, arg_overflow/1,
+ make_dep_options/1]).
-include_lib("common_test/include/ct.hrl").
@@ -57,113 +57,109 @@ end_per_group(_GroupName, Config) ->
%% Tests that compiling Erlang source code works.
compile_erl(Config) when is_list(Config) ->
- ?line {SrcDir, OutDir, Cmd} = get_cmd(Config),
- ?line FileName = filename:join(SrcDir, "erl_test_ok.erl"),
+ {SrcDir, OutDir, Cmd} = get_cmd(Config),
+ FileName = filename:join(SrcDir, "erl_test_ok.erl"),
%% By default, warnings are now turned on.
- ?line run(Config, Cmd, FileName, "",
- ["Warning: function foo/0 is unused\$",
- "_OK_"]),
+ run(Config, Cmd, FileName, "",
+ ["Warning: function foo/0 is unused\$", "_OK_"]),
%% Test that the compiled file is where it should be,
%% and that it is runnable.
- ?line {module, erl_test_ok} = code:load_abs(filename:join(OutDir,
- "erl_test_ok")),
- ?line 42 = erl_test_ok:shoe_size(#person{shoe_size=42}),
- ?line code:purge(erl_test_ok),
+ {module, erl_test_ok} = code:load_abs(filename:join(OutDir, "erl_test_ok")),
+ 42 = erl_test_ok:shoe_size(#person{shoe_size=42}),
+ code:purge(erl_test_ok),
%% Try disabling warnings.
- ?line run(Config, Cmd, FileName, "-W0", ["_OK_"]),
+ run(Config, Cmd, FileName, "-W0", ["_OK_"]),
%% Try treating warnings as errors.
- ?line run(Config, Cmd, FileName, "-Werror",
- ["compile: warnings being treated as errors\$",
- "function foo/0 is unused\$",
- "_ERROR_"]),
+ run(Config, Cmd, FileName, "-Werror",
+ ["compile: warnings being treated as errors\$",
+ "function foo/0 is unused\$", "_ERROR_"]),
%% Check a bad file.
- ?line BadFile = filename:join(SrcDir, "erl_test_bad.erl"),
- ?line run(Config, Cmd, BadFile, "", ["function non_existing/1 undefined\$",
- "_ERROR_"]),
+ BadFile = filename:join(SrcDir, "erl_test_bad.erl"),
+ run(Config, Cmd, BadFile, "", ["function non_existing/1 undefined\$",
+ "_ERROR_"]),
ok.
%% Test that compiling yecc source code works.
compile_yecc(Config) when is_list(Config) ->
- ?line {SrcDir, _, OutDir} = get_dirs(Config),
- ?line Cmd = erlc() ++ " -o" ++ OutDir ++ " ",
- ?line FileName = filename:join(SrcDir, "yecc_test_ok.yrl"),
- ?line run(Config, Cmd, FileName, "-W0", ["_OK_"]),
- ?line true = exists(filename:join(OutDir, "yecc_test_ok.erl")),
-
- ?line BadFile = filename:join(SrcDir, "yecc_test_bad.yrl"),
- ?line run(Config, Cmd, BadFile, "-W0",
- ["rootsymbol form is not a nonterminal\$",
- "undefined nonterminal: form\$",
- "Nonterminals is missing\$",
- "_ERROR_"]),
- ?line exists(filename:join(OutDir, "yecc_test_ok.erl")),
-
+ {SrcDir, _, OutDir} = get_dirs(Config),
+ Cmd = erlc() ++ " -o" ++ OutDir ++ " ",
+ FileName = filename:join(SrcDir, "yecc_test_ok.yrl"),
+ run(Config, Cmd, FileName, "-W0", ["_OK_"]),
+ true = exists(filename:join(OutDir, "yecc_test_ok.erl")),
+
+ BadFile = filename:join(SrcDir, "yecc_test_bad.yrl"),
+ run(Config, Cmd, BadFile, "-W0",
+ ["rootsymbol form is not a nonterminal\$",
+ "undefined nonterminal: form\$",
+ "Nonterminals is missing\$",
+ "_ERROR_"]),
+ exists(filename:join(OutDir, "yecc_test_ok.erl")),
ok.
%% Test that compiling start scripts works.
compile_script(Config) when is_list(Config) ->
- ?line {SrcDir, OutDir, Cmd} = get_cmd(Config),
- ?line FileName = filename:join(SrcDir, "start_ok.script"),
- ?line run(Config, Cmd, FileName, "", ["_OK_"]),
- ?line true = exists(filename:join(OutDir, "start_ok.boot")),
+ {SrcDir, OutDir, Cmd} = get_cmd(Config),
+ FileName = filename:join(SrcDir, "start_ok.script"),
+ run(Config, Cmd, FileName, "", ["_OK_"]),
+ true = exists(filename:join(OutDir, "start_ok.boot")),
- ?line BadFile = filename:join(SrcDir, "start_bad.script"),
- ?line run(Config, Cmd, BadFile, "", ["syntax error before:", "_ERROR_"]),
+ BadFile = filename:join(SrcDir, "start_bad.script"),
+ run(Config, Cmd, BadFile, "", ["syntax error before:", "_ERROR_"]),
ok.
%% Test that compiling SNMP mibs works.
compile_mib(Config) when is_list(Config) ->
- ?line {SrcDir, OutDir, Cmd} = get_cmd(Config),
- ?line FileName = filename:join(SrcDir, "GOOD-MIB.mib"),
- ?line run(Config, Cmd, FileName, "", ["_OK_"]),
- ?line Output = filename:join(OutDir, "GOOD-MIB.bin"),
- ?line true = exists(Output),
+ {SrcDir, OutDir, Cmd} = get_cmd(Config),
+ FileName = filename:join(SrcDir, "GOOD-MIB.mib"),
+ run(Config, Cmd, FileName, "", ["_OK_"]),
+ Output = filename:join(OutDir, "GOOD-MIB.bin"),
+ true = exists(Output),
%% Try -W option.
- ?line ok = file:delete(Output),
- ?line run(Config, Cmd, FileName, "-W",
- ["_OK_"]),
- ?line true = exists(Output),
+ ok = file:delete(Output),
+ run(Config, Cmd, FileName, "-W",
+ ["_OK_"]),
+ true = exists(Output),
%% Try -W option and more verbose.
- ?line ok = file:delete(Output),
- ?line case test_server:os_type() of
- {unix,_} ->
- ?line run(Config, Cmd, FileName, "-W +'{verbosity,info}'",
- ["\\[GOOD-MIB[.]mib\\]\\[INF\\]: No accessfunction for 'sysDescr' => using default",
- "_OK_"]),
- ?line true = exists(Output),
- ?line ok = file:delete(Output);
- _ -> ok %Don't bother -- too much work.
- end,
+ ok = file:delete(Output),
+ case test_server:os_type() of
+ {unix,_} ->
+ run(Config, Cmd, FileName, "-W +'{verbosity,info}'",
+ ["\\[GOOD-MIB[.]mib\\]\\[INF\\]: No accessfunction for 'sysDescr' => using default",
+ "_OK_"]),
+ true = exists(Output),
+ ok = file:delete(Output);
+ _ -> ok %Don't bother -- too much work.
+ end,
%% Try a bad file.
- ?line BadFile = filename:join(SrcDir, "BAD-MIB.mib"),
- ?line run(Config, Cmd, BadFile, "",
- ["BAD-MIB.mib: 1: syntax error before: mibs\$",
- "compilation_failed_ERROR_"]),
+ BadFile = filename:join(SrcDir, "BAD-MIB.mib"),
+ run(Config, Cmd, BadFile, "",
+ ["BAD-MIB.mib: 1: syntax error before: mibs\$",
+ "compilation_failed_ERROR_"]),
%% Make sure that no -I option works.
- ?line NewCmd = erlc() ++ " -o" ++ OutDir ++ " ",
- ?line run(Config, NewCmd, FileName, "", ["_OK_"]),
- ?line true = exists(Output),
+ NewCmd = erlc() ++ " -o" ++ OutDir ++ " ",
+ run(Config, NewCmd, FileName, "", ["_OK_"]),
+ true = exists(Output),
ok.
@@ -171,91 +167,91 @@ compile_mib(Config) when is_list(Config) ->
%% shell script with redirected input).
good_citizen(Config) when is_list(Config) ->
case os:type() of
- {unix, _} ->
- ?line PrivDir = ?config(priv_dir, Config),
- ?line Answer = filename:join(PrivDir, "answer"),
- ?line Script = filename:join(PrivDir, "test_script"),
- ?line Test = filename:join(PrivDir, "test.erl"),
- ?line S = ["#! /bin/sh\n", "erlc ", Test, "\n",
- "read reply\n", "echo $reply\n"],
- ?line ok = file:write_file(Script, S),
- ?line ok = file:write_file(Test, "-module(test).\n"),
- ?line Cmd = "echo y | sh " ++ Script ++ " > " ++ Answer,
- ?line os:cmd(Cmd),
- ?line {ok, Answer0} = file:read_file(Answer),
- ?line [$y|_] = binary_to_list(Answer0),
- ok;
- _ ->
- {skip, "Unix specific"}
+ {unix, _} ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ Answer = filename:join(PrivDir, "answer"),
+ Script = filename:join(PrivDir, "test_script"),
+ Test = filename:join(PrivDir, "test.erl"),
+ S = ["#! /bin/sh\n", "erlc ", Test, "\n",
+ "read reply\n", "echo $reply\n"],
+ ok = file:write_file(Script, S),
+ ok = file:write_file(Test, "-module(test).\n"),
+ Cmd = "echo y | sh " ++ Script ++ " > " ++ Answer,
+ os:cmd(Cmd),
+ {ok, Answer0} = file:read_file(Answer),
+ [$y|_] = binary_to_list(Answer0),
+ ok;
+ _ ->
+ {skip, "Unix specific"}
end.
%% Make sure that compiling an Erlang module deep down in
%% in a directory with more than 255 characters works.
deep_cwd(Config) when is_list(Config) ->
case os:type() of
- {unix, _} ->
- PrivDir = ?config(priv_dir, Config),
- deep_cwd_1(PrivDir);
- _ ->
- {skip, "Only a problem on Unix"}
+ {unix, _} ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ deep_cwd_1(PrivDir);
+ _ ->
+ {skip, "Only a problem on Unix"}
end.
deep_cwd_1(PrivDir) ->
- ?line DeepDir0 = filename:join(PrivDir, lists:duplicate(128, $a)),
- ?line DeepDir = filename:join(DeepDir0, lists:duplicate(128, $b)),
- ?line ok = file:make_dir(DeepDir0),
- ?line ok = file:make_dir(DeepDir),
- ?line ok = file:set_cwd(DeepDir),
- ?line ok = file:write_file("test.erl", "-module(test).\n\n"),
- ?line io:format("~s\n", [os:cmd("erlc test.erl")]),
- ?line true = filelib:is_file("test.beam"),
+ DeepDir0 = filename:join(PrivDir, lists:duplicate(128, $a)),
+ DeepDir = filename:join(DeepDir0, lists:duplicate(128, $b)),
+ ok = file:make_dir(DeepDir0),
+ ok = file:make_dir(DeepDir),
+ ok = file:set_cwd(DeepDir),
+ ok = file:write_file("test.erl", "-module(test).\n\n"),
+ io:format("~s\n", [os:cmd("erlc test.erl")]),
+ true = filelib:is_file("test.beam"),
ok.
%% Test that a large number of command line switches does not
%% overflow the argument buffer
arg_overflow(Config) when is_list(Config) ->
- ?line {SrcDir, _OutDir, Cmd} = get_cmd(Config),
- ?line FileName = filename:join(SrcDir, "erl_test_ok.erl"),
+ {SrcDir, _OutDir, Cmd} = get_cmd(Config),
+ FileName = filename:join(SrcDir, "erl_test_ok.erl"),
%% Each -D option will be expanded to three arguments when
%% invoking 'erl'.
- ?line NumDOptions = num_d_options(),
- ?line Args = lists:flatten([ ["-D", integer_to_list(N, 36), "=1 "] ||
- N <- lists:seq(1, NumDOptions) ]),
- ?line run(Config, Cmd, FileName, Args,
- ["Warning: function foo/0 is unused\$",
- "_OK_"]),
+ NumDOptions = num_d_options(),
+ Args = lists:flatten([ ["-D", integer_to_list(N, 36), "=1 "] ||
+ N <- lists:seq(1, NumDOptions) ]),
+ run(Config, Cmd, FileName, Args,
+ ["Warning: function foo/0 is unused\$",
+ "_OK_"]),
ok.
num_d_options() ->
case {os:type(),os:version()} of
- {{win32,_},_} ->
- %% The maximum size of a command line in the command
- %% shell on Windows is 8191 characters.
- %% Each -D option is expanded to "@dv NN 1", i.e.
- %% 8 characters. (Numbers up to 1295 can be expressed
- %% as two 36-base digits.)
- 1000;
- {{unix,linux},Version} when Version < {2,6,23} ->
- %% On some older 64-bit versions of Linux, the maximum number
- %% of arguments is 16383.
- %% See: http://www.in-ulm.de/~mascheck/various/argmax/
- 5440;
- {{unix,darwin},{Major,_,_}} when Major >= 11 ->
- %% "getconf ARG_MAX" still reports 262144 (as in previous
- %% version of MacOS X), but the useful space seem to have
- %% shrunk significantly (or possibly the number of arguments).
- %% 7673
- 7500;
- {_,_} ->
- 12000
+ {{win32,_},_} ->
+ %% The maximum size of a command line in the command
+ %% shell on Windows is 8191 characters.
+ %% Each -D option is expanded to "@dv NN 1", i.e.
+ %% 8 characters. (Numbers up to 1295 can be expressed
+ %% as two 36-base digits.)
+ 1000;
+ {{unix,linux},Version} when Version < {2,6,23} ->
+ %% On some older 64-bit versions of Linux, the maximum number
+ %% of arguments is 16383.
+ %% See: http://www.in-ulm.de/~mascheck/various/argmax/
+ 5440;
+ {{unix,darwin},{Major,_,_}} when Major >= 11 ->
+ %% "getconf ARG_MAX" still reports 262144 (as in previous
+ %% version of MacOS X), but the useful space seem to have
+ %% shrunk significantly (or possibly the number of arguments).
+ %% 7673
+ 7500;
+ {_,_} ->
+ 12000
end.
erlc() ->
case os:find_executable("erlc") of
- false ->
- test_server:fail("Can't find erlc");
- Erlc ->
- "\"" ++ Erlc ++ "\""
+ false ->
+ ct:fail("Can't find erlc");
+ Erlc ->
+ "\"" ++ Erlc ++ "\""
end.
make_dep_options(Config) ->
@@ -264,30 +260,30 @@ make_dep_options(Config) ->
DepRE = ["/erl_test_ok[.]beam: \\\\$",
- "/system_test/erlc_SUITE_data/src/erl_test_ok[.]erl \\\\$",
- "/system_test/erlc_SUITE_data/include/erl_test[.]hrl$",
- "_OK_"],
+ "/system_test/erlc_SUITE_data/src/erl_test_ok[.]erl \\\\$",
+ "/system_test/erlc_SUITE_data/include/erl_test[.]hrl$",
+ "_OK_"],
DepRETarget =
- ["^target: \\\\$",
- "/system_test/erlc_SUITE_data/src/erl_test_ok[.]erl \\\\$",
- "/system_test/erlc_SUITE_data/include/erl_test[.]hrl$",
- "_OK_"],
+ ["^target: \\\\$",
+ "/system_test/erlc_SUITE_data/src/erl_test_ok[.]erl \\\\$",
+ "/system_test/erlc_SUITE_data/include/erl_test[.]hrl$",
+ "_OK_"],
DepREMP =
- ["/erl_test_ok[.]beam: \\\\$",
- "/system_test/erlc_SUITE_data/src/erl_test_ok[.]erl \\\\$",
- "/system_test/erlc_SUITE_data/include/erl_test[.]hrl$",
- [],
- "/system_test/erlc_SUITE_data/include/erl_test.hrl:$",
- "_OK_"],
+ ["/erl_test_ok[.]beam: \\\\$",
+ "/system_test/erlc_SUITE_data/src/erl_test_ok[.]erl \\\\$",
+ "/system_test/erlc_SUITE_data/include/erl_test[.]hrl$",
+ [],
+ "/system_test/erlc_SUITE_data/include/erl_test.hrl:$",
+ "_OK_"],
DepREMissing =
- ["/erl_test_missing_header[.]beam: \\\\$",
- "/system_test/erlc_SUITE_data/src/erl_test_missing_header[.]erl \\\\$",
- "/system_test/erlc_SUITE_data/include/erl_test[.]hrl \\\\$",
- "missing.hrl$",
- "_OK_"],
+ ["/erl_test_missing_header[.]beam: \\\\$",
+ "/system_test/erlc_SUITE_data/src/erl_test_missing_header[.]erl \\\\$",
+ "/system_test/erlc_SUITE_data/include/erl_test[.]hrl \\\\$",
+ "missing.hrl$",
+ "_OK_"],
%% Test plain -M
run(Config, Cmd, FileName, "-M", DepRE),
@@ -309,7 +305,7 @@ make_dep_options(Config) ->
%% Test -MF File -MT Target
TargetDepFile = filename:join(OutDir, "target.deps"),
run(Config, Cmd, FileName, "-MF "++TargetDepFile++" -MT target",
- ["_OK_"]),
+ ["_OK_"]),
{ok,TargetBin} = file:read_file(TargetDepFile),
verify_result(binary_to_list(TargetBin)++["_OK_"], DepRETarget),
@@ -358,33 +354,33 @@ split([], Current, Lines) ->
match_messages([Msg|Rest1], [Regexp|Rest2]) ->
case re:run(Msg, Regexp, [{capture,none}, unicode]) of
- match ->
- ok;
- nomatch ->
- io:format("Not matching: ~s\n", [Msg]),
- io:format("Regexp : ~s\n", [Regexp]),
- test_server:fail(message_mismatch)
+ match ->
+ ok;
+ nomatch ->
+ io:format("Not matching: ~s\n", [Msg]),
+ io:format("Regexp : ~s\n", [Regexp]),
+ ct:fail(message_mismatch)
end,
match_messages(Rest1, Rest2);
match_messages([], [Expect|Rest]) ->
- test_server:fail({too_few_messages, [Expect|Rest]});
+ ct:fail({too_few_messages, [Expect|Rest]});
match_messages([Msg|Rest], []) ->
- test_server:fail({too_many_messages, [Msg|Rest]});
+ ct:fail({too_many_messages, [Msg|Rest]});
match_messages([], []) ->
ok.
get_cmd(Cfg) ->
- ?line {SrcDir, IncDir, OutDir} = get_dirs(Cfg),
- ?line Cmd = erlc() ++ " -I" ++ IncDir ++ " -o" ++ OutDir ++ " ",
+ {SrcDir, IncDir, OutDir} = get_dirs(Cfg),
+ Cmd = erlc() ++ " -I" ++ IncDir ++ " -o" ++ OutDir ++ " ",
{SrcDir, OutDir, Cmd}.
get_dirs(Cfg) ->
- ?line DataDir = ?config(data_dir, Cfg),
- ?line PrivDir = ?config(priv_dir, Cfg),
- ?line SrcDir = filename:join(DataDir, "src"),
- ?line IncDir = filename:join(DataDir, "include"),
+ DataDir = proplists:get_value(data_dir, Cfg),
+ PrivDir = proplists:get_value(priv_dir, Cfg),
+ SrcDir = filename:join(DataDir, "src"),
+ IncDir = filename:join(DataDir, "include"),
{SrcDir, IncDir, PrivDir}.
-
+
exists(Name) ->
filelib:is_file(Name).
@@ -396,7 +392,7 @@ exists(Name) ->
%% a non-zero exit status.
run_command(Config, Cmd) ->
- TmpDir = filename:join(?config(priv_dir, Config), "tmp"),
+ TmpDir = filename:join(proplists:get_value(priv_dir, Config), "tmp"),
file:make_dir(TmpDir),
{RunFile, Run, Script} = run_command(TmpDir, os:type(), Cmd),
ok = file:write_file(filename:join(TmpDir, RunFile), unicode:characters_to_binary(Script)),
@@ -405,7 +401,7 @@ run_command(Config, Cmd) ->
run_command(Dir, {win32, _}, Cmd) ->
BatchFile = filename:join(Dir, "run.bat"),
Run = re:replace(filename:rootname(BatchFile), "/", "\\",
- [global,{return,list}]),
+ [global,{return,list}]),
{BatchFile,
Run,
["@echo off\r\n",
@@ -426,5 +422,4 @@ run_command(Dir, {unix, _}, Cmd) ->
" *) echo '_ERROR_';;\n",
"esac\n"]};
run_command(_Dir, Other, _Cmd) ->
- M = io_lib:format("Don't know how to test exit code for ~p", [Other]),
- test_server:fail(lists:flatten(M)).
+ ct:fail("Don't know how to test exit code for ~p", [Other]).
diff --git a/erts/test/erlc_SUITE_data/include/erl_test.hrl b/erts/test/erlc_SUITE_data/include/erl_test.hrl
index e7d096d2c1..70aecc4762 100644
--- a/erts/test/erlc_SUITE_data/include/erl_test.hrl
+++ b/erts/test/erlc_SUITE_data/include/erl_test.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/test/erlc_SUITE_data/src/erl_test_bad.erl b/erts/test/erlc_SUITE_data/src/erl_test_bad.erl
index b8c4ee2786..cbfe81705f 100644
--- a/erts/test/erlc_SUITE_data/src/erl_test_bad.erl
+++ b/erts/test/erlc_SUITE_data/src/erl_test_bad.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/test/erlc_SUITE_data/src/erl_test_missing_header.erl b/erts/test/erlc_SUITE_data/src/erl_test_missing_header.erl
index f043fbebc4..604bb16bd6 100644
--- a/erts/test/erlc_SUITE_data/src/erl_test_missing_header.erl
+++ b/erts/test/erlc_SUITE_data/src/erl_test_missing_header.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-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.
diff --git a/erts/test/erlc_SUITE_data/src/erl_test_ok.erl b/erts/test/erlc_SUITE_data/src/erl_test_ok.erl
index a82eda95b3..f1a48cbf18 100644
--- a/erts/test/erlc_SUITE_data/src/erl_test_ok.erl
+++ b/erts/test/erlc_SUITE_data/src/erl_test_ok.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/test/erlc_SUITE_data/src/yecc_test_bad.yrl b/erts/test/erlc_SUITE_data/src/yecc_test_bad.yrl
index de17b903d6..da488b7232 100644
--- a/erts/test/erlc_SUITE_data/src/yecc_test_bad.yrl
+++ b/erts/test/erlc_SUITE_data/src/yecc_test_bad.yrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/test/erlc_SUITE_data/src/yecc_test_ok.yrl b/erts/test/erlc_SUITE_data/src/yecc_test_ok.yrl
index 9433dcb90d..feb067e34b 100644
--- a/erts/test/erlc_SUITE_data/src/yecc_test_ok.yrl
+++ b/erts/test/erlc_SUITE_data/src/yecc_test_ok.yrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-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.
diff --git a/erts/test/erlexec_SUITE.erl b/erts/test/erlexec_SUITE.erl
index 6440cbf0d7..44d7f63387 100644
--- a/erts/test/erlexec_SUITE.erl
+++ b/erts/test/erlexec_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-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.
@@ -27,71 +27,46 @@
%%%-------------------------------------------------------------------
-module(erlexec_SUITE).
+-export([all/0, suite/0, init_per_testcase/2, end_per_testcase/2]).
-%-define(line_trace, 1).
-
--define(DEFAULT_TIMEOUT, ?t:minutes(1)).
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- init_per_testcase/2, end_per_testcase/2]).
-
--export([args_file/1, evil_args_file/1, env/1, args_file_env/1, otp_7461/1, otp_7461_remote/1, otp_8209/1, zdbbl_dist_buf_busy_limit/1]).
+-export([args_file/1, evil_args_file/1, env/1, args_file_env/1,
+ otp_7461/1, otp_7461_remote/1, otp_8209/1,
+ zdbbl_dist_buf_busy_limit/1]).
-include_lib("common_test/include/ct.hrl").
-
init_per_testcase(Case, Config) ->
- Dog = ?t:timetrap(?DEFAULT_TIMEOUT),
SavedEnv = save_env(),
- [{testcase, Case}, {watchdog, Dog}, {erl_flags_env, SavedEnv} |Config].
+ [{testcase, Case},{erl_flags_env, SavedEnv}|Config].
end_per_testcase(_Case, Config) ->
- Dog = ?config(watchdog, Config),
- SavedEnv = ?config(erl_flags_env, Config),
+ SavedEnv = proplists:get_value(erl_flags_env, Config),
restore_env(SavedEnv),
cleanup_nodes(),
- ?t:timetrap_cancel(Dog),
ok.
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap, {minutes, 1}}].
all() ->
[args_file, evil_args_file, env, args_file_env,
otp_7461, otp_8209, zdbbl_dist_buf_busy_limit].
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-otp_8209(doc) ->
- ["Test that plain first argument does not "
- "destroy -home switch [OTP-8209]"];
-otp_8209(suite) ->
- [];
+%% Test that plain first argument does not
+%% destroy -home switch [OTP-8209]
otp_8209(Config) when is_list(Config) ->
- ?line {ok,[[PName]]} = init:get_argument(progname),
- ?line SNameS = "erlexec_test_01",
- ?line SName = list_to_atom(SNameS++"@"++
+ {ok,[[PName]]} = init:get_argument(progname),
+ SNameS = "erlexec_test_01",
+ SName = list_to_atom(SNameS++"@"++
hd(tl(string:tokens(atom_to_list(node()),"@")))),
- ?line Cmd = PName ++ " dummy_param -sname "++SNameS++" -setcookie "++
+ Cmd = PName ++ " dummy_param -sname "++SNameS++" -setcookie "++
atom_to_list(erlang:get_cookie()),
- ?line open_port({spawn,Cmd},[]),
- ?line pong = loop_ping(SName,40),
- ?line {ok,[[_]]} = rpc:call(SName,init,get_argument,[home]),
- ?line ["dummy_param"] = rpc:call(SName,init,get_plain_arguments,[]),
- ?line ok = cleanup_nodes(),
+ open_port({spawn,Cmd},[]),
+ pong = loop_ping(SName,40),
+ {ok,[[_]]} = rpc:call(SName,init,get_argument,[home]),
+ ["dummy_param"] = rpc:call(SName,init,get_plain_arguments,[]),
+ ok = cleanup_nodes(),
ok.
cleanup_nodes() ->
@@ -123,17 +98,14 @@ loop_ping(Node,N) ->
pong
end.
-args_file(doc) -> [];
-args_file(suite) -> [];
args_file(Config) when is_list(Config) ->
- ?line AFN1 = privfile("1", Config),
- ?line AFN2 = privfile("2", Config),
- ?line AFN3 = privfile("3", Config),
- ?line AFN4 = privfile("4", Config),
- ?line AFN5 = privfile("5", Config),
- ?line AFN6 = privfile("6", Config),
- ?line write_file(AFN1,
- "-MiscArg2~n"
+ AFN1 = privfile("1", Config),
+ AFN2 = privfile("2", Config),
+ AFN3 = privfile("3", Config),
+ AFN4 = privfile("4", Config),
+ AFN5 = privfile("5", Config),
+ AFN6 = privfile("6", Config),
+ write_file(AFN1, "-MiscArg2~n"
"# a comment +\\#1000~n"
"+\\#200 # another comment~n"
"~n"
@@ -145,7 +117,7 @@ args_file(Config) when is_list(Config) ->
"+\\#700~n"
"-extra +XtraArg6~n",
[AFN2]),
- ?line write_file(AFN2,
+ write_file(AFN2,
"-MiscArg3~n"
"+\\#300~n"
"-args_file ~s~n"
@@ -156,61 +128,59 @@ args_file(Config) when is_list(Config) ->
"-args_file ~s~n"
"-extra +XtraArg5~n",
[AFN3, AFN4, AFN5, AFN6]),
- ?line write_file(AFN3,
+ write_file(AFN3,
"# comment again~n"
" -MiscArg4 +\\#400 -extra +XtraArg1"),
- ?line write_file(AFN4,
+ write_file(AFN4,
" -MiscArg6 +\\#600 -extra +XtraArg2~n"
"+XtraArg3~n"
"+XtraArg4~n"
"# comment again~n"),
- ?line write_file(AFN5, ""),
- ?line write_file(AFN6, "-extra # +XtraArg10~n"),
- ?line CmdLine = "+#100 -MiscArg1 "
+ write_file(AFN5, ""),
+ write_file(AFN6, "-extra # +XtraArg10~n"),
+ CmdLine = "+#100 -MiscArg1 "
++ "-args_file " ++ AFN1
++ " +#800 -MiscArg8 -extra +XtraArg7 +XtraArg8",
- ?line {Emu, Misc, Extra} = emu_args(CmdLine),
- ?line verify_args(["-#100", "-#200", "-#300", "-#400",
+ {Emu, Misc, Extra} = emu_args(CmdLine),
+ verify_args(["-#100", "-#200", "-#300", "-#400",
"-#500", "-#600", "-#700", "-#800"], Emu),
- ?line verify_args(["-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4",
+ verify_args(["-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4",
"-MiscArg5", "-MiscArg6", "-MiscArg7", "-MiscArg8"],
Misc),
- ?line verify_args(["+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4",
+ verify_args(["+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4",
"+XtraArg5", "+XtraArg6", "+XtraArg7", "+XtraArg8"],
Extra),
- ?line verify_not_args(["-MiscArg10", "-#1000", "+XtraArg10",
+ verify_not_args(["-MiscArg10", "-#1000", "+XtraArg10",
"-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4",
"-MiscArg5", "-MiscArg6", "-MiscArg7", "-MiscArg8",
"+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4",
"+XtraArg5", "+XtraArg6", "+XtraArg7", "+XtraArg8"],
Emu),
- ?line verify_not_args(["-MiscArg10", "-#1000", "+XtraArg10",
+ verify_not_args(["-MiscArg10", "-#1000", "+XtraArg10",
"-#100", "-#200", "-#300", "-#400",
"-#500", "-#600", "-#700", "-#800",
"+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4",
"+XtraArg5", "+XtraArg6", "+XtraArg7", "+XtraArg8"],
Misc),
- ?line verify_not_args(["-MiscArg10", "-#1000", "+XtraArg10",
+ verify_not_args(["-MiscArg10", "-#1000", "+XtraArg10",
"-#100", "-#200", "-#300", "-#400",
"-#500", "-#600", "-#700", "-#800",
"-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4",
"-MiscArg5", "-MiscArg6", "-MiscArg7", "-MiscArg8"],
Extra),
- ?line ok.
+ ok.
-evil_args_file(doc) -> [];
-evil_args_file(suite) -> [];
evil_args_file(Config) when is_list(Config) ->
- ?line Lim = 300,
- ?line FNums = lists:seq(1, Lim),
+ Lim = 300,
+ FNums = lists:seq(1, Lim),
lists:foreach(fun (End) when End == Lim ->
- ?line AFN = privfile(integer_to_list(End), Config),
- ?line write_file(AFN,
+ AFN = privfile(integer_to_list(End), Config),
+ write_file(AFN,
"-MiscArg~p ",
[End]);
(I) ->
- ?line AFNX = privfile(integer_to_list(I), Config),
- ?line AFNY = privfile(integer_to_list(I+1), Config),
+ AFNX = privfile(integer_to_list(I), Config),
+ AFNY = privfile(integer_to_list(I+1), Config),
{Frmt, Args} =
case I rem 2 of
0 ->
@@ -220,65 +190,59 @@ evil_args_file(Config) when is_list(Config) ->
{"-MiscArg~p -args_file ~s",
[I, AFNY]}
end,
- ?line write_file(AFNX, Frmt, Args)
+ write_file(AFNX, Frmt, Args)
end,
FNums),
- ?line {_Emu, Misc, _Extra} = emu_args("-args_file "
+ {_Emu, Misc, _Extra} = emu_args("-args_file "
++ privfile("1", Config)),
- ?line ANums = FNums
+ ANums = FNums
++ lists:reverse(lists:filter(fun (I) when I == Lim -> false;
(I) when I rem 2 == 0 -> true;
(_) -> false
end, FNums)),
- ?line verify_args(lists:map(fun (I) -> "-MiscArg"++integer_to_list(I) end,
+ verify_args(lists:map(fun (I) -> "-MiscArg"++integer_to_list(I) end,
ANums),
Misc),
- ?line ok.
+ ok.
-env(doc) -> [];
-env(suite) -> [];
env(Config) when is_list(Config) ->
- ?line os:putenv("ERL_AFLAGS", "-MiscArg1 +#100 -extra +XtraArg1 +XtraArg2"),
- ?line CmdLine = "+#200 -MiscArg2 -extra +XtraArg3 +XtraArg4",
- ?line os:putenv("ERL_FLAGS", "-MiscArg3 +#300 -extra +XtraArg5"),
- ?line os:putenv("ERL_ZFLAGS", "-MiscArg4 +#400 -extra +XtraArg6"),
- ?line {Emu, Misc, Extra} = emu_args(CmdLine),
- ?line verify_args(["-#100", "-#200", "-#300", "-#400"], Emu),
- ?line verify_args(["-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4"],
+ os:putenv("ERL_AFLAGS", "-MiscArg1 +#100 -extra +XtraArg1 +XtraArg2"),
+ CmdLine = "+#200 -MiscArg2 -extra +XtraArg3 +XtraArg4",
+ os:putenv("ERL_FLAGS", "-MiscArg3 +#300 -extra +XtraArg5"),
+ os:putenv("ERL_ZFLAGS", "-MiscArg4 +#400 -extra +XtraArg6"),
+ {Emu, Misc, Extra} = emu_args(CmdLine),
+ verify_args(["-#100", "-#200", "-#300", "-#400"], Emu),
+ verify_args(["-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4"],
Misc),
- ?line verify_args(["+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4",
+ verify_args(["+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4",
"+XtraArg5", "+XtraArg6"],
Extra),
- ?line ok.
+ ok.
-args_file_env(doc) -> [];
-args_file_env(suite) -> [];
args_file_env(Config) when is_list(Config) ->
- ?line AFN1 = privfile("1", Config),
- ?line AFN2 = privfile("2", Config),
- ?line write_file(AFN1, "-MiscArg2 +\\#200 -extra +XtraArg1"),
- ?line write_file(AFN2, "-MiscArg3 +\\#400 -extra +XtraArg3"),
- ?line os:putenv("ERL_AFLAGS",
+ AFN1 = privfile("1", Config),
+ AFN2 = privfile("2", Config),
+ write_file(AFN1, "-MiscArg2 +\\#200 -extra +XtraArg1"),
+ write_file(AFN2, "-MiscArg3 +\\#400 -extra +XtraArg3"),
+ os:putenv("ERL_AFLAGS",
"-MiscArg1 +#100 -args_file "++AFN1++ " -extra +XtraArg2"),
- ?line CmdLine = "+#300 -args_file "++AFN2++" -MiscArg4 -extra +XtraArg4",
- ?line os:putenv("ERL_FLAGS", "-MiscArg5 +#500 -extra +XtraArg5"),
- ?line os:putenv("ERL_ZFLAGS", "-MiscArg6 +#600 -extra +XtraArg6"),
- ?line {Emu, Misc, Extra} = emu_args(CmdLine),
- ?line verify_args(["-#100", "-#200", "-#300", "-#400",
+ CmdLine = "+#300 -args_file "++AFN2++" -MiscArg4 -extra +XtraArg4",
+ os:putenv("ERL_FLAGS", "-MiscArg5 +#500 -extra +XtraArg5"),
+ os:putenv("ERL_ZFLAGS", "-MiscArg6 +#600 -extra +XtraArg6"),
+ {Emu, Misc, Extra} = emu_args(CmdLine),
+ verify_args(["-#100", "-#200", "-#300", "-#400",
"-#500", "-#600"], Emu),
- ?line verify_args(["-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4",
+ verify_args(["-MiscArg1", "-MiscArg2", "-MiscArg3", "-MiscArg4",
"-MiscArg5", "-MiscArg6"],
Misc),
- ?line verify_args(["+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4",
+ verify_args(["+XtraArg1", "+XtraArg2", "+XtraArg3", "+XtraArg4",
"+XtraArg5", "+XtraArg6"],
Extra),
- ?line ok.
+ ok.
%% Make sure "erl -detached" survives when parent process group gets killed
-otp_7461(doc) -> [];
-otp_7461(suite) -> [];
otp_7461(Config) when is_list(Config) ->
case os:type() of
{unix,_} ->
@@ -302,9 +266,9 @@ otp_7461(Config) when is_list(Config) ->
otp_7461_do(Config) ->
io:format("alive=~p node=~p\n",[is_alive(), node()]),
- TestProg = filename:join([?config(data_dir, Config), "erlexec_tests"]),
+ TestProg = filename:join([proplists:get_value(data_dir, Config), "erlexec_tests"]),
{ok, [[ErlProg]]} = init:get_argument(progname),
- ?line Cmd = TestProg ++ " " ++ ErlProg ++
+ Cmd = TestProg ++ " " ++ ErlProg ++
" -detached -sname " ++ get_nodename(otp_7461) ++
" -setcookie " ++ atom_to_list(erlang:get_cookie()) ++
" -pa " ++ filename:dirname(code:which(?MODULE)) ++
@@ -314,29 +278,31 @@ otp_7461_do(Config) ->
%% open_port fork+exec
io:format("spawn port prog ~p\n",[Cmd]),
- ?line Port = open_port({spawn, Cmd}, [eof]),
+ Port = open_port({spawn, Cmd}, [eof]),
io:format("Wait for node to connect...\n",[]),
- ?line {nodeup, Slave} = receive Msg -> Msg
+ {nodeup, Slave} = receive Msg -> Msg
after 20*1000 -> timeout end,
io:format("Node alive: ~p\n", [Slave]),
- ?line pong = net_adm:ping(Slave),
+ pong = net_adm:ping(Slave),
io:format("Ping ok towards ~p\n", [Slave]),
- ?line Port ! { self(), {command, "K"}}, % Kill child process group
- ?line {Port, {data, "K"}} = receive Msg2 -> Msg2 end,
- ?line port_close(Port),
+ Port ! { self(), {command, "K"}}, % Kill child process group
+ {Port, {data, "K"}} = receive Msg2 -> Msg2 end,
+ port_close(Port),
%% Now the actual test. Detached node should still be alive.
- ?line pong = net_adm:ping(Slave),
+ pong = net_adm:ping(Slave),
io:format("Ping still ok towards ~p\n", [Slave]),
%% Halt node
- ?line rpc:cast(Slave, ?MODULE, otp_7461_remote, [[halt, self()]]),
+ rpc:cast(Slave, ?MODULE, otp_7461_remote, [[halt, self()]]),
- ?line {nodedown, Slave} = receive Msg3 -> Msg3
- after 20*1000 -> timeout end,
+ {nodedown, Slave} = receive
+ Msg3 -> Msg3
+ after 20*1000 -> timeout
+ end,
io:format("Node dead: ~p\n", [Slave]),
ok.
@@ -349,24 +315,21 @@ otp_7461_remote([halt, Pid]) ->
io:format("halt order from ~p to node ~p\n",[Pid,node()]),
halt().
-zdbbl_dist_buf_busy_limit(doc) ->
- ["Check +zdbbl flag"];
-zdbbl_dist_buf_busy_limit(suite) ->
- [];
+%% Check +zdbbl flag
zdbbl_dist_buf_busy_limit(Config) when is_list(Config) ->
LimKB = 1122233,
LimB = LimKB*1024,
- ?line {ok,[[PName]]} = init:get_argument(progname),
- ?line SNameS = "erlexec_test_02",
- ?line SName = list_to_atom(SNameS++"@"++
+ {ok,[[PName]]} = init:get_argument(progname),
+ SNameS = "erlexec_test_02",
+ SName = list_to_atom(SNameS++"@"++
hd(tl(string:tokens(atom_to_list(node()),"@")))),
- ?line Cmd = PName ++ " -sname "++SNameS++" -setcookie "++
+ Cmd = PName ++ " -sname "++SNameS++" -setcookie "++
atom_to_list(erlang:get_cookie()) ++
" +zdbbl " ++ integer_to_list(LimKB),
- ?line open_port({spawn,Cmd},[]),
- ?line pong = loop_ping(SName,40),
- ?line LimB = rpc:call(SName,erlang,system_info,[dist_buf_busy_limit]),
- ?line ok = cleanup_node(SNameS, 10),
+ open_port({spawn,Cmd},[]),
+ pong = loop_ping(SName,40),
+ LimB = rpc:call(SName,erlang,system_info,[dist_buf_busy_limit]),
+ ok = cleanup_node(SNameS, 10),
ok.
@@ -404,8 +367,8 @@ restore_env({erl_flags, AFlgs, Flgs, RFlgs, ZFlgs}) ->
ok.
privfile(Name, Config) ->
- filename:join([?config(priv_dir, Config),
- atom_to_list(?config(testcase, Config)) ++ "." ++ Name]).
+ filename:join([proplists:get_value(priv_dir, Config),
+ atom_to_list(proplists:get_value(testcase, Config)) ++ "." ++ Name]).
write_file(FileName, Frmt) ->
write_file(FileName, Frmt, []).
@@ -430,8 +393,7 @@ verify_not_args(Xs, Ys) ->
true -> exit({arg_present, X});
false -> ok
end
- end,
- Xs).
+ end, Xs).
emu_args(CmdLineArgs) ->
io:format("CmdLineArgs = ~ts~n", [CmdLineArgs]),
diff --git a/erts/test/erlexec_SUITE_data/Makefile.src b/erts/test/erlexec_SUITE_data/Makefile.src
index 145aaedd64..641dff1e30 100644
--- a/erts/test/erlexec_SUITE_data/Makefile.src
+++ b/erts/test/erlexec_SUITE_data/Makefile.src
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2008-2012. All Rights Reserved.
+# Copyright Ericsson AB 2008-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.
diff --git a/erts/test/erlexec_SUITE_data/erlexec_tests.c b/erts/test/erlexec_SUITE_data/erlexec_tests.c
index 569bf7bcc4..bd28d2900c 100644
--- a/erts/test/erlexec_SUITE_data/erlexec_tests.c
+++ b/erts/test/erlexec_SUITE_data/erlexec_tests.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2010. All Rights Reserved.
+ * Copyright Ericsson AB 2008-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.
diff --git a/erts/test/ethread_SUITE.erl b/erts/test/ethread_SUITE.erl
index 8ad2a32278..19f738c572 100644
--- a/erts/test/ethread_SUITE.erl
+++ b/erts/test/ethread_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2004-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.
@@ -28,13 +28,7 @@
-module(ethread_SUITE).
-author('[email protected]').
-%-define(line_trace, 1).
-
--define(DEFAULT_TIMEOUT, ?t:minutes(10)).
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- init_per_testcase/2, end_per_testcase/2]).
+-export([all/0, suite/0, init_per_testcase/2, end_per_testcase/2]).
-export([create_join_thread/1,
equal_tids/1,
@@ -53,7 +47,11 @@
-include_lib("common_test/include/ct.hrl").
-tests() ->
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap, {minutes, 10}}].
+
+all() ->
[create_join_thread,
equal_tids,
mutex,
@@ -69,78 +67,50 @@ tests() ->
atomic,
dw_atomic_massage].
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- tests().
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
+init_per_testcase(Case, Config) ->
+ case inet:gethostname() of
+ {ok,"fenris"} when Case == max_threads ->
+ %% Cannot use os:type+os:version as not all
+ %% solaris10 machines are buggy.
+ {skip, "This machine is buggy"};
+ _Else ->
+ Config
+ end.
-end_per_suite(_Config) ->
+end_per_testcase(_Case, _Config) ->
ok.
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
%%
%%
%% The test-cases
%%
%%
-create_join_thread(doc) ->
- ["Tests ethr_thr_create and ethr_thr_join."];
-create_join_thread(suite) ->
- [];
+%% Tests ethr_thr_create and ethr_thr_join.
create_join_thread(Config) ->
run_case(Config, "create_join_thread", "").
-equal_tids(doc) ->
- ["Tests ethr_equal_tids."];
-equal_tids(suite) ->
- [];
+%% Tests ethr_equal_tids.
equal_tids(Config) ->
run_case(Config, "equal_tids", "").
-mutex(doc) ->
- ["Tests mutexes."];
-mutex(suite) ->
- [];
+%% Tests mutexes.
mutex(Config) ->
run_case(Config, "mutex", "").
-try_lock_mutex(doc) ->
- ["Tests try lock on mutex."];
-try_lock_mutex(suite) ->
- [];
+%% Tests try lock on mutex.
try_lock_mutex(Config) ->
run_case(Config, "try_lock_mutex", "").
-cond_wait(doc) ->
- ["Tests ethr_cond_wait with ethr_cond_signal and ethr_cond_broadcast."];
-cond_wait(suite) ->
- [];
+%% Tests ethr_cond_wait with ethr_cond_signal and ethr_cond_broadcast.
cond_wait(Config) ->
run_case(Config, "cond_wait", "").
-broadcast(doc) ->
- ["Tests that a ethr_cond_broadcast really wakes up all waiting threads"];
-broadcast(suite) ->
- [];
+%% Tests that a ethr_cond_broadcast really wakes up all waiting threads
broadcast(Config) ->
run_case(Config, "broadcast", "").
-detached_thread(doc) ->
- ["Tests detached threads."];
-detached_thread(suite) ->
- [];
+%% Tests detached threads.
detached_thread(Config) ->
case {os:type(), os:version()} of
{{unix,darwin}, {9, _, _}} ->
@@ -152,10 +122,7 @@ detached_thread(Config) ->
run_case(Config, "detached_thread", "")
end.
-max_threads(doc) ->
- ["Tests maximum number of threads."];
-max_threads(suite) ->
- [];
+%% Tests maximum number of threads.
max_threads(Config) ->
case {os:type(), os:version()} of
{{unix,darwin}, {9, _, _}} ->
@@ -167,45 +134,27 @@ max_threads(Config) ->
run_case(Config, "max_threads", "")
end.
-tsd(doc) ->
- ["Tests thread specific data."];
-tsd(suite) ->
- [];
+%% Tests thread specific data.
tsd(Config) ->
run_case(Config, "tsd", "").
-spinlock(doc) ->
- ["Tests spinlocks."];
-spinlock(suite) ->
- [];
+%% Tests spinlocks.
spinlock(Config) ->
run_case(Config, "spinlock", "").
-rwspinlock(doc) ->
- ["Tests rwspinlocks."];
-rwspinlock(suite) ->
- [];
+%% Tests rwspinlocks.
rwspinlock(Config) ->
run_case(Config, "rwspinlock", "").
-rwmutex(doc) ->
- ["Tests rwmutexes."];
-rwmutex(suite) ->
- [];
+%% Tests rwmutexes.
rwmutex(Config) ->
run_case(Config, "rwmutex", "").
-atomic(doc) ->
- ["Tests atomics."];
-atomic(suite) ->
- [];
+%% Tests atomics.
atomic(Config) ->
run_case(Config, "atomic", "").
-dw_atomic_massage(doc) ->
- ["Massage double word atomics"];
-dw_atomic_massage(suite) ->
- [];
+%% Massage double word atomics
dw_atomic_massage(Config) ->
run_case(Config, "dw_atomic_massage", "").
@@ -215,22 +164,6 @@ dw_atomic_massage(Config) ->
%%
%%
-init_per_testcase(Case, Config) ->
- case inet:gethostname() of
- {ok,"fenris"} when Case == max_threads ->
- %% Cannot use os:type+os:version as not all
- %% solaris10 machines are buggy.
- {skip, "This machine is buggy"};
- _Else ->
- Dog = ?t:timetrap(?DEFAULT_TIMEOUT),
- [{watchdog, Dog}|Config]
- end.
-
-end_per_testcase(_Case, Config) ->
- Dog = ?config(watchdog, Config),
- ?t:timetrap_cancel(Dog),
- ok.
-
-define(TESTPROG, "ethread_tests").
-define(FAILED_MARKER, $E,$T,$H,$R,$-,$T,$E,$S,$T,$-,$F,$A,$I,$L,$U,$R,$E).
-define(SKIPPED_MARKER, $E,$T,$H,$R,$-,$T,$E,$S,$T,$-,$S,$K,$I,$P).
@@ -238,68 +171,68 @@ end_per_testcase(_Case, Config) ->
-define(PID_MARKER, $E,$T,$H,$R,$-,$T,$E,$S,$T,$-,$P,$I,$D).
port_prog_killer(EProc, OSProc) when is_pid(EProc), is_list(OSProc) ->
- ?line process_flag(trap_exit, true),
- ?line Ref = erlang:monitor(process, EProc),
- ?line receive
- {'DOWN', Ref, _, _, Reason} when is_tuple(Reason),
- element(1, Reason)
- == timetrap_timeout ->
- ?line Cmd = "kill -9 " ++ OSProc,
- ?line ?t:format("Test case timed out. "
- "Trying to kill port program.~n"
- " Executing: ~p~n", [Cmd]),
- ?line case os:cmd(Cmd) of
- [] ->
- ok;
- OsCmdRes ->
- ?line ?t:format(" ~s", [OsCmdRes])
- end;
- {'DOWN', Ref, _, _, _} ->
- %% OSProc is assumed to have terminated by itself
- ?line ok
- end.
+ process_flag(trap_exit, true),
+ Ref = erlang:monitor(process, EProc),
+ receive
+ {'DOWN', Ref, _, _, Reason} when is_tuple(Reason),
+ element(1, Reason)
+ == timetrap_timeout ->
+ Cmd = "kill -9 " ++ OSProc,
+ io:format("Test case timed out. "
+ "Trying to kill port program.~n"
+ " Executing: ~p~n", [Cmd]),
+ case os:cmd(Cmd) of
+ [] ->
+ ok;
+ OsCmdRes ->
+ io:format(" ~s", [OsCmdRes])
+ end;
+ %% OSProc is assumed to have terminated by itself
+ {'DOWN', Ref, _, _, _} ->
+ ok
+ end.
get_line(_Port, eol, Data) ->
- ?line Data;
+ Data;
get_line(Port, noeol, Data) ->
- ?line receive
+ receive
{Port, {data, {Flag, NextData}}} ->
- ?line get_line(Port, Flag, Data ++ NextData);
+ get_line(Port, Flag, Data ++ NextData);
{Port, eof} ->
- ?line ?t:fail(port_prog_unexpectedly_closed)
+ ct:fail(port_prog_unexpectedly_closed)
end.
read_case_data(Port, TestCase) ->
- ?line receive
- {Port, {data, {eol, [?SUCCESS_MARKER]}}} ->
- ?line ok;
- {Port, {data, {Flag, [?SUCCESS_MARKER | CommentStart]}}} ->
- ?line {comment, get_line(Port, Flag, CommentStart)};
- {Port, {data, {Flag, [?SKIPPED_MARKER | CommentStart]}}} ->
- ?line {skipped, get_line(Port, Flag, CommentStart)};
- {Port, {data, {Flag, [?FAILED_MARKER | ReasonStart]}}} ->
- ?line ?t:fail(get_line(Port, Flag, ReasonStart));
- {Port, {data, {eol, [?PID_MARKER | PidStr]}}} ->
- ?line ?t:format("Port program pid: ~s~n", [PidStr]),
- ?line CaseProc = self(),
- ?line _ = list_to_integer(PidStr), % Sanity check
- spawn_opt(fun () ->
- port_prog_killer(CaseProc, PidStr)
- end,
- [{priority, max}, link]),
- read_case_data(Port, TestCase);
- {Port, {data, {Flag, LineStart}}} ->
- ?line ?t:format("~s~n", [get_line(Port, Flag, LineStart)]),
- read_case_data(Port, TestCase);
- {Port, eof} ->
- ?line ?t:fail(port_prog_unexpectedly_closed)
- end.
+ receive
+ {Port, {data, {eol, [?SUCCESS_MARKER]}}} ->
+ ok;
+ {Port, {data, {Flag, [?SUCCESS_MARKER | CommentStart]}}} ->
+ {comment, get_line(Port, Flag, CommentStart)};
+ {Port, {data, {Flag, [?SKIPPED_MARKER | CommentStart]}}} ->
+ {skipped, get_line(Port, Flag, CommentStart)};
+ {Port, {data, {Flag, [?FAILED_MARKER | ReasonStart]}}} ->
+ ct:fail(get_line(Port, Flag, ReasonStart));
+ {Port, {data, {eol, [?PID_MARKER | PidStr]}}} ->
+ io:format("Port program pid: ~s~n", [PidStr]),
+ CaseProc = self(),
+ _ = list_to_integer(PidStr), % Sanity check
+ spawn_opt(fun () ->
+ port_prog_killer(CaseProc, PidStr)
+ end,
+ [{priority, max}, link]),
+ read_case_data(Port, TestCase);
+ {Port, {data, {Flag, LineStart}}} ->
+ io:format("~s~n", [get_line(Port, Flag, LineStart)]),
+ read_case_data(Port, TestCase);
+ {Port, eof} ->
+ ct:fail(port_prog_unexpectedly_closed)
+ end.
run_case(Config, Test, TestArgs) ->
run_case(Config, Test, TestArgs, fun (_Port) -> ok end).
run_case(Config, Test, TestArgs, Fun) ->
- TestProg = filename:join([?config(data_dir, Config), ?TESTPROG]),
+ TestProg = filename:join([proplists:get_value(data_dir, Config), ?TESTPROG]),
Cmd = TestProg ++ " " ++ Test ++ " " ++ TestArgs,
case catch open_port({spawn, Cmd}, [stream,
use_stdio,
@@ -307,17 +240,13 @@ run_case(Config, Test, TestArgs, Fun) ->
eof,
{line, 1024}]) of
Port when is_port(Port) ->
- ?line Fun(Port),
- ?line CaseResult = read_case_data(Port, Test),
- ?line receive
- {Port, eof} ->
- ?line ok
- end,
- ?line CaseResult;
+ Fun(Port),
+ CaseResult = read_case_data(Port, Test),
+ receive
+ {Port, eof} ->
+ ok
+ end,
+ CaseResult;
Error ->
- ?line ?t:fail({open_port_failed, Error})
+ ct:fail({open_port_failed, Error})
end.
-
-
-
-
diff --git a/erts/test/ethread_SUITE_data/Makefile.src b/erts/test/ethread_SUITE_data/Makefile.src
index e8b9c79576..cf675b92a3 100644
--- a/erts/test/ethread_SUITE_data/Makefile.src
+++ b/erts/test/ethread_SUITE_data/Makefile.src
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2012. All Rights Reserved.
+# Copyright Ericsson AB 2004-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.
diff --git a/erts/test/ethread_SUITE_data/ethread_tests.c b/erts/test/ethread_SUITE_data/ethread_tests.c
index b51771c736..fe7f92b012 100644
--- a/erts/test/ethread_SUITE_data/ethread_tests.c
+++ b/erts/test/ethread_SUITE_data/ethread_tests.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2011. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/test/ignore_cores.erl b/erts/test/ignore_cores.erl
index e40b91392c..25dce346b9 100644
--- a/erts/test/ignore_cores.erl
+++ b/erts/test/ignore_cores.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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.
@@ -53,7 +53,7 @@ init(Config) ->
fini(Config) ->
#ignore_cores{org_cwd = OrgCWD,
org_path = OrgPath,
- org_pwd_env = OrgPWD} = ?config(ignore_cores, Config),
+ org_pwd_env = OrgPWD} = proplists:get_value(ignore_cores, Config),
ok = file:set_cwd(OrgCWD),
true = code:set_path(OrgPath),
case OrgPWD of
@@ -70,10 +70,10 @@ setup(Suite, Testcase, Config, SetCwd) when is_atom(Suite),
is_list(Config) ->
#ignore_cores{org_cwd = OrgCWD,
org_path = OrgPath,
- org_pwd_env = OrgPWD} = ?config(ignore_cores, Config),
+ org_pwd_env = OrgPWD} = proplists:get_value(ignore_cores, Config),
Path = lists:map(fun (".") -> OrgCWD; (Dir) -> Dir end, OrgPath),
true = code:set_path(Path),
- PrivDir = ?config(priv_dir, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
IgnDir = filename:join([PrivDir,
atom_to_list(Suite)
++ "_"
@@ -94,7 +94,7 @@ setup(Suite, Testcase, Config, SetCwd) when is_atom(Suite),
end,
ok = file:write_file(filename:join([IgnDir, "ignore_core_files"]), <<>>),
%% cores are dumped in /cores on MacOS X
- CoresDir = case {?t:os_type(), filelib:is_dir("/cores")} of
+ CoresDir = case {os:type(), filelib:is_dir("/cores")} of
{{unix,darwin}, true} ->
filelib:fold_files("/cores",
"^core.*$",
@@ -119,7 +119,7 @@ restore(Config) ->
org_path = OrgPath,
org_pwd_env = OrgPWD,
ign_dir = IgnDir,
- cores_dir = CoresDir} = ?config(ignore_cores, Config),
+ cores_dir = CoresDir} = proplists:get_value(ignore_cores, Config),
try
case CoresDir of
false ->
@@ -155,5 +155,5 @@ restore(Config) ->
dir(Config) ->
- #ignore_cores{ign_dir = Dir} = ?config(ignore_cores, Config),
+ #ignore_cores{ign_dir = Dir} = proplists:get_value(ignore_cores, Config),
Dir.
diff --git a/erts/test/install_SUITE.erl b/erts/test/install_SUITE.erl
index d6df1aab6b..2c7e8972f6 100644
--- a/erts/test/install_SUITE.erl
+++ b/erts/test/install_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2012. All Rights Reserved.
+%% 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.
@@ -28,11 +28,9 @@
%%%-------------------------------------------------------------------
-module(install_SUITE).
-%-define(line_trace, 1).
-
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
- init_per_suite/1, end_per_suite/1,
- init_per_testcase/2, end_per_testcase/2]).
+-export([all/0, suite/0,
+ init_per_suite/1, end_per_suite/1,
+ init_per_testcase/2, end_per_testcase/2]).
-export([bin_default/1,
bin_default_dirty/1,
@@ -49,7 +47,6 @@
bin_dirname_fail/1,
bin_no_use_dirname_fail/1]).
--define(DEFAULT_TIMEOUT, ?t:minutes(1)).
-define(JOIN(A,B,C), filename:join(A, B, C)).
-include_lib("common_test/include/ct.hrl").
@@ -77,49 +74,42 @@ dont_need_symlink_cases() ->
bin_unreasonable_path, 'bin white space',
bin_no_srcfile].
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap, {minutes, 1}}].
all() ->
dont_need_symlink_cases() ++ need_symlink_cases().
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
%%
%% The test cases
%%
bin_default(Config) when is_list(Config) ->
- ?line E = "/usr/local",
- ?line Bs = "/usr/local/bin",
- ?line Be = Bs,
- ?line EBs = "/usr/local/lib/erlang/bin",
- ?line EBe = EBs,
- ?line RP = "../lib/erlang/bin",
+ E = "/usr/local",
+ Bs = "/usr/local/bin",
+ Be = Bs,
+ EBs = "/usr/local/lib/erlang/bin",
+ EBe = EBs,
+ RP = "../lib/erlang/bin",
ChkRes = fun (Res, #inst{test_prefix = TP,
destdir = D,
extra_prefix = EP,
bindir_symlinks = BSL,
symlinks = SL}) ->
- ?line B = join([TP, D, EP, Be]),
+ B = join([TP, D, EP, Be]),
Expct = case {SL, BSL} of
{false, _} when BSL == "relative";
BSL == "absolute" ->
- ?line {error, no_ln_s};
+ {error, no_ln_s};
{false, _} ->
- ?line {ok,{absolute,
+ {ok,{absolute,
B,join([TP,D,EP,EBe])}};
{true, "absolute"} ->
- ?line {ok,{absolute,B,join([TP,EP,EBe])}};
+ {ok,{absolute,B,join([TP,EP,EBe])}};
{true, _} ->
- ?line {ok,{relative,B,RP}}
+ {ok,{relative,B,RP}}
end,
expect(Expct, Res)
end,
@@ -128,30 +118,30 @@ bin_default(Config) when is_list(Config) ->
erlang_bindir = EBs}, ChkRes).
bin_default_dirty(Config) when is_list(Config) ->
- ?line E = "/usr/./local/lib/..",
- ?line Bs = "/usr/local//lib/../lib/erlang/../../bin",
- ?line Be = "/usr/local/lib/../lib/erlang/../../bin",
- ?line EBs = "/usr/local/lib/../lib/erlang/../erlang/bin/x/y/../..//",
- ?line EBe = "/usr/local/lib/../lib/erlang/../erlang/bin/x/y/../..",
- ?line RP = "../lib/erlang/bin",
+ E = "/usr/./local/lib/..",
+ Bs = "/usr/local//lib/../lib/erlang/../../bin",
+ Be = "/usr/local/lib/../lib/erlang/../../bin",
+ EBs = "/usr/local/lib/../lib/erlang/../erlang/bin/x/y/../..//",
+ EBe = "/usr/local/lib/../lib/erlang/../erlang/bin/x/y/../..",
+ RP = "../lib/erlang/bin",
ChkRes = fun (Res, #inst{test_prefix = TP,
destdir = D,
extra_prefix = EP,
bindir_symlinks = BSL,
symlinks = SL}) ->
- ?line B = join([TP, D, EP, Be]),
+ B = join([TP, D, EP, Be]),
Expct = case {SL, BSL} of
{false, _} when BSL == "relative";
BSL == "absolute" ->
- ?line {error, no_ln_s};
+ {error, no_ln_s};
{false, _} ->
- ?line {ok,{absolute,
+ {ok,{absolute,
B,join([TP,D,EP,EBe])}};
{true, "absolute"} ->
- ?line {ok,{absolute,
+ {ok,{absolute,
B,join([TP,EP,EBe])}};
{true, _} ->
- ?line {ok,{relative,B,RP}}
+ {ok,{relative,B,RP}}
end,
expect(Expct, Res)
end,
@@ -161,29 +151,29 @@ bin_default_dirty(Config) when is_list(Config) ->
bin_outside_eprfx(Config) when is_list(Config) ->
- ?line E = "/usr/local",
- ?line Bs = "/usr/bin",
- ?line Be = Bs,
- ?line EBs = "/usr/local/lib/erlang/bin",
- ?line EBe = EBs,
- ?line RP = "../local/lib/erlang/bin",
+ E = "/usr/local",
+ Bs = "/usr/bin",
+ Be = Bs,
+ EBs = "/usr/local/lib/erlang/bin",
+ EBe = EBs,
+ RP = "../local/lib/erlang/bin",
ChkRes = fun (Res, #inst{test_prefix = TP,
destdir = D,
extra_prefix = EP,
bindir_symlinks = BSL,
symlinks = SL}) ->
- ?line B = join([TP, D, EP, Be]),
+ B = join([TP, D, EP, Be]),
Expct = case {SL, BSL} of
{false, _} when BSL == "relative";
BSL == "absolute" ->
- ?line {error, no_ln_s};
+ {error, no_ln_s};
{false, _} ->
- ?line {ok,{absolute,
+ {ok,{absolute,
B,join([TP,D,EP,EBe])}};
{true, "relative"} ->
- ?line {ok,{relative,B,RP}};
+ {ok,{relative,B,RP}};
{true, _} ->
- ?line {ok,{absolute,B,join([TP,EP,EBe])}}
+ {ok,{absolute,B,join([TP,EP,EBe])}}
end,
expect(Expct, Res)
end,
@@ -193,29 +183,29 @@ bin_outside_eprfx(Config) when is_list(Config) ->
bin_outside_eprfx_dirty(Config) when is_list(Config) ->
- ?line E = "/usr/local/lib/..",
- ?line Bs = "/usr/local/lib/../../bin",
- ?line Be = Bs,
- ?line EBs = "/usr/local/lib/erlang/bin",
- ?line EBe = EBs,
- ?line RP = "../local/lib/erlang/bin",
+ E = "/usr/local/lib/..",
+ Bs = "/usr/local/lib/../../bin",
+ Be = Bs,
+ EBs = "/usr/local/lib/erlang/bin",
+ EBe = EBs,
+ RP = "../local/lib/erlang/bin",
ChkRes = fun (Res, #inst{test_prefix = TP,
destdir = D,
extra_prefix = EP,
bindir_symlinks = BSL,
symlinks = SL}) ->
- ?line B = join([TP, D, EP, Be]),
+ B = join([TP, D, EP, Be]),
Expct = case {SL, BSL} of
{false, _} when BSL == "relative";
BSL == "absolute" ->
- ?line {error, no_ln_s};
+ {error, no_ln_s};
{false, _} ->
- ?line {ok,{absolute,
+ {ok,{absolute,
B,join([TP,D,EP,EBe])}};
{true, "relative"} ->
- ?line {ok,{relative,B,RP}};
+ {ok,{relative,B,RP}};
{true, _} ->
- ?line {ok,{absolute,B,join([TP,EP,EBe])}}
+ {ok,{absolute,B,join([TP,EP,EBe])}}
end,
expect(Expct, Res)
end,
@@ -224,33 +214,33 @@ bin_outside_eprfx_dirty(Config) when is_list(Config) ->
erlang_bindir = EBs}, ChkRes).
bin_unreasonable_path(Config) when is_list(Config) ->
- ?line E = "/usr/local/../../..",
- ?line Bs = "/usr/local/../../../bin",
- ?line Be = Bs,
- ?line EBs = "/usr/local/../../../bin_unreasonable_path/usr/local/lib/erlang/bin",
- ?line EBe = EBs,
- ?line RP = "../bin_unreasonable_path/usr/local/lib/erlang/bin",
+ E = "/usr/local/../../..",
+ Bs = "/usr/local/../../../bin",
+ Be = Bs,
+ EBs = "/usr/local/../../../bin_unreasonable_path/usr/local/lib/erlang/bin",
+ EBe = EBs,
+ RP = "../bin_unreasonable_path/usr/local/lib/erlang/bin",
ChkRes = fun (Res, #inst{test_prefix = TP,
destdir = D,
extra_prefix = EP,
bindir_symlinks = BSL,
symlinks = SL}) ->
- ?line B = join([TP, D, EP, Be]),
+ B = join([TP, D, EP, Be]),
Expct = case {TP, SL, BSL} of
{_, false, _} when BSL == "relative";
BSL == "absolute" ->
- ?line {error, no_ln_s};
+ {error, no_ln_s};
{_, false, _} ->
- ?line {ok,{absolute,
+ {ok,{absolute,
B,join([TP,D,EP,EBe])}};
{"", true, "relative"} ->
{error, unreasonable_path};
{"", true, _} ->
- ?line {ok,{absolute,B,join([TP,EP,EBe])}};
+ {ok,{absolute,B,join([TP,EP,EBe])}};
{_, true, "absolute"} ->
- ?line {ok,{absolute,B,join([TP,EP,EBe])}};
+ {ok,{absolute,B,join([TP,EP,EBe])}};
_ ->
- ?line {ok,{relative,B,RP}}
+ {ok,{relative,B,RP}}
end,
expect(Expct, Res)
end,
@@ -259,7 +249,7 @@ bin_unreasonable_path(Config) when is_list(Config) ->
erlang_bindir = EBs}, ChkRes).
bin_unreachable_absolute(Config) when is_list(Config) ->
- TDir = ?config(test_dir, Config),
+ TDir = proplists:get_value(test_dir, Config),
make_dirs(TDir, "/opt/local/lib/erlang/usr/bin"),
make_dirs(TDir, "/opt/local/lib/erlang/bin"),
Erl = join([TDir, "/opt/local/lib/erlang/bin/erl"]),
@@ -270,28 +260,28 @@ bin_unreachable_absolute(Config) when is_list(Config) ->
ok = file:write_file(Erlc, "erlc"),
ok = file:make_symlink("../../../opt/local/lib/erlang/usr",
join([TDir, "/usr/local/lib/erlang"])),
- ?line E = "/usr/local",
- ?line Bs = "/usr/local/bin",
- ?line Be = Bs,
- ?line EBs = "/usr/local/lib/erlang/../bin",
- ?line EBe = EBs,
+ E = "/usr/local",
+ Bs = "/usr/local/bin",
+ Be = Bs,
+ EBs = "/usr/local/lib/erlang/../bin",
+ EBe = EBs,
ChkRes = fun (Res, #inst{test_prefix = TP,
destdir = D,
extra_prefix = EP,
bindir_symlinks = BSL,
symlinks = SL}) ->
- ?line B = join([TP, D, EP, Be]),
+ B = join([TP, D, EP, Be]),
Expct = case {SL, BSL} of
{false, _} when BSL == "relative";
BSL == "absolute" ->
- ?line {error, no_ln_s};
+ {error, no_ln_s};
{false, _} ->
- ?line {ok,{absolute,
+ {ok,{absolute,
B,join([TP,D,EP,EBe])}};
{true, "relative"} ->
{error, unreachable_absolute};
{true, _} ->
- ?line {ok,{absolute,B,join([TP,EP,EBe])}}
+ {ok,{absolute,B,join([TP,EP,EBe])}}
end,
expect(Expct, Res)
end,
@@ -300,7 +290,7 @@ bin_unreachable_absolute(Config) when is_list(Config) ->
erlang_bindir = EBs}, ChkRes).
bin_unreachable_relative(Config) when is_list(Config) ->
- TDir = ?config(test_dir, Config),
+ TDir = proplists:get_value(test_dir, Config),
make_dirs(TDir, "/opt/local/lib/erlang/bin"),
make_dirs(TDir, "/opt/local/bin"),
make_dirs(TDir, "/usr/local/lib/erlang/bin"),
@@ -311,28 +301,28 @@ bin_unreachable_relative(Config) when is_list(Config) ->
ok = file:make_symlink("../../opt/local/bin",
join([TDir, "/usr/local/bin"])),
- ?line E = "/usr/local",
- ?line Bs = "/usr/local/bin",
- ?line Be = Bs,
- ?line EBs = "/usr/local/lib/erlang/bin",
- ?line EBe = EBs,
+ E = "/usr/local",
+ Bs = "/usr/local/bin",
+ Be = Bs,
+ EBs = "/usr/local/lib/erlang/bin",
+ EBe = EBs,
ChkRes = fun (Res, #inst{test_prefix = TP,
destdir = D,
extra_prefix = EP,
bindir_symlinks = BSL,
symlinks = SL}) ->
- ?line B = join([TP, D, EP, Be]),
+ B = join([TP, D, EP, Be]),
Expct = case {SL, BSL} of
{false, _} when BSL == "relative";
BSL == "absolute" ->
- ?line {error, no_ln_s};
+ {error, no_ln_s};
{false, _} ->
- ?line {ok,{absolute,
+ {ok,{absolute,
B,join([TP,D,EP,EBe])}};
{true, "relative"} ->
{error, unreachable_relative};
{true, _} ->
- ?line {ok,{absolute,B,join([TP,EP,EBe])}}
+ {ok,{absolute,B,join([TP,EP,EBe])}}
end,
expect(Expct, Res)
end,
@@ -341,7 +331,7 @@ bin_unreachable_relative(Config) when is_list(Config) ->
erlang_bindir = EBs}, ChkRes).
bin_ok_symlink(Config) when is_list(Config) ->
- TDir = ?config(test_dir, Config),
+ TDir = proplists:get_value(test_dir, Config),
make_dirs(TDir, "/usr/local/bin"),
make_dirs(TDir, "/opt/local/lib/erlang/bin"),
Erl = join([TDir, "/opt/local/lib/erlang/bin/erl"]),
@@ -350,29 +340,29 @@ bin_ok_symlink(Config) when is_list(Config) ->
ok = file:write_file(Erlc, "erlc"),
ok = file:make_symlink("../../opt/local/lib",
join([TDir, "/usr/local/lib"])),
- ?line E = "/usr/local",
- ?line Bs = "/usr/local/bin",
- ?line Be = Bs,
- ?line EBs = "/usr/local/lib/erlang/bin",
- ?line EBe = EBs,
- ?line RP = "../lib/erlang/bin",
+ E = "/usr/local",
+ Bs = "/usr/local/bin",
+ Be = Bs,
+ EBs = "/usr/local/lib/erlang/bin",
+ EBe = EBs,
+ RP = "../lib/erlang/bin",
ChkRes = fun (Res, #inst{test_prefix = TP,
destdir = D,
extra_prefix = EP,
bindir_symlinks = BSL,
symlinks = SL}) ->
- ?line B = join([TP, D, EP, Be]),
+ B = join([TP, D, EP, Be]),
Expct = case {SL, BSL} of
{false, _} when BSL == "relative";
BSL == "absolute" ->
- ?line {error, no_ln_s};
+ {error, no_ln_s};
{false, _} ->
- ?line {ok,{absolute,
+ {ok,{absolute,
B,join([TP,D,EP,EBe])}};
{true, "absolute"} ->
- ?line {ok,{absolute,B,join([TP,EP,EBe])}};
+ {ok,{absolute,B,join([TP,EP,EBe])}};
{true, _} ->
- ?line {ok,{relative,B,RP}}
+ {ok,{relative,B,RP}}
end,
expect(Expct, Res)
end,
@@ -381,7 +371,7 @@ bin_ok_symlink(Config) when is_list(Config) ->
erlang_bindir = EBs}, ChkRes).
bin_same_dir(Config) when is_list(Config) ->
- TDir = ?config(test_dir, Config),
+ TDir = proplists:get_value(test_dir, Config),
make_dirs(TDir, "/usr/local/bin"),
make_dirs(TDir, "/usr/local/lib"),
ok = file:make_symlink("..", join([TDir, "/usr/local/lib/erlang"])),
@@ -417,29 +407,29 @@ bin_not_abs(Config) when is_list(Config) ->
'bin white space'(Config) when is_list(Config) ->
- ?line E = "/u s r/local",
- ?line Bs = "/u s r/local/b i n",
- ?line Be = Bs,
- ?line EBs = "/u s r/local/lib/erl ang/bin",
- ?line EBe = EBs,
- ?line RP = "../lib/erl ang/bin",
+ E = "/u s r/local",
+ Bs = "/u s r/local/b i n",
+ Be = Bs,
+ EBs = "/u s r/local/lib/erl ang/bin",
+ EBe = EBs,
+ RP = "../lib/erl ang/bin",
ChkRes = fun (Res, #inst{test_prefix = TP,
destdir = D,
extra_prefix = EP,
bindir_symlinks = BSL,
symlinks = SL}) ->
- ?line B = join([TP, D, EP, Be]),
+ B = join([TP, D, EP, Be]),
Expct = case {SL, BSL} of
{false, _} when BSL == "relative";
BSL == "absolute" ->
- ?line {error, no_ln_s};
+ {error, no_ln_s};
{false, _} ->
- ?line {ok,{absolute,
+ {ok,{absolute,
B,join([TP,D,EP,EBe])}};
{true, "absolute"} ->
- ?line {ok,{absolute,B,join([TP,EP,EBe])}};
+ {ok,{absolute,B,join([TP,EP,EBe])}};
{true, _} ->
- ?line {ok,{relative,B,RP}}
+ {ok,{relative,B,RP}}
end,
expect(Expct, Res)
end,
@@ -448,29 +438,29 @@ bin_not_abs(Config) when is_list(Config) ->
erlang_bindir = EBs}, ChkRes).
bin_dirname_fail(Config) when is_list(Config) ->
- ?line E = "/opt",
- ?line Bs = "/opt/lib/../bin",
- ?line Be = Bs,
- ?line EBs = "/opt/lib/erlang/otp/bin",
- ?line EBe = EBs,
- ?line CMDPRFX = "PATH=\""++?config(data_dir,Config)++":"++os:getenv("PATH")++"\"",
+ E = "/opt",
+ Bs = "/opt/lib/../bin",
+ Be = Bs,
+ EBs = "/opt/lib/erlang/otp/bin",
+ EBe = EBs,
+ CMDPRFX = "PATH=\""++proplists:get_value(data_dir,Config)++":"++os:getenv("PATH")++"\"",
ChkRes = fun (Res, #inst{test_prefix = TP,
destdir = D,
extra_prefix = EP,
bindir_symlinks = BSL,
symlinks = SL}) ->
- ?line B = join([TP, D, EP, Be]),
+ B = join([TP, D, EP, Be]),
Expct = case {SL, BSL} of
{false, _} when BSL == "relative";
BSL == "absolute" ->
- ?line {error, no_ln_s};
+ {error, no_ln_s};
{false, _} ->
- ?line {ok,{absolute,
+ {ok,{absolute,
B,join([TP,D,EP,EBe])}};
{true, "relative"} ->
- ?line {error, dirname_failed};
+ {error, dirname_failed};
{true, _} ->
- ?line {ok,{absolute,B,join([TP,EP,EBe])}}
+ {ok,{absolute,B,join([TP,EP,EBe])}}
end,
expect(Expct, Res)
end,
@@ -480,30 +470,30 @@ bin_dirname_fail(Config) when is_list(Config) ->
erlang_bindir = EBs}, ChkRes).
bin_no_use_dirname_fail(Config) when is_list(Config) ->
- ?line E = "/opt",
- ?line Bs = "/opt/bin",
- ?line Be = Bs,
- ?line EBs = "/opt/lib/erlang/otp/bin",
- ?line EBe = EBs,
- ?line RP = "../lib/erlang/otp/bin",
- ?line CMDPRFX = "PATH=\""++?config(data_dir,Config)++":"++os:getenv("PATH")++"\"",
+ E = "/opt",
+ Bs = "/opt/bin",
+ Be = Bs,
+ EBs = "/opt/lib/erlang/otp/bin",
+ EBe = EBs,
+ RP = "../lib/erlang/otp/bin",
+ CMDPRFX = "PATH=\""++proplists:get_value(data_dir,Config)++":"++os:getenv("PATH")++"\"",
ChkRes = fun (Res, #inst{test_prefix = TP,
destdir = D,
extra_prefix = EP,
bindir_symlinks = BSL,
symlinks = SL}) ->
- ?line B = join([TP, D, EP, Be]),
+ B = join([TP, D, EP, Be]),
Expct = case {SL, BSL} of
{false, _} when BSL == "relative";
BSL == "absolute" ->
- ?line {error, no_ln_s};
+ {error, no_ln_s};
{false, _} ->
- ?line {ok,{absolute,
+ {ok,{absolute,
B,join([TP,D,EP,EBe])}};
{true, "absolute"} ->
- ?line {ok,{absolute,B,join([TP,EP,EBe])}};
+ {ok,{absolute,B,join([TP,EP,EBe])}};
{true, _} ->
- ?line {ok,{relative,B,RP}}
+ {ok,{relative,B,RP}}
end,
expect(Expct, Res)
end,
@@ -513,7 +503,7 @@ bin_no_use_dirname_fail(Config) when is_list(Config) ->
erlang_bindir = EBs}, ChkRes).
bin_no_srcfile(Config) when is_list(Config) ->
- TDir = ?config(test_dir, Config),
+ TDir = proplists:get_value(test_dir, Config),
make_dirs(TDir, "/opt/local/bin"),
make_dirs(TDir, "/opt/local/lib/erlang/bin"),
Erl = join([TDir, "/opt/local/lib/erlang/bin/erl"]),
@@ -525,13 +515,13 @@ bin_no_srcfile(Config) when is_list(Config) ->
Expct = case {SL, BSL} of
{false, _} when BSL == "relative";
BSL == "absolute" ->
- ?line {error, no_ln_s};
+ {error, no_ln_s};
{false,_} ->
- ?line {error,{no_srcfile, Erlc}};
+ {error,{no_srcfile, Erlc}};
{true, "absolute"} ->
- ?line {error,{no_srcfile, Erlc}};
+ {error,{no_srcfile, Erlc}};
{true, _} ->
- ?line {error,{no_srcfile, RP_Erlc}}
+ {error,{no_srcfile, RP_Erlc}}
end,
expect(Expct, Res)
end,
@@ -549,34 +539,34 @@ bin_no_srcfile(Config) when is_list(Config) ->
%%
expect(X, X) ->
- ?t:format("result: ~p~n", [X]),
- ?t:format("-----------------------------------------------~n", []),
+ io:format("result: ~p~n", [X]),
+ io:format("-----------------------------------------------~n", []),
ok;
expect(X, Y) ->
- ?t:format("expected: ~p~n", [X]),
- ?t:format("got : ~p~n", [Y]),
- ?t:format("-----------------------------------------------~n", []),
- ?t:fail({X,Y}).
+ io:format("expected: ~p~n", [X]),
+ io:format("got : ~p~n", [Y]),
+ io:format("-----------------------------------------------~n", []),
+ ct:fail({X,Y}).
init_per_suite(Config) ->
- PD = ?config(priv_dir, Config),
- SymLinks = case ?t:os_type() of
- {win32, _} -> false;
- _ ->
- case file:make_symlink("nothing",
- filename:join(PD,
- "symlink_test")) of
- ok -> true;
- _ -> false
- end
- end,
+ PD = proplists:get_value(priv_dir, Config),
+ SymLinks = case os:type() of
+ {win32, _} -> false;
+ _ ->
+ case file:make_symlink("nothing",
+ filename:join(PD, "symlink_test")) of
+ ok -> true;
+ _ -> false
+ end
+ end,
[{symlinks, SymLinks} | Config].
end_per_suite(_Config) ->
ok.
init_per_testcase(Case, Config) ->
- init_per_testcase_aux(?config(symlinks,Config),?t:os_type(),Case,Config).
+ init_per_testcase_aux(proplists:get_value(symlinks,Config),
+ os:type(),Case,Config).
init_per_testcase_aux(_, {win32, _}, _Case, _Config) ->
{skip, "Not on windows"};
@@ -586,18 +576,13 @@ init_per_testcase_aux(false, OsType, Case, Config) ->
true -> {skip, "Cannot create symbolic links"}
end;
init_per_testcase_aux(true, _OsType, Case, Config) ->
- Dog = ?t:timetrap(?DEFAULT_TIMEOUT),
- [{watchdog, Dog},
- {testcase, Case},
- {test_dir, make_dirs(?config(priv_dir, Config), atom_to_list(Case))}
+ [{testcase, Case},
+ {test_dir, make_dirs(proplists:get_value(priv_dir, Config), atom_to_list(Case))}
| Config].
-end_per_testcase(_Case, Config) ->
- Dog = ?config(watchdog, Config),
- ?t:timetrap_cancel(Dog),
+end_per_testcase(_Case, _Config) ->
ok.
-
make_dirs(Root, Suffix) ->
do_make_dirs(Root, string:tokens(Suffix, [$/])).
@@ -616,9 +601,9 @@ install_bin(Config, #inst{mkdirs = MkDirs,
exec_prefix = EXEC_PREFIX,
bindir = BINDIR,
erlang_bindir = ERLANG_BINDIR} = Inst, ChkRes) ->
- PDir = ?config(priv_dir, Config),
- TDir = ?config(test_dir, Config),
- TD = atom_to_list(?config(testcase, Config)),
+ PDir = proplists:get_value(priv_dir, Config),
+ TDir = proplists:get_value(test_dir, Config),
+ TD = atom_to_list(proplists:get_value(testcase, Config)),
case MkDirs of
false -> ok;
true ->
@@ -641,7 +626,7 @@ install_bin(Config, #inst{mkdirs = MkDirs,
bindir = join([TDir, BINDIR]),
erlang_bindir = join([TDir, ERLANG_BINDIR])},
ChkRes),
- case ?config(symlinks, Config) of
+ case proplists:get_value(symlinks, Config) of
true -> ok;
false -> {comment, "No symlink tests run, since symlinks not working"}
end.
@@ -664,7 +649,7 @@ install_bin2(Config, Inst, ChkRes) ->
install_bin3(Config, Inst#inst{symlinks = false,
ln_s = "cp -p",
bindir_symlinks = "absolute"}, ChkRes),
- case ?config(symlinks, Config) of
+ case proplists:get_value(symlinks, Config) of
true ->
install_bin3(Config, Inst#inst{symlinks = true,
ln_s = "ln -s"}, ChkRes),
@@ -690,9 +675,9 @@ install_bin3(Config,
erlang_bindir = ERLANG_BINDIR,
bindir_symlinks = BINDIR_SYMLINKS} = Inst,
ChkRes) ->
- Test = ?config(testcase, Config),
- DDir = ?config(data_dir, Config),
- TDir = ?config(test_dir, Config),
+ Test = proplists:get_value(testcase, Config),
+ DDir = proplists:get_value(data_dir, Config),
+ TDir = proplists:get_value(test_dir, Config),
InstallBin = filename:join(DDir, "install_bin"),
ResFile = filename:join(TDir, atom_to_list(Test) ++ "-result.txt"),
Cmd = CMD_PRFX ++ " "
@@ -705,7 +690,7 @@ install_bin3(Config,
++ "\" --exec-prefix \"" ++ EXEC_PREFIX
++ "\" --test-file \"" ++ ResFile ++ "\" erl erlc",
- ?t:format("CMD_PRFX = \"~s\"~n"
+ io:format("CMD_PRFX = \"~s\"~n"
"LN_S = \"~s\"~n"
"BINDIR_SYMLINKS = \"~s\"~n"
"exec_prefix = \"~s\"~n"
@@ -716,9 +701,9 @@ install_bin3(Config,
[CMD_PRFX, LN_S, BINDIR_SYMLINKS, EXEC_PREFIX, BINDIR,
ERLANG_BINDIR, EXTRA_PREFIX, DESTDIR]),
- ?t:format("$ ~s~n", [Cmd]),
+ io:format("$ ~s~n", [Cmd]),
CmdOutput = os:cmd(Cmd),
- ?t:format("~s~n", [CmdOutput]),
+ io:format("~s~n", [CmdOutput]),
ChkRes(case file:consult(ResFile) of
{ok, [Res]} -> Res;
Err -> exit({result, Err})
@@ -731,4 +716,3 @@ join([""|Ds]) ->
join(Ds);
join([D|Ds]) ->
"/" ++ string:strip(D, both, $/) ++ join(Ds).
-
diff --git a/erts/test/nt_SUITE.erl b/erts/test/nt_SUITE.erl
index 1ddaaaaeb5..624e5484ba 100644
--- a/erts/test/nt_SUITE.erl
+++ b/erts/test/nt_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1998-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.
@@ -23,55 +23,36 @@
-include_lib("common_test/include/ct.hrl").
-include_lib("kernel/include/file.hrl").
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,init_per_testcase/2,
- end_per_testcase/2,nt/1,handle_eventlog/2,
- middleman/1,service_basic/1, service_env/1, user_env/1, synced/1,
- service_prio/1,
- logout/1, debug/1, restart/1, restart_always/1,stopaction/1,
- shutdown_io/0,do_shutdown_io/0]).
--define(TEST_TIMEOUT, ?t:seconds(180)).
+-export([all/0, suite/0,
+ init_per_testcase/2, end_per_testcase/2,
+ nt/1,handle_eventlog/2,
+ middleman/1,service_basic/1, service_env/1, user_env/1, synced/1,
+ service_prio/1,
+ logout/1, debug/1, restart/1, restart_always/1,stopaction/1,
+ shutdown_io/0,do_shutdown_io/0]).
-define(TEST_SERVICES, [1,2,3,4,5,6,7,8,9,10,11]).
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap, {minutes, 3}}].
-all() ->
- case os:type() of
- {win32, nt} ->
+all() ->
+ case {os:type(), os:version()} of
+ {{win32, nt}, Vsn} when Vsn =< {6,1,999999} ->
[nt, service_basic, service_env, user_env, synced,
service_prio, logout, debug, restart, restart_always,
stopaction];
_ -> [nt]
end.
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
init_per_testcase(_Func, Config) ->
- Dog = test_server:timetrap(?TEST_TIMEOUT),
- [{watchdog, Dog} | Config].
+ Config.
-end_per_testcase(_Func, Config) ->
+end_per_testcase(_Func, _Config) ->
lists:foreach(fun(X) ->
- catch remove_service("test_service_" ++
- integer_to_list(X)) end,
- ?TEST_SERVICES),
- Dog = ?config(watchdog, Config),
- catch test_server:timetrap_cancel(Dog),
+ catch remove_service("test_service_" ++ integer_to_list(X))
+ end, ?TEST_SERVICES),
ok.
erlsrv() ->
@@ -80,19 +61,18 @@ erlsrv() ->
recv_prog_output(Port) ->
receive
- {Port, {data, {eol,Data}}} ->
- %%io:format("Got data: ~s~n", [Data]),
- [ Data | recv_prog_output(Port)];
- _X ->
- %%io:format("Got data: ~p~n", [_X]),
- Port ! {self(), close},
- receive
- _ ->
- []
- end
+ {Port, {data, {eol,Data}}} ->
+ %%io:format("Got data: ~s~n", [Data]),
+ [ Data | recv_prog_output(Port)];
+ _X ->
+ %%io:format("Got data: ~p~n", [_X]),
+ Port ! {self(), close},
+ receive
+ _ ->
+ []
+ end
end.
-
%%% X == parameters to erlsrv
%%% returns command output without stderr
do_command(X) ->
@@ -100,11 +80,11 @@ do_command(X) ->
Port = open_port({spawn, erlsrv() ++ " " ++ X}, [stream, {line, 100}, eof, in]),
Res = recv_prog_output(Port),
case Res of
- [] ->
- failed;
- _Y ->
- %%io:format("~p~n",[_Y]),
- ok
+ [] ->
+ failed;
+ _Y ->
+ %%io:format("~p~n",[_Y]),
+ ok
end.
@@ -123,13 +103,13 @@ do_wait_for_it(_,0) ->
false;
do_wait_for_it(FullName,N) ->
case net_adm:ping(FullName) of
- pong ->
- true;
- _ ->
- receive
- after 1000 ->
- do_wait_for_it(FullName,N-1)
- end
+ pong ->
+ true;
+ _ ->
+ receive
+ after 1000 ->
+ do_wait_for_it(FullName,N-1)
+ end
end.
wait_for_node(Name) ->
@@ -139,309 +119,282 @@ wait_for_node(Name) ->
make_full_name(Name) ->
[_,Suffix] = string:tokens(atom_to_list(node()),"@"),
list_to_atom(Name ++ "@" ++ Suffix).
-
+
%%% The following tests are only run on NT:
-service_basic(doc) ->
- ["Check some basic (cosmetic) service parameters"];
-service_basic(suite) -> [];
+%% Check some basic (cosmetic) service parameters
service_basic(Config) when is_list(Config) ->
- ?line Name = "test_service_20",
- ?line IntName = Name++"_internal",
- ?line Service = [{servicename,Name},
- {args, ["-setcookie",
- atom_to_list(erlang:get_cookie())]},
- {internalservicename,IntName},
- {comment,"Epic comment"}],
- ?line ok = erlsrv:store_service(Service),
- ?line start_service(Name),
- ?line true = wait_for_node(Name),
- ?line S2 = erlsrv:get_service(Name),
- ?line {value,{comment,"Epic comment"}} = lists:keysearch(comment,1,S2),
- ?line {value,{internalservicename,IntName}} =
- lists:keysearch(internalservicename,1,S2),
- ?line S3 = lists:keyreplace(comment,1,S2,{comment,"Basic comment"}),
- ?line S4 = lists:keyreplace(internalservicename,1,S3,
- {internalservicename,"WillNotHappen"}),
- ?line ok = erlsrv:store_service(S4),
- ?line S5 = erlsrv:get_service(Name),
- ?line {value,{comment,"Basic comment"}} = lists:keysearch(comment,1,S5),
- ?line {value,{internalservicename,IntName}} =
- lists:keysearch(internalservicename,1,S5),
- ?line NewName = "test_service_21",
- ?line S6 = erlsrv:new_service(NewName,S5,[]), % should remove
- % internalservicename
- ?line ok = erlsrv:store_service(S6),
- ?line S7 = erlsrv:get_service(NewName),
- ?line {value,{comment,"Basic comment"}} = lists:keysearch(comment,1,S7),
- ?line {value,{internalservicename,[$t,$e,$s,$t | _]}} =
- lists:keysearch(internalservicename,1,S7),
- ?line remove_service(Name),
- ?line remove_service(NewName),
+ Name = "test_service_20",
+ IntName = Name++"_internal",
+ Service = [{servicename,Name},
+ {args, ["-setcookie", atom_to_list(erlang:get_cookie())]},
+ {internalservicename,IntName},
+ {comment,"Epic comment"}],
+ ok = erlsrv:store_service(Service),
+ start_service(Name),
+ true = wait_for_node(Name),
+ S2 = erlsrv:get_service(Name),
+ {value,{comment,"Epic comment"}} = lists:keysearch(comment,1,S2),
+ {value,{internalservicename,IntName}} =
+ lists:keysearch(internalservicename,1,S2),
+ S3 = lists:keyreplace(comment,1,S2,{comment,"Basic comment"}),
+ S4 = lists:keyreplace(internalservicename,1,S3,
+ {internalservicename,"WillNotHappen"}),
+ ok = erlsrv:store_service(S4),
+ S5 = erlsrv:get_service(Name),
+ {value,{comment,"Basic comment"}} = lists:keysearch(comment,1,S5),
+ {value,{internalservicename,IntName}} =
+ lists:keysearch(internalservicename,1,S5),
+ NewName = "test_service_21",
+ S6 = erlsrv:new_service(NewName,S5,[]), % should remove
+ % internalservicename
+ ok = erlsrv:store_service(S6),
+ S7 = erlsrv:get_service(NewName),
+ {value,{comment,"Basic comment"}} = lists:keysearch(comment,1,S7),
+ {value,{internalservicename,[$t,$e,$s,$t | _]}} =
+ lists:keysearch(internalservicename,1,S7),
+ remove_service(Name),
+ remove_service(NewName),
ok.
-service_env(doc) ->
- ["Check that service name and executable is in the environment of the " ++
- "erlang process created by erlsrv."];
-service_env(suite) -> [];
+%% Check that service name and executable is in the environment of the
+%% erlang process created by erlsrv.
service_env(Config) when is_list(Config) ->
- ?line Name = "test_service_2",
- ?line Service = [{servicename,Name},
- {args, ["-setcookie",
- atom_to_list(erlang:get_cookie())]}],
- ?line ok = erlsrv:store_service(Service),
- ?line start_service(Name),
- ?line true = wait_for_node(Name),
- ?line Name = rpc:call(make_full_name(Name),os,getenv,
- ["ERLSRV_SERVICE_NAME"]),
- ?line "erlsrv.exe" = filename:basename(
- hd(
- string:tokens(
- rpc:call(make_full_name(Name),
- os,
- getenv,
- ["ERLSRV_EXECUTABLE"]),
- "\""))),
- ?line remove_service(Name),
+ Name = "test_service_2",
+ Service = [{servicename,Name},
+ {args, ["-setcookie", atom_to_list(erlang:get_cookie())]}],
+ ok = erlsrv:store_service(Service),
+ start_service(Name),
+ true = wait_for_node(Name),
+ Name = rpc:call(make_full_name(Name),os,getenv,
+ ["ERLSRV_SERVICE_NAME"]),
+ "erlsrv.exe" = filename:basename(
+ hd(
+ string:tokens(
+ rpc:call(make_full_name(Name),
+ os,
+ getenv,
+ ["ERLSRV_EXECUTABLE"]),
+ "\""))),
+ remove_service(Name),
ok.
-user_env(doc) ->
- ["Check that the user defined environment is ADDED to the service's"++
- " normal dito."];
-user_env(suite) -> [];
+
+%% Check that the user defined environment is ADDED to the service's
+%% normal dito.
user_env(Config) when is_list(Config) ->
- ?line Name = "test_service_3",
- ?line Service = [{servicename,Name},{env,[{"HUBBA","BUBBA"}]},
- {args, ["-setcookie",
- atom_to_list(erlang:get_cookie())]}],
- ?line ok = erlsrv:store_service(Service),
- ?line start_service(Name),
- ?line true = wait_for_node(Name),
- ?line true = rpc:call(make_full_name(Name),os,getenv,
- ["SystemDrive"]) =/= false,
- ?line "BUBBA" = rpc:call(make_full_name(Name),os,getenv,["HUBBA"]),
- ?line remove_service(Name),
+ Name = "test_service_3",
+ Service = [{servicename,Name},{env,[{"HUBBA","BUBBA"}]},
+ {args, ["-setcookie", atom_to_list(erlang:get_cookie())]}],
+ ok = erlsrv:store_service(Service),
+ start_service(Name),
+ true = wait_for_node(Name),
+ true = rpc:call(make_full_name(Name),os,getenv,
+ ["SystemDrive"]) =/= false,
+ "BUBBA" = rpc:call(make_full_name(Name),os,getenv,["HUBBA"]),
+ remove_service(Name),
ok.
-synced(doc) ->
- ["Check that services are stopped and started syncronous and that"++
- " failed stopactions kill the erlang machine anyway."];
-synced(suite) -> [];
+
+%% Check that services are stopped and started syncronous and that
+%% failed stopactions kill the erlang machine anyway.
synced(Config) when is_list(Config) ->
- ?line Name0 = "test_service_4",
- ?line Service0 = [{servicename,Name0},
- {machine, "N:\\nickeNyfikenPaSjukhus"}],
- ?line ok = erlsrv:store_service(Service0),
- ?line true = (catch start_service(Name0)) =/= ok,
- ?line remove_service(Name0),
- ?line Name = "test_service_5",
- ?line Service = [{servicename,Name},
- {stopaction,"erlang:info(garbage_collection)."},
- {args, ["-setcookie",
- atom_to_list(erlang:get_cookie())]}],
- ?line ok = erlsrv:store_service(Service),
- ?line start_service(Name),
- ?line true = wait_for_node(Name),
- ?line T1 = calendar:datetime_to_gregorian_seconds(
- calendar:universal_time()),
- ?line stop_service(Name),
- ?line Diff1 = calendar:datetime_to_gregorian_seconds(
- calendar:universal_time()) - T1,
- ?line true = Diff1 > 30,
- ?line start_service(Name),
- ?line true = wait_for_node(Name),
- ?line T2 = calendar:datetime_to_gregorian_seconds(
- calendar:universal_time()),
- ?line remove_service(Name),
- ?line Diff2 = calendar:datetime_to_gregorian_seconds(
- calendar:universal_time()) - T2,
- ?line true = Diff2 > 30,
+ Name0 = "test_service_4",
+ Service0 = [{servicename,Name0},
+ {machine, "N:\\nickeNyfikenPaSjukhus"}],
+ ok = erlsrv:store_service(Service0),
+ true = (catch start_service(Name0)) =/= ok,
+ remove_service(Name0),
+ Name = "test_service_5",
+ Service = [{servicename,Name},
+ {stopaction,"erlang:info(garbage_collection)."},
+ {args, ["-setcookie", atom_to_list(erlang:get_cookie())]}],
+ ok = erlsrv:store_service(Service),
+ start_service(Name),
+ true = wait_for_node(Name),
+ T1 = calendar:datetime_to_gregorian_seconds(
+ calendar:universal_time()),
+ stop_service(Name),
+ Diff1 = calendar:datetime_to_gregorian_seconds(
+ calendar:universal_time()) - T1,
+ true = Diff1 > 30,
+ start_service(Name),
+ true = wait_for_node(Name),
+ T2 = calendar:datetime_to_gregorian_seconds(
+ calendar:universal_time()),
+ remove_service(Name),
+ Diff2 = calendar:datetime_to_gregorian_seconds(
+ calendar:universal_time()) - T2,
+ true = Diff2 > 30,
ok.
-service_prio(doc) ->
- ["Check that a service with higher prio create port programs with "
- "higher prio."];
-service_prio(suite) -> [];
+
+%% Check that a service with higher prio create port programs with
+%% higher prio.
service_prio(Config) when is_list(Config) ->
- ?line Name = "test_service_6",
- ?line Service = [{servicename,Name},{prio,"high"},
- {env, [{"HEART_COMMAND","echo off"}]},
- {args, ["-setcookie",
- atom_to_list(erlang:get_cookie()),
- "-heart"]}],
- ?line ok = erlsrv:store_service(Service),
- ?line {ok, OldProcs} = get_current_procs(Config),
- ?line start_service(Name),
- ?line {ok, NewProcs} = get_current_procs(Config),
+ Name = "test_service_6",
+ Service = [{servicename,Name},{prio,"high"},
+ {env, [{"HEART_COMMAND","echo off"}]},
+ {args, ["-setcookie", atom_to_list(erlang:get_cookie()),
+ "-heart"]}],
+ ok = erlsrv:store_service(Service),
+ {ok, OldProcs} = get_current_procs(Config),
+ start_service(Name),
+ {ok, NewProcs} = get_current_procs(Config),
timer:sleep(2000),
- ?line {ok, NewProcs2} = get_current_procs(Config),
- ?line remove_service(Name),
- ?line Diff = arrived_procs(OldProcs,NewProcs),
+ {ok, NewProcs2} = get_current_procs(Config),
+ remove_service(Name),
+ Diff = arrived_procs(OldProcs,NewProcs),
io:format("NewProcs ~p~n after sleep~n ~p~n",[Diff, arrived_procs(OldProcs,NewProcs2)]),
%% Not really correct, could fail if another heart is
%% started at the same time...
- ?line {value, {"heart.exe",_,"high"}} =
- lists:keysearch("heart.exe",1,Diff),
+ {value, {"heart.exe",_,"high"}} = lists:keysearch("heart.exe",1,Diff),
ok.
-logout(doc) ->
- ["Check that logout does not kill services"];
-logout(suite) -> [];
+
+%% Check that logout does not kill services
logout(Config) when is_list(Config) ->
- ?line {comment, "Have to be run manually by registering a service with " ++
- "heart, logout and log in again and then examine that the heart " ++
- "process id is not changed."}.
-debug(doc) ->
- ["Check the debug options to erlsrv."];
-debug(suite) -> [];
+ {comment, "Have to be run manually by registering a service with " ++
+ "heart, logout and log in again and then examine that the heart " ++
+ "process id is not changed."}.
+
+%% Check the debug options to erlsrv.
debug(Config) when is_list(Config) ->
- ?line Name0 = "test_service_7",
+ Name0 = "test_service_7",
%% We used to set the privdir as temporary directory, but for some
%% reason we don't seem to have write access to that directory,
%% so we'll use the directory specified in the next line.
- ?line TempDir = "C:/TEMP",
- ?line Service0 = [{servicename,Name0},
- {workdir,filename:nativename(TempDir)},
- {debugtype,"reuse"},
- {args, ["-setcookie",
- atom_to_list(erlang:get_cookie())]}],
- ?line ok = erlsrv:store_service(Service0),
- ?line T1 = calendar:datetime_to_gregorian_seconds(
- calendar:local_time()),
+ TempDir = "C:/TEMP",
+ Service0 = [{servicename,Name0},
+ {workdir,filename:nativename(TempDir)},
+ {debugtype,"reuse"},
+ {args, ["-setcookie", atom_to_list(erlang:get_cookie())]}],
+ ok = erlsrv:store_service(Service0),
+ T1 = calendar:datetime_to_gregorian_seconds(
+ calendar:local_time()),
%% sleep a little
- ?line receive after 2000 -> ok end,
- ?line start_service(Name0),
- ?line true = wait_for_node(Name0),
- ?line LF = filename:join(TempDir, Name0++".debug"),
- ?line {ok,Info0} = file:read_file_info(LF),
- ?line T2 = calendar:datetime_to_gregorian_seconds(
- Info0#file_info.mtime),
- ?line true = T2 > T1,
- ?line remove_service(Name0),
- ?line file:delete(LF),
- ?line Name1 = "test_service_8",
- ?line Service1 = [{servicename,Name1},
- {workdir, filename:nativename(TempDir)},
- {debugtype,"new"},
- {args, ["-setcookie",
- atom_to_list(erlang:get_cookie())]}],
- ?line ok = erlsrv:store_service(Service1),
- ?line T3 = calendar:datetime_to_gregorian_seconds(
- calendar:local_time()),
+ receive after 2000 -> ok end,
+ start_service(Name0),
+ true = wait_for_node(Name0),
+ LF = filename:join(TempDir, Name0++".debug"),
+ {ok,Info0} = file:read_file_info(LF),
+ T2 = calendar:datetime_to_gregorian_seconds(
+ Info0#file_info.mtime),
+ true = T2 > T1,
+ remove_service(Name0),
+ file:delete(LF),
+ Name1 = "test_service_8",
+ Service1 = [{servicename,Name1},
+ {workdir, filename:nativename(TempDir)},
+ {debugtype,"new"},
+ {args, ["-setcookie", atom_to_list(erlang:get_cookie())]}],
+ ok = erlsrv:store_service(Service1),
+ T3 = calendar:datetime_to_gregorian_seconds(
+ calendar:local_time()),
%% sleep a little
- ?line receive after 2000 -> ok end,
- ?line NF = next_logfile(TempDir, Name1),
- ?line start_service(Name1),
- ?line true = wait_for_node(Name1),
- ?line {ok,Info1} = file:read_file_info(NF),
- ?line T4 = calendar:datetime_to_gregorian_seconds(
- Info1#file_info.mtime),
- ?line true = T4 > T3,
- ?line remove_service(Name1),
- ?line file:delete(NF),
+ receive after 2000 -> ok end,
+ NF = next_logfile(TempDir, Name1),
+ start_service(Name1),
+ true = wait_for_node(Name1),
+ {ok,Info1} = file:read_file_info(NF),
+ T4 = calendar:datetime_to_gregorian_seconds(
+ Info1#file_info.mtime),
+ true = T4 > T3,
+ remove_service(Name1),
+ file:delete(NF),
ok.
-restart(doc) ->
- ["Check the restart options to erlsrv"];
-restart(suite) -> [];
+%% Check the restart options to erlsrv
restart(Config) when is_list(Config) ->
- ?line Name = "test_service_9",
- ?line Service = [{servicename,Name},
- {workdir, filename:nativename(logdir(Config))},
- {onfail,"restart"},
- {args, ["-setcookie",
- atom_to_list(erlang:get_cookie())]}],
- ?line ok = erlsrv:store_service(Service),
- ?line start_service(Name),
- ?line true = wait_for_node(Name),
- ?line receive after 20000 -> ok end,
- ?line rpc:call(make_full_name(Name),erlang,halt,[]),
- ?line receive after 1000 -> ok end,
- ?line true = wait_for_node(Name),
- ?line rpc:call(make_full_name(Name),erlang,halt,[]),
- ?line receive after 1000 -> ok end,
- ?line false = wait_for_node(Name),
- ?line remove_service(Name),
+ Name = "test_service_9",
+ Service = [{servicename,Name},
+ {workdir, filename:nativename(logdir(Config))},
+ {onfail,"restart"},
+ {args, ["-setcookie", atom_to_list(erlang:get_cookie())]}],
+ ok = erlsrv:store_service(Service),
+ start_service(Name),
+ true = wait_for_node(Name),
+ receive after 20000 -> ok end,
+ rpc:call(make_full_name(Name),erlang,halt,[]),
+ receive after 1000 -> ok end,
+ true = wait_for_node(Name),
+ rpc:call(make_full_name(Name),erlang,halt,[]),
+ receive after 1000 -> ok end,
+ false = wait_for_node(Name),
+ remove_service(Name),
ok.
-restart_always(doc) ->
- ["Check the restart options to erlsrv"];
-restart_always(suite) -> [];
+%% Check the restart options to erlsrv
restart_always(Config) when is_list(Config) ->
- ?line Name = "test_service_10",
- ?line Service = [{servicename,Name},
- {workdir, filename:nativename(logdir(Config))},
- {onfail,"restart_always"},
- {args, ["-setcookie",
- atom_to_list(erlang:get_cookie())]}],
- ?line ok = erlsrv:store_service(Service),
- ?line start_service(Name),
- ?line true = wait_for_node(Name),
- ?line rpc:call(make_full_name(Name),erlang,halt,[]),
- ?line receive after 1000 -> ok end,
- ?line true = wait_for_node(Name),
- ?line rpc:call(make_full_name(Name),erlang,halt,[]),
- ?line receive after 1000 -> ok end,
- ?line true = wait_for_node(Name),
- ?line remove_service(Name),
+ Name = "test_service_10",
+ Service = [{servicename,Name},
+ {workdir, filename:nativename(logdir(Config))},
+ {onfail,"restart_always"},
+ {args, ["-setcookie", atom_to_list(erlang:get_cookie())]}],
+ ok = erlsrv:store_service(Service),
+ start_service(Name),
+ true = wait_for_node(Name),
+ rpc:call(make_full_name(Name),erlang,halt,[]),
+ receive after 1000 -> ok end,
+ true = wait_for_node(Name),
+ rpc:call(make_full_name(Name),erlang,halt,[]),
+ receive after 1000 -> ok end,
+ true = wait_for_node(Name),
+ remove_service(Name),
ok.
-stopaction(doc) ->
- ["Check that stopaction does not hang output while shutting down"];
-stopaction(suite) -> [];
+
+%% Check that stopaction does not hang output while shutting down
stopaction(Config) when is_list(Config) ->
- ?line Name = "test_service_11",
+ Name = "test_service_11",
%% Icky, I prepend the first element in the codepath, cause
%% I "suppose" it's the one to where I am.
- ?line Service = [{servicename,Name},
- {stopaction,atom_to_list(?MODULE) ++ ":shutdown_io()."},
- {args, ["-setcookie",
- atom_to_list(erlang:get_cookie()),
- "-pa", hd(code:get_path())]}],
- ?line ok = erlsrv:store_service(Service),
- ?line start_service(Name),
- ?line true = wait_for_node(Name),
- ?line T1 = calendar:datetime_to_gregorian_seconds(
- calendar:universal_time()),
- ?line stop_service(Name),
- ?line Diff1 = calendar:datetime_to_gregorian_seconds(
- calendar:universal_time()) - T1,
- ?line true = Diff1 < 30,
- ?line remove_service(Name),
+ Service = [{servicename,Name},
+ {stopaction,atom_to_list(?MODULE) ++ ":shutdown_io()."},
+ {args, ["-setcookie", atom_to_list(erlang:get_cookie()),
+ "-pa", hd(code:get_path())]}],
+ ok = erlsrv:store_service(Service),
+ start_service(Name),
+ true = wait_for_node(Name),
+ T1 = calendar:datetime_to_gregorian_seconds(
+ calendar:universal_time()),
+ stop_service(Name),
+ Diff1 = calendar:datetime_to_gregorian_seconds(
+ calendar:universal_time()) - T1,
+ true = Diff1 < 30,
+ remove_service(Name),
ok.
%%% This test is run on all platforms, but just gives a comment on
%%% other platforms than NT.
-nt(doc) ->
- ["Run NT specific tests."];
-nt(suite) ->
- [];
nt(Config) when is_list(Config) ->
- case os:type() of
- {win32,nt} ->
+ case {os:type(), os:version()} of
+ {{win32, nt}, Vsn} when Vsn =< {6,1,999999} ->
nt_run();
+ {{win32, nt}, _} ->
+ {skipped, "This test case requires admin privileges on Win 8 and later."};
_ ->
{skipped, "This test case is intended for Win NT only."}
end.
nt_run() ->
- ?line start_all(),
- ?line create_service("test_service_1"),
- ?line R = start_look_for_single("System","ErlSrv","Informational",
- ".*test_service_1.*started.*"),
- ?line start_service("test_service_1"),
- ?line Res = look_for_single(R),
- ?line io:format("Result from eventlog: ~p~n",
- [Res]),
- ?line remove_service("test_service_1"),
- ?line stop_all(),
+ start_all(),
+ create_service("test_service_1"),
+ R = start_look_for_single("System","ErlSrv","Informational",
+ ".*test_service_1.*started.*"),
+ start_service("test_service_1"),
+ Res = look_for_single(R),
+ io:format("Result from eventlog: ~p~n",
+ [Res]),
+ remove_service("test_service_1"),
+ stop_all(),
ok.
start_all() ->
Pid1 = spawn_link(?MODULE,middleman,[[]]),
register(?MODULE,Pid1),
_Pid2 = nteventlog:start("log_testing",
- {?MODULE,handle_eventlog,[Pid1]}).
+ {?MODULE,handle_eventlog,[Pid1]}).
stop_all() ->
?MODULE ! stop,
@@ -454,10 +407,10 @@ start_look_for_single(Cat,Fac,Sev,MessRE) ->
look_for_single(Ref) ->
receive
- {Ref,Time,Mes} ->
- {Time,Mes}
+ {Ref,Time,Mes} ->
+ {Time,Mes}
after 60000 ->
- timeout
+ timeout
end.
@@ -468,25 +421,25 @@ handle_eventlog(Mes,Pid) ->
%%% Waitfor = [{Pid, Ref, {Category,Facility,Severity,MessageRE}} ...]
middleman(Waitfor) ->
receive
- {Time,Category,Facility,Severity,Message} ->
- io:format("Middleman got ~s...", [Message]),
- case match_event({Time,Category,Facility,Severity,Message},
- Waitfor) of
- {ok, {Pid,Ref,Time,Mes}, Rest} ->
- io:format("matched~n"),
- Pid ! {Ref,Time,Mes},
- middleman(Rest);
- _ ->
- io:format("no match~n"),
- middleman(Waitfor)
- end;
- {lookfor, X} ->
- io:format("Middleman told to look for ~p~n", [X]),
- middleman([X|Waitfor]);
- stop ->
- stopped;
- _ ->
- middleman(Waitfor)
+ {Time,Category,Facility,Severity,Message} ->
+ io:format("Middleman got ~s...", [Message]),
+ case match_event({Time,Category,Facility,Severity,Message},
+ Waitfor) of
+ {ok, {Pid,Ref,Time,Mes}, Rest} ->
+ io:format("matched~n"),
+ Pid ! {Ref,Time,Mes},
+ middleman(Rest);
+ _ ->
+ io:format("no match~n"),
+ middleman(Waitfor)
+ end;
+ {lookfor, X} ->
+ io:format("Middleman told to look for ~p~n", [X]),
+ middleman([X|Waitfor]);
+ stop ->
+ stopped;
+ _ ->
+ middleman(Waitfor)
end.
@@ -495,81 +448,81 @@ match_event(_X, []) ->
nomatch;
match_event({Time,Cat,Fac,Sev,Mes},[{Pid,Ref,{Cat,Fac,Sev,MesRE}} | Tail]) ->
case re:run(Mes,MesRE,[{capture,none}]) of
- match ->
- %%io:format("Match!~n"),
- {ok,{Pid,Ref,Time,Mes},Tail};
- nomatch ->
- %%io:format("No match~n"),
- case match_event({Time,Cat,Fac,Sev,Mes},Tail) of
- {ok,X,Rest} ->
- {ok,X,[{Pid,Ref,{Cat,Fac,Sev,MesRE}} | Rest]};
- X ->
- X
- end
+ match ->
+ %%io:format("Match!~n"),
+ {ok,{Pid,Ref,Time,Mes},Tail};
+ nomatch ->
+ %%io:format("No match~n"),
+ case match_event({Time,Cat,Fac,Sev,Mes},Tail) of
+ {ok,X,Rest} ->
+ {ok,X,[{Pid,Ref,{Cat,Fac,Sev,MesRE}} | Rest]};
+ X ->
+ X
+ end
end;
match_event(X,[Y | T]) ->
%%io:format("X == ~p, Y == ~p~n",[X,Y]),
case match_event(X,T) of
- {ok,Z,R} ->
- {ok,Z,[Y|R]};
- XX ->
- XX
+ {ok,Z,R} ->
+ {ok,Z,[Y|R]};
+ XX ->
+ XX
end.
arrived_procs(_,[]) ->
[];
arrived_procs(OldProcs,[{Executable, Pid, Priority} | TNewProcs]) ->
case lists:keysearch(Pid,2,OldProcs) of
- {value, _} ->
- arrived_procs(OldProcs, TNewProcs);
- false ->
- [{Executable, Pid, Priority} | arrived_procs(OldProcs, TNewProcs)]
+ {value, _} ->
+ arrived_procs(OldProcs, TNewProcs);
+ false ->
+ [{Executable, Pid, Priority} | arrived_procs(OldProcs, TNewProcs)]
end.
-
+
get_current_procs(Config) ->
- ?line P = open_port({spawn,nt_info(Config) ++ " -E"},
- [{line,10000}]),
- ?line L = receive
- {P,{data,{eol,D}}} ->
- D;
- _ -> "error. "
- end,
- ?line P ! {self(), close},
- ?line receive
- {P, closed} -> ok
- end,
- ?line {done,{ok,Tok,_},_} = erl_scan:tokens([],L,0),
- ?line erl_parse:parse_term(Tok).
+ P = open_port({spawn,nt_info(Config) ++ " -E"},
+ [{line,10000}]),
+ L = receive
+ {P,{data,{eol,D}}} ->
+ D;
+ _ -> "error. "
+ end,
+ P ! {self(), close},
+ receive
+ {P, closed} -> ok
+ end,
+ {done,{ok,Tok,_},_} = erl_scan:tokens([],L,0),
+ erl_parse:parse_term(Tok).
nt_info(Config) when is_list(Config) ->
- ?line "\"" ++ filename:join(?config(data_dir, Config), "nt_info") ++ "\"".
+ "\"" ++ filename:join(proplists:get_value(data_dir, Config), "nt_info") ++ "\"".
logdir(Config) ->
- ?line ?config(priv_dir, Config).
+ proplists:get_value(priv_dir, Config).
look_for_next(Template,L,N) ->
- ?line FN = Template ++ integer_to_list(N),
- ?line case lists:member(FN,L) of
- true ->
- ?line look_for_next(Template,L,N+1);
- false ->
- ?line FN
+ FN = Template ++ integer_to_list(N),
+ case lists:member(FN,L) of
+ true ->
+ look_for_next(Template,L,N+1);
+ false ->
+ FN
end.
next_logfile(LD, Servicename) ->
- ?line {ok, Files} = file:list_dir(LD),
- ?line Ftmpl = Servicename ++ ".debug.",
- ?line filename:join(LD,look_for_next(Ftmpl,Files,1)).
+ {ok, Files} = file:list_dir(LD),
+ Ftmpl = Servicename ++ ".debug.",
+ filename:join(LD,look_for_next(Ftmpl,Files,1)).
%%% Functions run by the service
do_shutdown_io() ->
receive
after 2000 ->
- io:format("IO in shutting down...~n"),
- erlang:halt()
+ io:format("IO in shutting down...~n"),
+ erlang:halt()
end.
shutdown_io() ->
diff --git a/erts/test/nt_SUITE_data/Makefile.src b/erts/test/nt_SUITE_data/Makefile.src
index 26da26b195..2317828337 100644
--- a/erts/test/nt_SUITE_data/Makefile.src
+++ b/erts/test/nt_SUITE_data/Makefile.src
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1998-2009. All Rights Reserved.
+# Copyright Ericsson AB 1998-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.
diff --git a/erts/test/nt_SUITE_data/nt_info.c b/erts/test/nt_SUITE_data/nt_info.c
index 41d9a44c18..8ef52cad2d 100644
--- a/erts/test/nt_SUITE_data/nt_info.c
+++ b/erts/test/nt_SUITE_data/nt_info.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1998-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.
diff --git a/erts/test/otp_SUITE.erl b/erts/test/otp_SUITE.erl
index 2efb5ae200..54fcfd935f 100644
--- a/erts/test/otp_SUITE.erl
+++ b/erts/test/otp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2000-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.
@@ -20,18 +20,20 @@
-module(otp_SUITE).
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
- init_per_suite/1,end_per_suite/1]).
+-export([all/0, suite/0,
+ init_per_suite/1,end_per_suite/1]).
-export([undefined_functions/1,deprecated_not_in_obsolete/1,
- obsolete_but_not_deprecated/1,call_to_deprecated/1,
+ obsolete_but_not_deprecated/1,call_to_deprecated/1,
call_to_size_1/1,call_to_now_0/1,strong_components/1,
- erl_file_encoding/1,xml_file_encoding/1,runtime_dependencies/1]).
+ erl_file_encoding/1,xml_file_encoding/1,runtime_dependencies/1]).
-include_lib("common_test/include/ct.hrl").
-import(lists, [filter/2,foldl/3,foreach/2]).
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap, {minutes, 10}}].
all() ->
[undefined_functions, deprecated_not_in_obsolete,
@@ -40,54 +42,41 @@ all() ->
erl_file_encoding, xml_file_encoding,
runtime_dependencies].
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
init_per_suite(Config) ->
- Dog = test_server:timetrap(?t:minutes(10)),
Root = code:root_dir(),
Server = daily_xref,
- ?line xref:start(Server),
- ?line xref:set_default(Server, [{verbose,false},
- {warnings,false},
- {builtins,true}]),
- ?line {ok,_Relname} = xref:add_release(Server, Root, {name,otp}),
+ xref:start(Server),
+ xref:set_default(Server, [{verbose,false},
+ {warnings,false},
+ {builtins,true}]),
+ {ok,_Relname} = xref:add_release(Server, Root, {name,otp}),
%% If we are running the tests in the source tree, the ERTS application
%% is not in the code path. We must add it explicitly.
case code:lib_dir(erts) of
- {error,bad_name} ->
- Erts = filename:join([code:root_dir(),"erts","preloaded","ebin"]),
- ?line {ok,_} = xref:add_directory(Server, Erts, []);
- _ ->
- ok
+ {error,bad_name} ->
+ Erts = filename:join([code:root_dir(),"erts","preloaded","ebin"]),
+ {ok,_} = xref:add_directory(Server, Erts, []);
+ _ ->
+ ok
end,
-
- ?line ?t:timetrap_cancel(Dog),
[{xref_server,Server}|Config].
end_per_suite(Config) ->
- Server = ?config(xref_server, Config),
+ Server = proplists:get_value(xref_server, Config),
catch xref:stop(Server),
Config.
undefined_functions(Config) when is_list(Config) ->
- Server = ?config(xref_server, Config),
+ Server = proplists:get_value(xref_server, Config),
%% Exclude calls from generated modules in the SSL application.
ExcludeFrom = "SSL-PKIX|PKIX.*|ssl_pkix_oid",
- ?line UndefS = xref_base:analysis(undefined_function_calls),
- ?line Q = io_lib:format("Undef = ~s,"
- "ExcludedFrom = ~p:_/_,"
- "Undef - Undef | ExcludedFrom",
- [UndefS,ExcludeFrom]),
+ UndefS = xref_base:analysis(undefined_function_calls),
+ Q = io_lib:format("Undef = ~s,"
+ "ExcludedFrom = ~p:_/_,"
+ "Undef - Undef | ExcludedFrom",
+ [UndefS,ExcludeFrom]),
{ok,Undef0} = xref:q(Server, lists:flatten(Q)),
Undef1 = hipe_filter(Undef0),
Undef2 = ssl_crypto_filter(Undef1),
@@ -99,124 +88,124 @@ undefined_functions(Config) when is_list(Config) ->
Undef = diameter_filter(Undef7),
case Undef of
- [] -> ok;
- _ ->
- Fd = open_log(Config, "undefined_functions"),
- foreach(fun ({MFA1,MFA2}) ->
- io:format("~s calls undefined ~s",
- [format_mfa(Server, MFA1),
- format_mfa(MFA2)]),
- io:format(Fd, "~s ~s\n",
- [format_mfa(Server, MFA1),
- format_mfa(MFA2)])
- end, Undef),
- close_log(Fd),
- ?line ?t:fail({length(Undef),undefined_functions_in_otp})
+ [] -> ok;
+ _ ->
+ Fd = open_log(Config, "undefined_functions"),
+ foreach(fun ({MFA1,MFA2}) ->
+ io:format("~s calls undefined ~s",
+ [format_mfa(Server, MFA1),
+ format_mfa(MFA2)]),
+ io:format(Fd, "~s ~s\n",
+ [format_mfa(Server, MFA1),
+ format_mfa(MFA2)])
+ end, Undef),
+ close_log(Fd),
+ ct:fail({length(Undef),undefined_functions_in_otp})
end.
hipe_filter(Undef) ->
case erlang:system_info(hipe_architecture) of
- undefined ->
- filter(fun ({_,{hipe_bifs,_,_}}) -> false;
- ({_,{hipe,_,_}}) -> false;
- ({_,{hipe_consttab,_,_}}) -> false;
- ({_,{hipe_converters,_,_}}) -> false;
- ({{code,_,_},{Mod,_,_}}) ->
- not is_hipe_module(Mod);
- ({{code_server,_,_},{Mod,_,_}}) ->
- not is_hipe_module(Mod);
- ({{compile,_,_},{Mod,_,_}}) ->
- not is_hipe_module(Mod);
- ({{hipe,_,_},{Mod,_,_}}) ->
- %% See comment for the next clause.
- not is_hipe_module(Mod);
- ({{cerl_to_icode,translate_flags1,2},
- {hipe_rtl_arch,endianess,0}}) ->
- false;
- ({{Caller,_,_},{Callee,_,_}}) ->
- %% Part of the hipe application is here
- %% for the sake of Dialyzer. There are many
- %% undefined calls within the hipe application.
- not is_hipe_module(Caller) orelse
- not is_hipe_module(Callee);
- (_) -> true
- end, Undef);
- _Arch ->
- filter(fun ({{Mod,_,_},{hipe_bifs,write_u64,2}}) ->
- %% Unavailable except in 64 bit AMD. Ignore it.
- not is_hipe_module(Mod);
- (_) -> true
- end, Undef)
+ undefined ->
+ filter(fun ({_,{hipe_bifs,_,_}}) -> false;
+ ({_,{hipe,_,_}}) -> false;
+ ({_,{hipe_consttab,_,_}}) -> false;
+ ({_,{hipe_converters,_,_}}) -> false;
+ ({{code,_,_},{Mod,_,_}}) ->
+ not is_hipe_module(Mod);
+ ({{code_server,_,_},{Mod,_,_}}) ->
+ not is_hipe_module(Mod);
+ ({{compile,_,_},{Mod,_,_}}) ->
+ not is_hipe_module(Mod);
+ ({{hipe,_,_},{Mod,_,_}}) ->
+ %% See comment for the next clause.
+ not is_hipe_module(Mod);
+ ({{cerl_to_icode,translate_flags1,2},
+ {hipe_rtl_arch,endianess,0}}) ->
+ false;
+ ({{Caller,_,_},{Callee,_,_}}) ->
+ %% Part of the hipe application is here
+ %% for the sake of Dialyzer. There are many
+ %% undefined calls within the hipe application.
+ not is_hipe_module(Caller) orelse
+ not is_hipe_module(Callee);
+ (_) -> true
+ end, Undef);
+ _Arch ->
+ filter(fun ({{Mod,_,_},{hipe_bifs,write_u64,2}}) ->
+ %% Unavailable except in 64 bit AMD. Ignore it.
+ not is_hipe_module(Mod);
+ (_) -> true
+ end, Undef)
end.
is_hipe_module(Mod) ->
case atom_to_list(Mod) of
- "hipe_"++_ -> true;
- _ -> false
+ "hipe_"++_ -> true;
+ _ -> false
end.
ssl_crypto_filter(Undef) ->
case {app_exists(crypto),app_exists(ssl)} of
- {false,false} ->
- filter(fun({_,{ssl,_,_}}) -> false;
- ({_,{crypto,_,_}}) -> false;
- ({_,{ssh,_,_}}) -> false;
- ({_,{ssh_connection,_,_}}) -> false;
- ({_,{ssh_sftp,_,_}}) -> false;
- (_) -> true
- end, Undef);
- {_,_} -> Undef
+ {false,false} ->
+ filter(fun({_,{ssl,_,_}}) -> false;
+ ({_,{crypto,_,_}}) -> false;
+ ({_,{ssh,_,_}}) -> false;
+ ({_,{ssh_connection,_,_}}) -> false;
+ ({_,{ssh_sftp,_,_}}) -> false;
+ (_) -> true
+ end, Undef);
+ {_,_} -> Undef
end.
edoc_filter(Undef) ->
%% Filter away function call that is catched.
filter(fun({{edoc_lib,uri_get_http,1},{http,request_sync,2}}) -> false;
- (_) -> true
- end, Undef).
+ (_) -> true
+ end, Undef).
eunit_filter(Undef) ->
filter(fun({{eunit_test,wrapper_test_exported_,0},
- {eunit_test,nonexisting_function,0}}) -> false;
- (_) -> true
- end, Undef).
+ {eunit_test,nonexisting_function,0}}) -> false;
+ (_) -> true
+ end, Undef).
dialyzer_filter(Undef) ->
case app_exists(dialyzer) of
- false ->
- filter(fun({_,{dialyzer_callgraph,_,_}}) -> false;
- ({_,{dialyzer_codeserver,_,_}}) -> false;
- ({_,{dialyzer_contracts,_,_}}) -> false;
- ({_,{dialyzer_cl_parse,_,_}}) -> false;
- ({_,{dialyzer_timing,_,_}}) -> false;
- ({_,{dialyzer_plt,_,_}}) -> false;
- ({_,{dialyzer_succ_typings,_,_}}) -> false;
- ({_,{dialyzer_utils,_,_}}) -> false;
- (_) -> true
- end, Undef);
- _ -> Undef
+ false ->
+ filter(fun({_,{dialyzer_callgraph,_,_}}) -> false;
+ ({_,{dialyzer_codeserver,_,_}}) -> false;
+ ({_,{dialyzer_contracts,_,_}}) -> false;
+ ({_,{dialyzer_cl_parse,_,_}}) -> false;
+ ({_,{dialyzer_timing,_,_}}) -> false;
+ ({_,{dialyzer_plt,_,_}}) -> false;
+ ({_,{dialyzer_succ_typings,_,_}}) -> false;
+ ({_,{dialyzer_utils,_,_}}) -> false;
+ (_) -> true
+ end, Undef);
+ _ -> Undef
end.
wx_filter(Undef) ->
case app_exists(wx) of
- false ->
- filter(fun({_,{MaybeWxModule,_,_}}) ->
- case atom_to_list(MaybeWxModule) of
- "wx"++_ -> false;
- _ -> true
- end
- end, Undef);
- _ -> Undef
+ false ->
+ filter(fun({_,{MaybeWxModule,_,_}}) ->
+ case atom_to_list(MaybeWxModule) of
+ "wx"++_ -> false;
+ _ -> true
+ end
+ end, Undef);
+ _ -> Undef
end.
-
+
gs_filter(Undef) ->
case code:lib_dir(gs) of
- {error,bad_name} ->
- filter(fun({_,{gs,_,_}}) -> false;
- ({_,{gse,_,_}}) -> false;
+ {error,bad_name} ->
+ filter(fun({_,{gs,_,_}}) -> false;
+ ({_,{gse,_,_}}) -> false;
({_,{tool_utils,_,_}}) -> false;
- (_) -> true
- end, Undef);
- _ -> Undef
+ (_) -> true
+ end, Undef);
+ _ -> Undef
end.
diameter_filter(Undef) ->
@@ -229,80 +218,80 @@ diameter_filter(Undef) ->
false;
({{diameter_lib,_,_},{erlang,time_offset,0}}) ->
false;
- (_) -> true
- end, Undef).
+ (_) -> true
+ end, Undef).
deprecated_not_in_obsolete(Config) when is_list(Config) ->
- ?line Server = ?config(xref_server, Config),
- ?line {ok,DeprecatedFunctions} = xref:q(Server, "DF"),
-
- ?line L = foldl(fun({M,F,A}=MFA, Acc) ->
- case otp_internal:obsolete(M, F, A) of
- no -> [MFA|Acc];
- _ -> Acc
- end
- end, [], DeprecatedFunctions),
+ Server = proplists:get_value(xref_server, Config),
+ {ok,DeprecatedFunctions} = xref:q(Server, "DF"),
+
+ L = foldl(fun({M,F,A}=MFA, Acc) ->
+ case otp_internal:obsolete(M, F, A) of
+ no -> [MFA|Acc];
+ _ -> Acc
+ end
+ end, [], DeprecatedFunctions),
case L of
- [] -> ok;
- _ ->
- io:put_chars("The following functions have -deprecated() attributes,\n"
- "but are not listed in otp_internal:obsolete/3.\n"),
- print_mfas(group_leader(), Server, L),
- Fd = open_log(Config, "deprecated_not_obsolete"),
- print_mfas(Fd, Server, L),
- close_log(Fd),
- ?line ?t:fail({length(L),deprecated_but_not_obsolete})
+ [] -> ok;
+ _ ->
+ io:put_chars("The following functions have -deprecated() attributes,\n"
+ "but are not listed in otp_internal:obsolete/3.\n"),
+ print_mfas(group_leader(), Server, L),
+ Fd = open_log(Config, "deprecated_not_obsolete"),
+ print_mfas(Fd, Server, L),
+ close_log(Fd),
+ ct:fail({length(L),deprecated_but_not_obsolete})
end.
obsolete_but_not_deprecated(Config) when is_list(Config) ->
- ?line Server = ?config(xref_server, Config),
- ?line {ok,NotDeprecated} = xref:q(Server, "X - DF"),
+ Server = proplists:get_value(xref_server, Config),
+ {ok,NotDeprecated} = xref:q(Server, "X - DF"),
- ?line L = foldl(fun({M,F,A}=MFA, Acc) ->
- case otp_internal:obsolete(M, F, A) of
- no -> Acc;
- _ -> [MFA|Acc]
- end
- end, [], NotDeprecated),
+ L = foldl(fun({M,F,A}=MFA, Acc) ->
+ case otp_internal:obsolete(M, F, A) of
+ no -> Acc;
+ _ -> [MFA|Acc]
+ end
+ end, [], NotDeprecated),
case L of
- [] -> ok;
- _ ->
- io:put_chars("The following functions are listed "
- "in otp_internal:obsolete/3,\n"
- "but don't have -deprecated() attributes.\n"),
- print_mfas(group_leader(), Server, L),
- Fd = open_log(Config, "obsolete_not_deprecated"),
- print_mfas(Fd, Server, L),
- close_log(Fd),
- ?line ?t:fail({length(L),obsolete_but_not_deprecated})
+ [] -> ok;
+ _ ->
+ io:put_chars("The following functions are listed "
+ "in otp_internal:obsolete/3,\n"
+ "but don't have -deprecated() attributes.\n"),
+ print_mfas(group_leader(), Server, L),
+ Fd = open_log(Config, "obsolete_not_deprecated"),
+ print_mfas(Fd, Server, L),
+ close_log(Fd),
+ ct:fail({length(L),obsolete_but_not_deprecated})
end.
-
+
call_to_deprecated(Config) when is_list(Config) ->
- Server = ?config(xref_server, Config),
- ?line {ok,DeprecatedCalls} = xref:q(Server, "strict(E || DF)"),
+ Server = proplists:get_value(xref_server, Config),
+ {ok,DeprecatedCalls} = xref:q(Server, "strict(E || DF)"),
foreach(fun ({MFA1,MFA2}) ->
- io:format("~s calls deprecated ~s",
- [format_mfa(MFA1),format_mfa(MFA2)])
- end, DeprecatedCalls),
+ io:format("~s calls deprecated ~s",
+ [format_mfa(MFA1),format_mfa(MFA2)])
+ end, DeprecatedCalls),
{comment,integer_to_list(length(DeprecatedCalls))++" calls to deprecated functions"}.
call_to_size_1(Config) when is_list(Config) ->
%% Applications that do not call erlang:size/1:
Apps = [asn1,compiler,debugger,kernel,observer,parsetools,
- runtime_tools,stdlib,tools],
+ runtime_tools,stdlib,tools],
not_recommended_calls(Config, Apps, {erlang,size,1}).
call_to_now_0(Config) when is_list(Config) ->
%% Applications that do not call erlang:now/1:
Apps = [asn1,common_test,compiler,debugger,dialyzer,
- gs,kernel,mnesia,observer,parsetools,reltool,
- runtime_tools,sasl,stdlib,syntax_tools,
- tools],
+ gs,kernel,mnesia,observer,parsetools,reltool,
+ runtime_tools,sasl,stdlib,syntax_tools,
+ tools],
not_recommended_calls(Config, Apps, {erlang,now,0}).
not_recommended_calls(Config, Apps0, MFA) ->
- Server = ?config(xref_server, Config),
+ Server = proplists:get_value(xref_server, Config),
Apps = [App || App <- Apps0, is_present_application(App, Server)],
@@ -315,14 +304,14 @@ not_recommended_calls(Config, Apps0, MFA) ->
{ok,CallsToMFA} = xref:q(Server, lists:flatten(Q2)),
case CallsToMFA of
- [] ->
+ [] ->
ok;
- _ ->
+ _ ->
io:format("These calls are not allowed:\n"),
- foreach(fun ({MFA1,MFA2}) ->
- io:format("~s calls non-recommended ~s",
- [format_mfa(MFA1),format_mfa(MFA2)])
- end, CallsToMFA)
+ foreach(fun ({MFA1,MFA2}) ->
+ io:format("~s calls non-recommended ~s",
+ [format_mfa(MFA1),format_mfa(MFA2)])
+ end, CallsToMFA)
end,
%% Enumerate calls to MFA from other applications than
@@ -338,7 +327,7 @@ not_recommended_calls(Config, Apps0, MFA) ->
end, Calls)
end,
case CallsToMFA of
- [] ->
+ [] ->
SkippedApps = ordsets:subtract(ordsets:from_list(Apps0),
ordsets:from_list(Apps)),
case SkippedApps of
@@ -350,8 +339,8 @@ not_recommended_calls(Config, Apps0, MFA) ->
[string:join(AppStrings, ", ")]),
{comment, Mess}
end;
- _ ->
- ?t:fail({length(CallsToMFA),calls_to_size_1})
+ _ ->
+ ct:fail({length(CallsToMFA),calls_to_size_1})
end.
is_present_application(Name, Server) ->
@@ -362,8 +351,8 @@ is_present_application(Name, Server) ->
end.
strong_components(Config) when is_list(Config) ->
- Server = ?config(xref_server, Config),
- ?line {ok,Cs} = xref:q(Server, "components AE"),
+ Server = proplists:get_value(xref_server, Config),
+ {ok,Cs} = xref:q(Server, "components AE"),
io:format("\n\nStrong components:\n\n~p\n", [Cs]),
ok.
@@ -371,41 +360,41 @@ erl_file_encoding(_Config) ->
Root = code:root_dir(),
Wc = filename:join([Root,"**","*.erl"]),
ErlFiles = ordsets:subtract(ordsets:from_list(filelib:wildcard(Wc)),
- release_files(Root, "*.erl")),
+ release_files(Root, "*.erl")),
{ok, MP} = re:compile(".*lib/(ic)|(orber)|(cos).*", [unicode]),
Fs = [F || F <- ErlFiles,
- filter_use_latin1_coding(F, MP),
- case epp:read_encoding(F) of
- none -> false;
- _ -> true
- end],
+ filter_use_latin1_coding(F, MP),
+ case epp:read_encoding(F) of
+ none -> false;
+ _ -> true
+ end],
case Fs of
- [] ->
- ok;
- [_|_] ->
- io:put_chars("Files with \"coding:\":\n"),
- [io:put_chars(F) || F <- Fs],
- ?t:fail()
+ [] ->
+ ok;
+ [_|_] ->
+ io:put_chars("Files with \"coding:\":\n"),
+ [io:put_chars(F) || F <- Fs],
+ ct:fail(failed)
end.
filter_use_latin1_coding(F, MP) ->
case re:run(F, MP) of
- nomatch ->
- true;
+ nomatch ->
+ true;
{match, _} ->
- false
+ false
end.
xml_file_encoding(_Config) ->
XmlFiles = xml_files(),
Fs = [F || F <- XmlFiles, is_bad_encoding(F)],
case Fs of
- [] ->
- ok;
- [_|_] ->
- io:put_chars("Encoding should be \"utf-8\" or \"UTF-8\":\n"),
- [io:put_chars(F) || F <- Fs],
- ?t:fail()
+ [] ->
+ ok;
+ [_|_] ->
+ io:put_chars("Encoding should be \"utf-8\" or \"UTF-8\":\n"),
+ [io:put_chars(F) || F <- Fs],
+ ct:fail(failed)
end.
xml_files() ->
@@ -417,7 +406,7 @@ xml_files() ->
XmerlWc = filename:join([Root,"lib","xmerl","**","*.xml"]),
XmerlXmlFiles = ordsets:from_list(filelib:wildcard(XmerlWc)),
Ignore = ordsets:union([TestXmlFiles,XmerlXmlFiles,
- release_files(Root, "*.xml")]),
+ release_files(Root, "*.xml")]),
ordsets:subtract(AllXmlFiles, Ignore).
release_files(Root, Ext) ->
@@ -427,12 +416,12 @@ release_files(Root, Ext) ->
is_bad_encoding(File) ->
{ok,Bin} = file:read_file(File),
case Bin of
- <<"<?xml version=\"1.0\" encoding=\"utf-8\"",_/binary>> ->
- false;
- <<"<?xml version=\"1.0\" encoding=\"UTF-8\"",_/binary>> ->
- false;
- _ ->
- true
+ <<"<?xml version=\"1.0\" encoding=\"utf-8\"",_/binary>> ->
+ false;
+ <<"<?xml version=\"1.0\" encoding=\"UTF-8\"",_/binary>> ->
+ false;
+ _ ->
+ true
end.
runtime_dependencies(Config) ->
@@ -444,31 +433,31 @@ runtime_dependencies(Config) ->
%% Verify that (at least) OTP application runtime dependencies found
%% by xref are listed in the runtime_dependencies field of the .app file
%% of each application.
- Server = ?config(xref_server, Config),
+ Server = proplists:get_value(xref_server, Config),
{ok, AE} = xref:q(Server, "AE"),
SAE = lists:keysort(1, AE),
put(ignored_failures, []),
{AppDep, AppDeps} = lists:foldl(fun ({App, App}, Acc) ->
- Acc;
- ({App, Dep}, {undefined, []}) ->
- {{App, [Dep]}, []};
- ({App, Dep}, {{App, Deps}, AppDeps}) ->
- {{App, [Dep|Deps]}, AppDeps};
- ({App, Dep}, {AppDep, AppDeps}) ->
- {{App, [Dep]}, [AppDep | AppDeps]}
- end,
- {undefined, []},
- SAE),
+ Acc;
+ ({App, Dep}, {undefined, []}) ->
+ {{App, [Dep]}, []};
+ ({App, Dep}, {{App, Deps}, AppDeps}) ->
+ {{App, [Dep|Deps]}, AppDeps};
+ ({App, Dep}, {AppDep, AppDeps}) ->
+ {{App, [Dep]}, [AppDep | AppDeps]}
+ end,
+ {undefined, []},
+ SAE),
check_apps_deps([AppDep|AppDeps], IgnoreApps),
case IgnoreApps of
- [] ->
- ok;
- _ ->
- Comment = lists:flatten(io_lib:format("Ignored applications: ~p "
- "Ignored failures: ~p",
- [IgnoreApps,
- get(ignored_failures)])),
- {comment, Comment}
+ [] ->
+ ok;
+ _ ->
+ Comment = lists:flatten(io_lib:format("Ignored applications: ~p "
+ "Ignored failures: ~p",
+ [IgnoreApps,
+ get(ignored_failures)])),
+ {comment, Comment}
end.
have_rdep(_App, [], _Dep) ->
@@ -476,11 +465,11 @@ have_rdep(_App, [], _Dep) ->
have_rdep(App, [RDep | RDeps], Dep) ->
[AppStr, _VsnStr] = string:tokens(RDep, "-"),
case Dep == list_to_atom(AppStr) of
- true ->
- io:format("~p -> ~s~n", [App, RDep]),
- true;
- false ->
- have_rdep(App, RDeps, Dep)
+ true ->
+ io:format("~p -> ~s~n", [App, RDep]),
+ true;
+ false ->
+ have_rdep(App, RDeps, Dep)
end.
check_app_deps(_App, _AppFile, _AFDeps, [], _IgnoreApps) ->
@@ -488,17 +477,17 @@ check_app_deps(_App, _AppFile, _AFDeps, [], _IgnoreApps) ->
check_app_deps(App, AppFile, AFDeps, [XRDep | XRDeps], IgnoreApps) ->
ResOtherDeps = check_app_deps(App, AppFile, AFDeps, XRDeps, IgnoreApps),
case have_rdep(App, AFDeps, XRDep) of
- true ->
- ResOtherDeps;
- false ->
- Failure = {missing_runtime_dependency, AppFile, XRDep},
- case lists:member(App, IgnoreApps) of
- true ->
- put(ignored_failures, [Failure | get(ignored_failures)]),
- ResOtherDeps;
- false ->
- [Failure | ResOtherDeps]
- end
+ true ->
+ ResOtherDeps;
+ false ->
+ Failure = {missing_runtime_dependency, AppFile, XRDep},
+ case lists:member(App, IgnoreApps) of
+ true ->
+ put(ignored_failures, [Failure | get(ignored_failures)]),
+ ResOtherDeps;
+ false ->
+ [Failure | ResOtherDeps]
+ end
end.
check_apps_deps([], _IgnoreApps) ->
@@ -508,24 +497,24 @@ check_apps_deps([{App, Deps}|AppDeps], IgnoreApps) ->
AppFile = code:where_is_file(atom_to_list(App) ++ ".app"),
{ok,[{application, App, Info}]} = file:consult(AppFile),
case lists:keyfind(runtime_dependencies, 1, Info) of
- {runtime_dependencies, RDeps} ->
- check_app_deps(App, AppFile, RDeps, Deps, IgnoreApps)
- ++ ResOtherApps;
- false ->
- Failure = {missing_runtime_dependencies_key, AppFile},
- case lists:member(App, IgnoreApps) of
- true ->
- put(ignored_failures, [Failure | get(ignored_failures)]),
- ResOtherApps;
- false ->
- [Failure | ResOtherApps]
- end
+ {runtime_dependencies, RDeps} ->
+ check_app_deps(App, AppFile, RDeps, Deps, IgnoreApps)
+ ++ ResOtherApps;
+ false ->
+ Failure = {missing_runtime_dependencies_key, AppFile},
+ case lists:member(App, IgnoreApps) of
+ true ->
+ put(ignored_failures, [Failure | get(ignored_failures)]),
+ ResOtherApps;
+ false ->
+ [Failure | ResOtherApps]
+ end
end.
%%%
%%% Common help functions.
%%%
-
+
print_mfas(Fd, Server, MFAs) ->
[io:format(Fd, "~s\n", [format_mfa(Server, MFA)]) || MFA <- MFAs],
ok.
@@ -537,13 +526,13 @@ format_mfa(Server, MFA) ->
MFAString = format_mfa(MFA),
AQ = "(App)" ++ MFAString,
AppPrefix = case xref:q(Server, AQ) of
- {ok,[App]} -> "[" ++ atom_to_list(App) ++ "]";
- _ -> ""
- end,
+ {ok,[App]} -> "[" ++ atom_to_list(App) ++ "]";
+ _ -> ""
+ end,
AppPrefix ++ MFAString.
open_log(Config, Name) ->
- PrivDir = ?config(priv_dir, Config),
+ PrivDir = proplists:get_value(priv_dir, Config),
RunDir = filename:dirname(filename:dirname(PrivDir)),
Path = filename:join(RunDir, "system_"++Name++".log"),
{ok,Fd} = file:open(Path, [write]),
@@ -554,13 +543,13 @@ close_log(Fd) ->
app_exists(AppAtom) ->
case code:lib_dir(AppAtom) of
- {error,bad_name} ->
- false;
- Path ->
- case file:read_file_info(filename:join(Path,"ebin")) of
- {ok,_} ->
- true;
- _ ->
- false
- end
+ {error,bad_name} ->
+ false;
+ Path ->
+ case file:read_file_info(filename:join(Path,"ebin")) of
+ {ok,_} ->
+ true;
+ _ ->
+ false
+ end
end.
diff --git a/erts/test/run_erl_SUITE.erl b/erts/test/run_erl_SUITE.erl
index e3c563d3d9..47d38bde7c 100644
--- a/erts/test/run_erl_SUITE.erl
+++ b/erts/test/run_erl_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2005-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.
@@ -20,43 +20,19 @@
-module(run_erl_SUITE).
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- init_per_testcase/2,end_per_testcase/2,
- basic/1,heavy/1,heavier/1,defunct/1]).
+-export([all/0, suite/0]).
+-export([basic/1,heavy/1,heavier/1,defunct/1]).
-export([ping_me_back/1]).
-include_lib("common_test/include/ct.hrl").
-init_per_testcase(_Case, Config) ->
- Dog = ?t:timetrap(?t:minutes(2)),
- [{watchdog, Dog}|Config].
-
-end_per_testcase(_Case, Config) ->
- Dog = ?config(watchdog, Config),
- ?t:timetrap_cancel(Dog),
- ok.
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap, {minutes, 2}}].
all() ->
[basic, heavy, heavier, defunct].
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
basic(Config) when is_list(Config) ->
case os:type() of
@@ -65,16 +41,16 @@ basic(Config) when is_list(Config) ->
end.
basic_1(Config) ->
- ?line {Node,Pipe} = do_run_erl(Config, "basic"),
+ {Node,Pipe} = do_run_erl(Config, "basic"),
- ?line ToErl = open_port({spawn,"to_erl "++Pipe}, []),
- ?line erlang:port_command(ToErl, "halt().\r\n"),
+ ToErl = open_port({spawn,"to_erl "++Pipe}, []),
+ erlang:port_command(ToErl, "halt().\r\n"),
receive
{nodedown,Node} ->
- ?line io:format("Down: ~p\n", [Node])
+ io:format("Down: ~p\n", [Node])
after 10000 ->
- ?line ?t:fail()
+ ct:fail(timeout)
end,
ok.
@@ -86,29 +62,28 @@ heavy(Config) when is_list(Config) ->
end.
heavy_1(Config) ->
- ?line {Node,Pipe} = do_run_erl(Config, "heavy"),
+ {Node,Pipe} = do_run_erl(Config, "heavy"),
- ?line ToErl = open_port({spawn,"to_erl "++Pipe}, []),
+ ToErl = open_port({spawn,"to_erl "++Pipe}, []),
IoFormat = "io:format(\"~s\n\", [lists:duplicate(10000, 10)]).\r\n",
- ?line erlang:port_command(ToErl, IoFormat),
- ?line erlang:port_command(ToErl, IoFormat),
- ?line erlang:port_command(ToErl, IoFormat),
- ?line erlang:port_command(ToErl, "init:stop().\r\n"),
+ erlang:port_command(ToErl, IoFormat),
+ erlang:port_command(ToErl, IoFormat),
+ erlang:port_command(ToErl, IoFormat),
+ erlang:port_command(ToErl, "init:stop().\r\n"),
receive
{nodedown,Node} ->
- ?line io:format("Down: ~p\n", [Node])
+ io:format("Down: ~p\n", [Node])
after 10000 ->
- ?line ?t:fail()
+ ct:fail(timeout)
end,
- ?line case count_new_lines(ToErl, 0) of
- Nls when Nls > 30000 ->
- ok;
- Nls ->
- ?line io:format("new_lines: ~p\n", [Nls]),
- ?line ?t:fail()
- end.
+ case count_new_lines(ToErl, 0) of
+ Nls when Nls > 30000 ->
+ ok;
+ Nls ->
+ ct:fail("new_lines: ~p\n", [Nls])
+ end.
ping_me_back([Node]) when is_atom(Node) ->
@@ -137,16 +112,16 @@ heavier(Config) when is_list(Config) ->
end.
heavier_1(Config) ->
- ?line {Node,Pipe} = do_run_erl(Config, "heavier"),
+ {Node,Pipe} = do_run_erl(Config, "heavier"),
- ?line ToErl = open_port({spawn,"to_erl "++Pipe}, []),
+ ToErl = open_port({spawn,"to_erl "++Pipe}, []),
io:format("ToErl = ~p\n", [ToErl]),
Seed = {1,555,42},
rand:seed(exsplus, Seed),
SeedCmd = lists:flatten(io_lib:format("rand:seed(exsplus, ~p). \r\n",
[Seed])),
- ?line io:format("~p\n", [SeedCmd]),
- ?line erlang:port_command(ToErl, SeedCmd),
+ io:format("~p\n", [SeedCmd]),
+ erlang:port_command(ToErl, SeedCmd),
Iter = 1000,
MaxLen = 2048,
@@ -165,19 +140,19 @@ heavier_1(Config) ->
"F(F,"++integer_to_list(Iter)++")."++" \r\n",
- ?line io:format("~p\n", [Random]),
- ?line erlang:port_command(ToErl, Random),
+ io:format("~p\n", [Random]),
+ erlang:port_command(ToErl, Random),
%% Finish.
- ?line erlang:port_command(ToErl, "init:stop().\r\n"),
- ?line receive_all(Iter, ToErl, MaxLen),
+ erlang:port_command(ToErl, "init:stop().\r\n"),
+ receive_all(Iter, ToErl, MaxLen),
receive
{nodedown,Node} ->
- ?line io:format("Down: ~p\n", [Node])
+ io:format("Down: ~p\n", [Node])
after 10000 ->
- ?line c:flush(),
- ?line ?t:fail()
+ c:flush(),
+ ct:fail(timeout)
end,
ok.
@@ -204,9 +179,7 @@ receive_all_2(Iter, {NumChars,Pattern}, Line0, ToErl, MaxLen) ->
%%io:format("Recv: ~p\n", [S]),
receive_all_2(Iter, {NumChars,Pattern}, Line++S, ToErl, MaxLen)
after 10000 ->
- io:format("Timeout waiting for\n~p\ngot\n~p\n",
- [Pattern, Line]),
- ?line ?t:fail()
+ ct:fail("Timeout waiting for\n~p\ngot\n~p\n", [Pattern, Line])
end
end.
@@ -241,49 +214,47 @@ defunct_1(Config) ->
end.
defunct_2(Config, Perl) ->
- ?line Data = ?config(data_dir, Config),
- ?line RunErlTest = filename:join(Data, "run_erl_test.pl"),
- ?line Defuncter = filename:join(Data, "defuncter.pl"),
- ?line Priv = ?config(priv_dir, Config),
- ?line LogDir = filename:join(Priv, "defunct"),
- ?line ok = file:make_dir(LogDir),
- ?line Pipe = LogDir ++ "/",
- ?line RunErl = os:find_executable(run_erl),
- ?line Cmd = Perl ++ " " ++ RunErlTest ++ " \"" ++ RunErl ++ "\" " ++
+ Data = proplists:get_value(data_dir, Config),
+ RunErlTest = filename:join(Data, "run_erl_test.pl"),
+ Defuncter = filename:join(Data, "defuncter.pl"),
+ Priv = proplists:get_value(priv_dir, Config),
+ LogDir = filename:join(Priv, "defunct"),
+ ok = file:make_dir(LogDir),
+ Pipe = LogDir ++ "/",
+ RunErl = os:find_executable(run_erl),
+ Cmd = Perl ++ " " ++ RunErlTest ++ " \"" ++ RunErl ++ "\" " ++
Defuncter ++ " " ++ Pipe ++ " " ++ LogDir,
- ?line io:format("~p", [Cmd]),
- ?line Res = os:cmd(Cmd),
- ?line io:format("~p\n", [Res]),
+ io:format("~p", [Cmd]),
+ Res = os:cmd(Cmd),
+ io:format("~p\n", [Res]),
"OK"++_ = Res,
ok.
%%% Utilities.
do_run_erl(Config, Case) ->
- ?line Priv = ?config(priv_dir, Config),
- ?line LogDir = filename:join(Priv, Case),
- ?line ok = file:make_dir(LogDir),
- ?line Pipe = LogDir ++ "/",
- ?line NodeName = "run_erl_node_" ++ Case,
- ?line Cmd = "run_erl "++Pipe++" "++LogDir++" \"erl -sname " ++ NodeName ++
+ Priv = proplists:get_value(priv_dir, Config),
+ LogDir = filename:join(Priv, Case),
+ ok = file:make_dir(LogDir),
+ Pipe = LogDir ++ "/",
+ NodeName = "run_erl_node_" ++ Case,
+ Cmd = "run_erl "++Pipe++" "++LogDir++" \"erl -sname " ++ NodeName ++
" -pa " ++ filename:dirname(code:which(?MODULE)) ++
" -s " ++ ?MODULE_STRING ++ " ping_me_back " ++
atom_to_list(node()) ++ "\"",
- ?line io:format("~p\n", [Cmd]),
+ io:format("~p\n", [Cmd]),
- ?line net_kernel:monitor_nodes(true),
- ?line open_port({spawn,Cmd}, []),
- ?line [_,Host] = string:tokens(atom_to_list(node()), "@"),
- ?line Node = list_to_atom(NodeName++"@"++Host),
+ net_kernel:monitor_nodes(true),
+ open_port({spawn,Cmd}, []),
+ [_,Host] = string:tokens(atom_to_list(node()), "@"),
+ Node = list_to_atom(NodeName++"@"++Host),
receive
{nodeup,Node} ->
- ?line io:format("Up: ~p\n", [Node]);
+ io:format("Up: ~p\n", [Node]);
Other ->
- ?line io:format("Unexpected: ~p\n", [Other]),
- ?line ?t:fail()
+ ct:fail("Unexpected: ~p\n", [Other])
after 10000 ->
- ?line ?t:fail()
+ ct:fail(timeout)
end,
-
{Node,Pipe}.
diff --git a/erts/test/run_erl_SUITE_data/defuncter.pl b/erts/test/run_erl_SUITE_data/defuncter.pl
index 666d4cca41..0b6771a8bb 100644
--- a/erts/test/run_erl_SUITE_data/defuncter.pl
+++ b/erts/test/run_erl_SUITE_data/defuncter.pl
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2006-2009. All Rights Reserved.
+# Copyright Ericsson AB 2006-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.
diff --git a/erts/test/run_erl_SUITE_data/run_erl_test.pl b/erts/test/run_erl_SUITE_data/run_erl_test.pl
index b9e3f0a363..9560fa3c14 100644
--- a/erts/test/run_erl_SUITE_data/run_erl_test.pl
+++ b/erts/test/run_erl_SUITE_data/run_erl_test.pl
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2006-2009. All Rights Reserved.
+# Copyright Ericsson AB 2006-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.
diff --git a/erts/test/upgrade_SUITE.erl b/erts/test/upgrade_SUITE.erl
index 83cd2359d8..174c028ac7 100644
--- a/erts/test/upgrade_SUITE.erl
+++ b/erts/test/upgrade_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014. All Rights Reserved.
+%% Copyright Ericsson AB 2014-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.
@@ -50,12 +50,12 @@ init_per_suite(Config) ->
%% Fake release, no applications
{skip, "Need a real release running to create other releases"};
_ ->
- rm_rf(filename:join([?config(data_dir,Config),priv_dir])),
+ rm_rf(filename:join([proplists:get_value(data_dir,Config),priv_dir])),
Config
end.
init_per_testcase(Case,Config) ->
- PrivDir = filename:join([?config(data_dir,Config),priv_dir,Case]),
+ PrivDir = filename:join([proplists:get_value(data_dir,Config),priv_dir,Case]),
CreateDir = filename:join([PrivDir,create]),
InstallDir = filename:join([PrivDir,install]),
ok = filelib:ensure_dir(filename:join(CreateDir,"*")),
@@ -66,10 +66,10 @@ init_per_testcase(Case,Config) ->
end_per_testcase(_Case,Config) ->
Nodes = nodes(),
[test_server:stop_node(Node) || Node <- Nodes],
- case ?config(tc_status,Config) of
+ case proplists:get_value(tc_status,Config) of
ok ->
%% Note that priv_dir here is per test case!
- rm_rf(?config(priv_dir,Config));
+ rm_rf(proplists:get_value(priv_dir,Config));
_fail ->
%% Test case data can be found under DataDir/priv_dir/Case
ok
@@ -115,15 +115,15 @@ upgrade_test(FromVsn,ToVsn,Config) ->
case OldRel of
false ->
%% Note that priv_dir here is per test case!
- rm_rf(?config(priv_dir,Config)),
+ rm_rf(proplists:get_value(priv_dir,Config)),
{skip, "no previous release available"};
_ ->
upgrade_test1(FromVsn,ToVsn,[{old_rel,OldRel}|Config])
end.
upgrade_test1(FromVsn,ToVsn,Config) ->
- CreateDir = ?config(create_dir,Config),
- InstallDir = ?config(install_dir,Config),
+ CreateDir = proplists:get_value(create_dir,Config),
+ InstallDir = proplists:get_value(install_dir,Config),
FromRelName = "otp-"++FromVsn,
ToRelName = "otp-"++ToVsn,
@@ -141,7 +141,7 @@ upgrade_test1(FromVsn,ToVsn,Config) ->
%%% - chmod 'start' and 'start_erl'
target_system(RelName0,RelVsn,CreateDir,InstallDir,Config) ->
{ok,Node} = test_server:start_node(list_to_atom(RelName0),peer,
- [{erl,[?config(old_rel,Config)]}]),
+ [{erl,[proplists:get_value(old_rel,Config)]}]),
{RelName,Apps,ErtsVsn} = create_relfile(Node,CreateDir,RelName0,RelVsn),
@@ -184,7 +184,7 @@ target_system(RelName0,RelVsn,CreateDir,InstallDir,Config) ->
write_file(SysConfig, "[]."),
%% Insert 'start' script from data_dir - modified to add sname and heart
- copy_file(filename:join(?config(data_dir,Config),"start.src"),
+ copy_file(filename:join(proplists:get_value(data_dir,Config),"start.src"),
filename:join(ErtsBinDir,"start.src")),
ok = file:change_mode(filename:join(ErtsBinDir,"start.src"),8#0755),
diff --git a/erts/test/upgrade_SUITE_data/start.src b/erts/test/upgrade_SUITE_data/start.src
index 7098a6919a..67d8de8c9e 100644
--- a/erts/test/upgrade_SUITE_data/start.src
+++ b/erts/test/upgrade_SUITE_data/start.src
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2014. All Rights Reserved.
+# Copyright Ericsson AB 2014-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.
diff --git a/erts/test/utils/gccifier.c b/erts/test/utils/gccifier.c
index ca022eb390..0c3ef915fb 100644
--- a/erts/test/utils/gccifier.c
+++ b/erts/test/utils/gccifier.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2004-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.
diff --git a/erts/test/utils/gccifier.sh b/erts/test/utils/gccifier.sh
index 24b4d2f335..9311e34300 100755
--- a/erts/test/utils/gccifier.sh
+++ b/erts/test/utils/gccifier.sh
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2005-2012. All Rights Reserved.
+# Copyright Ericsson AB 2005-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.
diff --git a/erts/test/z_SUITE.erl b/erts/test/z_SUITE.erl
index 7f3260e4cb..281a47134f 100644
--- a/erts/test/z_SUITE.erl
+++ b/erts/test/z_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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.
@@ -24,8 +24,6 @@
%% This suite expects to be run as the last suite of all suites.
%%
-%-define(line_trace, 1).
-
-include_lib("kernel/include/file.hrl").
-record(core_search_conf, {search_dir,
@@ -34,52 +32,19 @@
file,
run_by_ts}).
--define(DEFAULT_TIMEOUT, ?t:minutes(5)).
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- init_per_testcase/2, end_per_testcase/2]).
+-export([all/0, suite/0]).
-export([search_for_core_files/1, core_files/1]).
-include_lib("common_test/include/ct.hrl").
-
-init_per_testcase(Case, Config) ->
- Dog = ?t:timetrap(?DEFAULT_TIMEOUT),
- [{testcase, Case}, {watchdog, Dog} |Config].
-
-end_per_testcase(_Case, Config) ->
- Dog = ?config(watchdog, Config),
- ?t:timetrap_cancel(Dog),
- ok.
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap, {minutes, 5}}].
all() ->
[core_files].
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-
-core_files(doc) ->
- [];
-core_files(suite) ->
- [];
core_files(Config) when is_list(Config) ->
case os:type() of
{win32, _} ->
@@ -354,7 +319,7 @@ core_file_search(#core_search_conf{search_dir = Base,
case {RunByTS, ICores, FCores} of
{true, [], []} -> ok;
{true, _, []} -> {comment, Res};
- {true, _, _} -> ?t:fail(Res);
+ {true, _, _} -> ct:fail(Res);
_ -> Res
end
end.