aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--.travis.yml62
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--HOWTO/INSTALL-RASPBERRYPI3.md323
-rw-r--r--HOWTO/INSTALL.md2
-rw-r--r--Makefile.in43
-rw-r--r--OTP_VERSION2
-rw-r--r--bootstrap/bin/no_dot_erlang.bootbin6292 -> 6374 bytes
-rw-r--r--bootstrap/bin/start.bootbin6292 -> 6374 bytes
-rw-r--r--bootstrap/bin/start_clean.bootbin6292 -> 6374 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_dead.beambin13804 -> 13892 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_disasm.beambin21676 -> 21728 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_jump.beambin8984 -> 9132 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_peep.beambin3004 -> 3036 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_trim.beambin7508 -> 7540 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_type.beambin18692 -> 18744 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_utils.beambin22468 -> 22624 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_validator.beambin31796 -> 31848 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl.beambin30144 -> 30144 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl_inline.beambin37816 -> 37800 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/compile.beambin41364 -> 41384 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/compiler.appup2
-rw-r--r--bootstrap/lib/compiler/ebin/core_lint.beambin12872 -> 12880 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/erl_bifs.beambin2104 -> 2204 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/rec_env.beambin4584 -> 4588 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_fold.beambin47916 -> 47536 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_inline.beambin3980 -> 3992 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_codegen.beambin65360 -> 65424 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application_controller.beambin31272 -> 31400 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/code_server.beambin24140 -> 24136 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/disk_log.beambin31768 -> 32124 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/dist_util.beambin13028 -> 13044 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_ddll.beambin2856 -> 2864 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_epmd.beambin7176 -> 7248 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_signal_handler.beambin956 -> 1112 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/error_logger.beambin5412 -> 6132 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/file_io_server.beambin15700 -> 15708 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet.beambin23616 -> 23632 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_db.beambin26404 -> 26440 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_dns.beambin19112 -> 19268 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_parse.beambin13792 -> 13828 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_tcp_dist.beambin7288 -> 7700 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/kernel.app6
-rw-r--r--bootstrap/lib/kernel/ebin/kernel.beambin3672 -> 3596 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger.beambin11484 -> 11312 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_backend.beambin2600 -> 2620 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_config.beambin2940 -> 3428 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_disk_log_h.beambin8508 -> 9460 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_filters.beambin1760 -> 1800 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_formatter.beambin5736 -> 7796 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_h_common.beambin5116 -> 5672 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_server.beambin7208 -> 10476 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_simple.beambin4524 -> 0 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_simple_h.beambin0 -> 4464 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_std_h.beambin10132 -> 10872 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/net_kernel.beambin25560 -> 25644 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/ram_file.beambin6244 -> 6248 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_utils.beambin27260 -> 27380 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_v9.beambin47804 -> 47832 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/epp.beambin27716 -> 29720 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_anno.beambin3616 -> 3628 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_error.beambin0 -> 8368 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_eval.beambin30260 -> 35988 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_expand_records.beambin21732 -> 21760 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_internal.beambin7012 -> 7808 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_lint.beambin91848 -> 91872 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_scan.beambin27868 -> 28204 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/escript.beambin16824 -> 16832 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/ets.beambin22280 -> 22460 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/filename.beambin15096 -> 15144 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_event.beambin13984 -> 13972 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_fsm.beambin11636 -> 11476 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_server.beambin15008 -> 15012 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_statem.beambin20528 -> 20676 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io.beambin6020 -> 6044 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io_lib_pretty.beambin21948 -> 21956 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/lib.beambin14936 -> 0 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/maps.beambin3464 -> 3552 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/ms_transform.beambin19468 -> 19532 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/otp_internal.beambin10284 -> 10596 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/proc_lib.beambin12436 -> 12448 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/qlc.beambin68808 -> 68896 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/shell.beambin29804 -> 29848 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/slave.beambin4740 -> 4816 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/stdlib.app4
-rw-r--r--bootstrap/lib/stdlib/ebin/string.beambin35068 -> 37096 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/supervisor.beambin23348 -> 23352 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/supervisor_bridge.beambin2412 -> 2400 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/unicode.beambin13448 -> 13456 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/uri_string.beambin26712 -> 26396 bytes
-rw-r--r--bootstrap/lib/stdlib/include/assert.hrl6
-rw-r--r--configure.in2
-rw-r--r--erts/aclocal.m410
-rwxr-xr-xerts/autoconf/configure.vxworks5
-rw-r--r--erts/autoconf/vxworks/sed.general5
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_cpu321
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_ppc321
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_ppc6031
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_ppc603_nolongcall1
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_ppc8601
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_simlinux1
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_simso1
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_sparc1
-rw-r--r--erts/configure.in595
-rw-r--r--erts/doc/src/Makefile4
-rw-r--r--erts/doc/src/absform.xml3
-rw-r--r--erts/doc/src/alt_disco.xml93
-rw-r--r--erts/doc/src/alt_dist.xml2
-rw-r--r--erts/doc/src/driver_entry.xml2
-rw-r--r--erts/doc/src/erl.xml8
-rw-r--r--erts/doc/src/erl_dist_protocol.xml2
-rw-r--r--erts/doc/src/erl_driver.xml2
-rw-r--r--erts/doc/src/erl_nif.xml14
-rw-r--r--erts/doc/src/erlang.xml285
-rw-r--r--erts/doc/src/erlc.xml2
-rw-r--r--erts/doc/src/erts_alloc.xml13
-rw-r--r--erts/doc/src/match_spec.xml2
-rw-r--r--erts/doc/src/notes.xml1240
-rw-r--r--erts/doc/src/part.xml3
-rw-r--r--erts/doc/src/run_erl.xml2
-rw-r--r--erts/doc/src/time_correction.xml2
-rw-r--r--erts/emulator/Makefile.in4
-rw-r--r--erts/emulator/beam/atom.c2
-rw-r--r--erts/emulator/beam/atom.h2
-rw-r--r--erts/emulator/beam/atom.names3
-rw-r--r--erts/emulator/beam/beam_bif_load.c37
-rw-r--r--erts/emulator/beam/beam_debug.c5
-rw-r--r--erts/emulator/beam/beam_emu.c38
-rw-r--r--erts/emulator/beam/beam_load.c52
-rw-r--r--erts/emulator/beam/beam_ranges.c8
-rw-r--r--erts/emulator/beam/bif.c183
-rw-r--r--erts/emulator/beam/bif.h37
-rw-r--r--erts/emulator/beam/bif.tab14
-rw-r--r--erts/emulator/beam/bif_instrs.tab2
-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.c1
-rw-r--r--erts/emulator/beam/bs_instrs.tab2
-rw-r--r--erts/emulator/beam/code_ix.c2
-rw-r--r--erts/emulator/beam/copy.c2
-rw-r--r--erts/emulator/beam/dist.c422
-rw-r--r--erts/emulator/beam/erl_afit_alloc.c2
-rw-r--r--erts/emulator/beam/erl_alloc.c280
-rw-r--r--erts/emulator/beam/erl_alloc.h35
-rw-r--r--erts/emulator/beam/erl_alloc.types36
-rw-r--r--erts/emulator/beam/erl_alloc_util.c752
-rw-r--r--erts/emulator/beam/erl_alloc_util.h87
-rw-r--r--erts/emulator/beam/erl_ao_firstfit_alloc.c82
-rw-r--r--erts/emulator/beam/erl_ao_firstfit_alloc.h13
-rw-r--r--erts/emulator/beam/erl_arith.c2
-rw-r--r--erts/emulator/beam/erl_async.c2
-rw-r--r--erts/emulator/beam/erl_bestfit_alloc.c2
-rw-r--r--erts/emulator/beam/erl_bif_binary.c71
-rw-r--r--erts/emulator/beam/erl_bif_chksum.c4
-rw-r--r--erts/emulator/beam/erl_bif_ddll.c4
-rw-r--r--erts/emulator/beam/erl_bif_info.c242
-rw-r--r--erts/emulator/beam/erl_bif_re.c2
-rw-r--r--erts/emulator/beam/erl_bif_trace.c194
-rw-r--r--erts/emulator/beam/erl_bif_unique.h2
-rw-r--r--erts/emulator/beam/erl_binary.h6
-rw-r--r--erts/emulator/beam/erl_bits.h2
-rw-r--r--erts/emulator/beam/erl_db.c640
-rw-r--r--erts/emulator/beam/erl_db.h11
-rw-r--r--erts/emulator/beam/erl_db_hash.c958
-rw-r--r--erts/emulator/beam/erl_db_hash.h22
-rw-r--r--erts/emulator/beam/erl_db_tree.c66
-rw-r--r--erts/emulator/beam/erl_db_tree.h2
-rw-r--r--erts/emulator/beam/erl_db_util.c10
-rw-r--r--erts/emulator/beam/erl_db_util.h18
-rw-r--r--erts/emulator/beam/erl_dirty_bif.tab2
-rw-r--r--erts/emulator/beam/erl_drv_thread.c2
-rw-r--r--erts/emulator/beam/erl_gc.c15
-rw-r--r--erts/emulator/beam/erl_goodfit_alloc.c2
-rw-r--r--erts/emulator/beam/erl_init.c3
-rw-r--r--erts/emulator/beam/erl_io_queue.c2
-rw-r--r--erts/emulator/beam/erl_lock_check.h2
-rw-r--r--erts/emulator/beam/erl_lock_count.h2
-rw-r--r--erts/emulator/beam/erl_map.c101
-rw-r--r--erts/emulator/beam/erl_message.c23
-rw-r--r--erts/emulator/beam/erl_message.h6
-rw-r--r--erts/emulator/beam/erl_monitor_link.c97
-rw-r--r--erts/emulator/beam/erl_monitor_link.h57
-rw-r--r--erts/emulator/beam/erl_msacc.c2
-rw-r--r--erts/emulator/beam/erl_msacc.h2
-rw-r--r--erts/emulator/beam/erl_mtrace.c2
-rw-r--r--erts/emulator/beam/erl_nfunc_sched.c2
-rw-r--r--erts/emulator/beam/erl_nfunc_sched.h2
-rw-r--r--erts/emulator/beam/erl_nif.c72
-rw-r--r--erts/emulator/beam/erl_nif.h2
-rw-r--r--erts/emulator/beam/erl_nif_api_funcs.h2
-rw-r--r--erts/emulator/beam/erl_node_container_utils.h2
-rw-r--r--erts/emulator/beam/erl_port_task.c7
-rw-r--r--erts/emulator/beam/erl_printf_term.c2
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.c599
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.h171
-rw-r--r--erts/emulator/beam/erl_process.c1218
-rw-r--r--erts/emulator/beam/erl_process.h59
-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.c6
-rw-r--r--erts/emulator/beam/erl_process_lock.h18
-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_thr_progress.c2
-rw-r--r--erts/emulator/beam/erl_thr_progress.h2
-rw-r--r--erts/emulator/beam/erl_thr_queue.c2
-rw-r--r--erts/emulator/beam/erl_thr_queue.h2
-rw-r--r--erts/emulator/beam/erl_time_sup.c2
-rw-r--r--erts/emulator/beam/erl_trace.c48
-rw-r--r--erts/emulator/beam/erl_trace.h4
-rw-r--r--erts/emulator/beam/erl_unicode.c10
-rw-r--r--erts/emulator/beam/erl_utils.h2
-rw-r--r--erts/emulator/beam/erl_vm.h2
-rw-r--r--erts/emulator/beam/erlang_dtrace.d2
-rw-r--r--erts/emulator/beam/erlang_lttng.h2
-rw-r--r--erts/emulator/beam/export.h2
-rw-r--r--erts/emulator/beam/external.c2
-rw-r--r--erts/emulator/beam/hash.c2
-rw-r--r--erts/emulator/beam/instrs.tab2
-rw-r--r--erts/emulator/beam/io.c5
-rw-r--r--erts/emulator/beam/lttng-wrapper.h2
-rw-r--r--erts/emulator/beam/module.c2
-rw-r--r--erts/emulator/beam/module.h2
-rw-r--r--erts/emulator/beam/ops.tab7
-rw-r--r--erts/emulator/beam/packet_parser.c2
-rw-r--r--erts/emulator/beam/register.c2
-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.h2
-rw-r--r--erts/emulator/beam/utils.c15
-rw-r--r--erts/emulator/drivers/common/gzio.h2
-rw-r--r--erts/emulator/drivers/common/inet_drv.c52
-rw-r--r--erts/emulator/drivers/unix/ttsl_drv.c4
-rw-r--r--erts/emulator/hipe/hipe_amd64.c2
-rw-r--r--erts/emulator/hipe/hipe_amd64_bifs.m42
-rw-r--r--erts/emulator/hipe/hipe_arm_bifs.m42
-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_bif_list.m42
-rw-r--r--erts/emulator/hipe/hipe_debug.c2
-rw-r--r--erts/emulator/hipe/hipe_gc.c2
-rw-r--r--erts/emulator/hipe/hipe_mode_switch.c15
-rw-r--r--erts/emulator/hipe/hipe_native_bif.c23
-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_bifs.m42
-rw-r--r--erts/emulator/hipe/hipe_primops.h2
-rw-r--r--erts/emulator/hipe/hipe_process.h11
-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_bifs.m42
-rw-r--r--erts/emulator/hipe/hipe_x86_bifs.m42
-rw-r--r--erts/emulator/hipe/hipe_x86_stack.c2
-rw-r--r--erts/emulator/internal_doc/CarrierMigration.md19
-rw-r--r--erts/emulator/nifs/common/prim_file_nif.c2
-rw-r--r--erts/emulator/nifs/common/prim_file_nif.h2
-rw-r--r--erts/emulator/nifs/unix/unix_prim_file.c2
-rw-r--r--erts/emulator/nifs/win32/win_prim_file.c2
-rw-r--r--erts/emulator/sys/common/erl_check_io.c1
-rw-r--r--erts/emulator/sys/common/erl_mmap.c6
-rw-r--r--erts/emulator/sys/common/erl_mmap.h2
-rw-r--r--erts/emulator/sys/common/erl_mseg.c2
-rw-r--r--erts/emulator/sys/common/erl_mseg.h2
-rw-r--r--erts/emulator/sys/common/erl_os_monotonic_time_extender.c2
-rw-r--r--erts/emulator/sys/common/erl_os_monotonic_time_extender.h2
-rw-r--r--erts/emulator/sys/common/erl_osenv.c10
-rw-r--r--erts/emulator/sys/common/erl_poll.c52
-rw-r--r--erts/emulator/sys/common/erl_poll.h2
-rw-r--r--erts/emulator/sys/common/erl_poll_api.h2
-rw-r--r--erts/emulator/sys/common/erl_sys_common_misc.c2
-rw-r--r--erts/emulator/sys/unix/erl_child_setup.c2
-rw-r--r--erts/emulator/sys/unix/erl_unix_sys.h12
-rw-r--r--erts/emulator/sys/unix/sys.c4
-rw-r--r--erts/emulator/sys/unix/sys_drivers.c111
-rw-r--r--erts/emulator/sys/unix/sys_float.c2
-rw-r--r--erts/emulator/sys/unix/sys_time.c2
-rw-r--r--erts/emulator/sys/unix/sys_uds.c15
-rw-r--r--erts/emulator/sys/unix/sys_uds.h2
-rw-r--r--erts/emulator/sys/win32/erl_poll.c18
-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_interrupt.c2
-rw-r--r--erts/emulator/sys/win32/sys_time.c2
-rw-r--r--erts/emulator/test/alloc_SUITE.erl5
-rw-r--r--erts/emulator/test/alloc_SUITE_data/migration.c2
-rw-r--r--erts/emulator/test/beam_SUITE.erl2
-rw-r--r--erts/emulator/test/beam_literals_SUITE.erl2
-rw-r--r--erts/emulator/test/bif_SUITE.erl16
-rw-r--r--erts/emulator/test/big_SUITE.erl2
-rw-r--r--erts/emulator/test/binary_SUITE.erl2
-rw-r--r--erts/emulator/test/call_trace_SUITE.erl2
-rw-r--r--erts/emulator/test/code_SUITE.erl28
-rw-r--r--erts/emulator/test/code_SUITE_data/literals.erl8
-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.erl15
-rw-r--r--erts/emulator/test/driver_SUITE.erl45
-rw-r--r--erts/emulator/test/driver_SUITE_data/ioq_exit_drv.c2
-rw-r--r--erts/emulator/test/dump_SUITE.erl2
-rw-r--r--erts/emulator/test/efile_SUITE.erl2
-rw-r--r--erts/emulator/test/erts_debug_SUITE.erl31
-rw-r--r--erts/emulator/test/exception_SUITE.erl2
-rw-r--r--erts/emulator/test/fun_SUITE.erl18
-rw-r--r--erts/emulator/test/iovec_SUITE.erl2
-rw-r--r--erts/emulator/test/lcnt_SUITE.erl2
-rw-r--r--erts/emulator/test/map_SUITE.erl11
-rw-r--r--erts/emulator/test/match_spec_SUITE.erl2
-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/nif_SUITE.erl77
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_SUITE.c12
-rw-r--r--erts/emulator/test/num_bif_SUITE.erl2
-rw-r--r--erts/emulator/test/port_SUITE.erl8
-rw-r--r--erts/emulator/test/process_SUITE.erl62
-rw-r--r--erts/emulator/test/ref_SUITE.erl28
-rw-r--r--erts/emulator/test/register_SUITE.erl2
-rw-r--r--erts/emulator/test/sensitive_SUITE.erl4
-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.erl32
-rw-r--r--erts/emulator/test/system_profile_SUITE.erl88
-rw-r--r--erts/emulator/test/timer_bif_SUITE.erl4
-rw-r--r--erts/emulator/test/trace_SUITE.erl86
-rw-r--r--erts/emulator/test/tracer_SUITE.erl8
-rw-r--r--erts/emulator/test/tuple_SUITE.erl2
-rw-r--r--erts/emulator/test/z_SUITE.erl2
-rwxr-xr-xerts/emulator/utils/make_driver_tab2
-rwxr-xr-xerts/emulator/utils/make_tables2
-rw-r--r--erts/etc/common/erlexec.c2
-rw-r--r--erts/etc/common/escript.c15
-rw-r--r--erts/etc/common/heart.c2
-rw-r--r--erts/etc/unix/cerl.src28
-rw-r--r--erts/etc/unix/dyn_erl.c2
-rw-r--r--erts/etc/unix/etp-commands.in186
-rw-r--r--erts/include/internal/erl_printf.h2
-rw-r--r--erts/include/internal/gcc/ethr_membar.h2
-rw-r--r--erts/lib_src/Makefile.in4
-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/preloaded/ebin/erl_prim_loader.beambin54432 -> 54452 bytes
-rw-r--r--erts/preloaded/ebin/erl_tracer.beambin2168 -> 2188 bytes
-rw-r--r--erts/preloaded/ebin/erlang.beambin101844 -> 101860 bytes
-rw-r--r--erts/preloaded/ebin/erts_code_purger.beambin11348 -> 11372 bytes
-rw-r--r--erts/preloaded/ebin/erts_dirty_process_signal_handler.beambin2720 -> 2760 bytes
-rw-r--r--erts/preloaded/ebin/erts_internal.beambin15584 -> 16676 bytes
-rw-r--r--erts/preloaded/ebin/erts_literal_area_collector.beambin3268 -> 3288 bytes
-rw-r--r--erts/preloaded/ebin/init.beambin51408 -> 51428 bytes
-rw-r--r--erts/preloaded/ebin/otp_ring0.beambin1404 -> 1424 bytes
-rw-r--r--erts/preloaded/ebin/prim_buffer.beambin3568 -> 3588 bytes
-rw-r--r--erts/preloaded/ebin/prim_eval.beambin1472 -> 1496 bytes
-rw-r--r--erts/preloaded/ebin/prim_file.beambin27724 -> 27800 bytes
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin77884 -> 77932 bytes
-rw-r--r--erts/preloaded/ebin/prim_zip.beambin22864 -> 22892 bytes
-rw-r--r--erts/preloaded/ebin/zlib.beambin19704 -> 19760 bytes
-rw-r--r--erts/preloaded/src/erl_prim_loader.erl2
-rw-r--r--erts/preloaded/src/erlang.erl349
-rw-r--r--erts/preloaded/src/erts.app.src2
-rw-r--r--erts/preloaded/src/erts_code_purger.erl4
-rw-r--r--erts/preloaded/src/erts_dirty_process_signal_handler.erl34
-rw-r--r--erts/preloaded/src/erts_internal.erl49
-rw-r--r--erts/preloaded/src/init.erl2
-rw-r--r--erts/preloaded/src/prim_file.erl25
-rw-r--r--erts/preloaded/src/prim_inet.erl4
-rw-r--r--erts/preloaded/src/prim_zip.erl2
-rw-r--r--erts/preloaded/src/zlib.erl50
-rw-r--r--erts/test/erlc_SUITE.erl6
-rw-r--r--erts/test/erlexec_SUITE.erl2
-rw-r--r--erts/test/nt_SUITE.erl2
-rw-r--r--erts/test/otp_SUITE.erl2
-rw-r--r--erts/test/run_erl_SUITE.erl2
-rw-r--r--erts/test/upgrade_SUITE.erl4
-rw-r--r--erts/test/z_SUITE.erl2
-rw-r--r--erts/vsn.mk4
-rw-r--r--lib/Makefile2
-rw-r--r--lib/asn1/c_src/asn1_erl_nif.c10
-rw-r--r--lib/asn1/doc/src/Makefile3
-rw-r--r--lib/asn1/doc/src/notes.xml39
-rw-r--r--lib/asn1/src/asn1ct.erl2
-rw-r--r--lib/asn1/src/asn1ct_check.erl2
-rw-r--r--lib/asn1/src/asn1ct_gen.erl2
-rw-r--r--lib/asn1/src/asn1rtt_real_common.erl2
-rw-r--r--lib/asn1/test/asn1_SUITE.erl45
-rw-r--r--lib/asn1/test/asn1_SUITE_data/IN-CS-1-Datatypes.asn2
-rw-r--r--lib/asn1/test/testUniqueObjectSets.erl2
-rw-r--r--lib/asn1/test/test_modified_x420.erl2
-rw-r--r--lib/asn1/vsn.mk2
-rw-r--r--lib/common_test/doc/src/Makefile1
-rw-r--r--lib/common_test/doc/src/ct.xml14
-rw-r--r--lib/common_test/doc/src/ct_ftp.xml2
-rw-r--r--lib/common_test/doc/src/ct_hooks.xml2
-rw-r--r--lib/common_test/doc/src/ct_hooks_chapter.xml45
-rw-r--r--lib/common_test/doc/src/notes.xml34
-rw-r--r--lib/common_test/src/Makefile2
-rw-r--r--lib/common_test/src/common_test.app.src2
-rw-r--r--lib/common_test/src/ct.erl943
-rw-r--r--lib/common_test/src/ct_config.erl2
-rw-r--r--lib/common_test/src/ct_config_plain.erl2
-rw-r--r--lib/common_test/src/ct_cover.erl42
-rw-r--r--lib/common_test/src/ct_default_gl.erl2
-rw-r--r--lib/common_test/src/ct_event.erl8
-rw-r--r--lib/common_test/src/ct_framework.erl48
-rw-r--r--lib/common_test/src/ct_ftp.erl135
-rw-r--r--lib/common_test/src/ct_gen_conn.erl97
-rw-r--r--lib/common_test/src/ct_groups.erl10
-rw-r--r--lib/common_test/src/ct_hooks.erl12
-rw-r--r--lib/common_test/src/ct_hooks_lock.erl14
-rw-r--r--lib/common_test/src/ct_logs.erl249
-rw-r--r--lib/common_test/src/ct_master.erl112
-rw-r--r--lib/common_test/src/ct_master_event.erl8
-rw-r--r--lib/common_test/src/ct_master_logs.erl8
-rw-r--r--lib/common_test/src/ct_master_status.erl8
-rw-r--r--lib/common_test/src/ct_netconfc.hrl6
-rw-r--r--lib/common_test/src/ct_property_test.erl63
-rw-r--r--lib/common_test/src/ct_release_test.erl176
-rw-r--r--lib/common_test/src/ct_repeat.erl8
-rw-r--r--lib/common_test/src/ct_rpc.erl112
-rw-r--r--lib/common_test/src/ct_run.erl72
-rw-r--r--lib/common_test/src/ct_slave.erl190
-rw-r--r--lib/common_test/src/ct_snmp.erl289
-rw-r--r--lib/common_test/src/ct_ssh.erl616
-rw-r--r--lib/common_test/src/ct_telnet.erl411
-rw-r--r--lib/common_test/src/ct_testspec.erl6
-rw-r--r--lib/common_test/src/ct_util.erl110
-rw-r--r--lib/common_test/src/ct_webtool.erl2
-rw-r--r--lib/common_test/src/ct_webtool_sup.erl2
-rw-r--r--lib/common_test/src/cth_log_redirect.erl28
-rw-r--r--lib/common_test/src/cth_surefire.erl8
-rw-r--r--lib/common_test/src/test_server.erl2
-rw-r--r--lib/common_test/src/test_server_ctrl.erl8
-rw-r--r--lib/common_test/src/test_server_node.erl10
-rw-r--r--lib/common_test/src/test_server_sup.erl2
-rw-r--r--lib/common_test/src/unix_telnet.erl62
-rw-r--r--lib/common_test/src/vts.erl2
-rw-r--r--lib/common_test/test/ct_auto_clean_SUITE.erl2
-rw-r--r--lib/common_test/test/ct_auto_clean_SUITE_data/ac_SUITE.erl2
-rw-r--r--lib/common_test/test/ct_auto_clean_SUITE_data/cth_auto_clean.erl2
-rw-r--r--lib/common_test/test/ct_auto_compile_SUITE.erl4
-rw-r--r--lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl6
-rw-r--r--lib/common_test/test/ct_error_SUITE_data/error/test/verify_config.erl38
-rw-r--r--lib/common_test/test/ct_event_handler_SUITE_data/eh_A.erl8
-rw-r--r--lib/common_test/test/ct_hooks_SUITE.erl2
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_per_tc_cth_SUITE.erl22
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/cth_log_SUITE.erl2
-rw-r--r--lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl42
-rw-r--r--lib/common_test/test/ct_log_SUITE.erl2
-rw-r--r--lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl10
-rw-r--r--lib/common_test/test/ct_netconfc_SUITE_data/ns.erl2
-rw-r--r--lib/common_test/test/ct_pre_post_test_io_SUITE.erl2
-rw-r--r--lib/common_test/test/ct_priv_dir_SUITE_data/priv_dir_SUITE.erl2
-rw-r--r--lib/common_test/test/ct_repeat_testrun_SUITE_data/a_test/r1_SUITE.erl10
-rw-r--r--lib/common_test/test/ct_repeat_testrun_SUITE_data/b_test/r2_SUITE.erl10
-rw-r--r--lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE.erl6
-rw-r--r--lib/common_test/test/ct_surefire_SUITE_data/surefire_SUITE.erl6
-rw-r--r--lib/common_test/test/ct_test_support.erl6
-rw-r--r--lib/common_test/test/ct_test_support_eh.erl8
-rw-r--r--lib/common_test/test/ct_unicode_SUITE_data/unicode_atoms_SUITE.erl2
-rw-r--r--lib/common_test/test/ct_userconfig_callback.erl2
-rw-r--r--lib/common_test/test/ct_verbosity_SUITE_data/simple_evh.erl8
-rw-r--r--lib/common_test/test/test_server_SUITE.erl13
-rw-r--r--lib/common_test/test/test_server_test_lib.erl2
-rw-r--r--lib/common_test/test_server/ts.erl2
-rw-r--r--lib/common_test/test_server/ts_autoconf_win32.erl2
-rw-r--r--lib/common_test/test_server/ts_erl_config.erl12
-rw-r--r--lib/common_test/test_server/ts_install_cth.erl34
-rw-r--r--lib/common_test/test_server/ts_lib.erl2
-rw-r--r--lib/common_test/test_server/ts_run.erl10
-rw-r--r--lib/common_test/vsn.mk2
-rw-r--r--lib/compiler/doc/src/Makefile1
-rw-r--r--lib/compiler/doc/src/compile.xml2
-rw-r--r--lib/compiler/doc/src/notes.xml301
-rw-r--r--lib/compiler/src/Makefile2
-rw-r--r--lib/compiler/src/beam_a.erl2
-rw-r--r--lib/compiler/src/beam_asm.erl4
-rw-r--r--lib/compiler/src/beam_block.erl2
-rw-r--r--lib/compiler/src/beam_bs.erl2
-rw-r--r--lib/compiler/src/beam_bsm.erl15
-rw-r--r--lib/compiler/src/beam_clean.erl2
-rw-r--r--lib/compiler/src/beam_dead.erl2
-rw-r--r--lib/compiler/src/beam_disasm.erl2
-rw-r--r--lib/compiler/src/beam_disasm.hrl2
-rw-r--r--lib/compiler/src/beam_except.erl2
-rw-r--r--lib/compiler/src/beam_flatten.erl2
-rw-r--r--lib/compiler/src/beam_jump.erl23
-rw-r--r--lib/compiler/src/beam_listing.erl2
-rw-r--r--lib/compiler/src/beam_peep.erl2
-rw-r--r--lib/compiler/src/beam_receive.erl2
-rw-r--r--lib/compiler/src/beam_reorder.erl2
-rw-r--r--lib/compiler/src/beam_split.erl2
-rw-r--r--lib/compiler/src/beam_type.erl4
-rw-r--r--lib/compiler/src/beam_utils.erl15
-rw-r--r--lib/compiler/src/beam_validator.erl36
-rw-r--r--lib/compiler/src/beam_z.erl2
-rw-r--r--lib/compiler/src/compile.erl33
-rw-r--r--lib/compiler/src/core_lint.erl2
-rw-r--r--lib/compiler/src/core_parse.yrl2
-rw-r--r--lib/compiler/src/core_pp.erl2
-rw-r--r--lib/compiler/src/erl_bifs.erl3
-rwxr-xr-xlib/compiler/src/genop.tab5
-rw-r--r--lib/compiler/src/sys_core_alias.erl2
-rw-r--r--lib/compiler/src/sys_core_bsm.erl2
-rw-r--r--lib/compiler/src/sys_core_dsetel.erl2
-rw-r--r--lib/compiler/src/sys_core_fold.erl175
-rw-r--r--lib/compiler/src/sys_core_inline.erl6
-rw-r--r--lib/compiler/src/v3_codegen.erl7
-rw-r--r--lib/compiler/src/v3_core.erl38
-rw-r--r--lib/compiler/src/v3_kernel.erl2
-rw-r--r--lib/compiler/src/v3_kernel.hrl2
-rw-r--r--lib/compiler/src/v3_kernel_pp.erl2
-rw-r--r--lib/compiler/test/andor_SUITE.erl2
-rw-r--r--lib/compiler/test/apply_SUITE.erl2
-rw-r--r--lib/compiler/test/beam_block_SUITE.erl4
-rw-r--r--lib/compiler/test/beam_except_SUITE.erl2
-rw-r--r--lib/compiler/test/beam_jump_SUITE.erl2
-rw-r--r--lib/compiler/test/beam_reorder_SUITE.erl2
-rw-r--r--lib/compiler/test/beam_type_SUITE.erl36
-rw-r--r--lib/compiler/test/beam_utils_SUITE.erl52
-rw-r--r--lib/compiler/test/beam_validator_SUITE.erl4
-rw-r--r--lib/compiler/test/bif_SUITE.erl2
-rw-r--r--lib/compiler/test/bs_bincomp_SUITE.erl13
-rw-r--r--lib/compiler/test/bs_bit_binaries_SUITE.erl4
-rw-r--r--lib/compiler/test/bs_construct_SUITE.erl8
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl47
-rw-r--r--lib/compiler/test/bs_utf_SUITE.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE_data/opt_crash.erl2
-rw-r--r--lib/compiler/test/compile_SUITE.erl25
-rw-r--r--lib/compiler/test/compile_SUITE_data/big.erl2
-rw-r--r--lib/compiler/test/core_SUITE.erl10
-rw-r--r--lib/compiler/test/core_SUITE_data/fun_letrec_effect.core25
-rw-r--r--lib/compiler/test/core_SUITE_data/name_capture.core110
-rw-r--r--lib/compiler/test/core_alias_SUITE.erl2
-rw-r--r--lib/compiler/test/core_fold_SUITE.erl45
-rw-r--r--lib/compiler/test/error_SUITE.erl2
-rw-r--r--lib/compiler/test/float_SUITE.erl2
-rw-r--r--lib/compiler/test/fun_SUITE.erl4
-rw-r--r--lib/compiler/test/guard_SUITE.erl2
-rw-r--r--lib/compiler/test/inline_SUITE.erl2
-rw-r--r--lib/compiler/test/lc_SUITE.erl4
-rw-r--r--lib/compiler/test/map_SUITE.erl61
-rw-r--r--lib/compiler/test/match_SUITE.erl4
-rw-r--r--lib/compiler/test/misc_SUITE.erl4
-rw-r--r--lib/compiler/test/overridden_bif_SUITE.erl2
-rw-r--r--lib/compiler/test/receive_SUITE.erl81
-rw-r--r--lib/compiler/test/record_SUITE.erl2
-rw-r--r--lib/compiler/test/regressions_SUITE.erl19
-rw-r--r--lib/compiler/test/trycatch_SUITE.erl4
-rw-r--r--lib/compiler/test/warnings_SUITE.erl2
-rw-r--r--lib/compiler/test/z_SUITE.erl4
-rw-r--r--lib/compiler/vsn.mk2
-rw-r--r--lib/crypto/c_src/crypto.c577
-rw-r--r--lib/crypto/c_src/otp_test_engine.c2
-rw-r--r--lib/crypto/doc/src/Makefile1
-rw-r--r--lib/crypto/doc/src/crypto.xml6
-rw-r--r--lib/crypto/doc/src/engine_keys.xml2
-rw-r--r--lib/crypto/doc/src/notes.xml81
-rw-r--r--lib/crypto/doc/src/usersguide.xml2
-rw-r--r--lib/crypto/src/Makefile2
-rw-r--r--lib/crypto/src/crypto.erl30
-rw-r--r--lib/crypto/src/crypto_ec_curves.erl36
-rw-r--r--lib/crypto/test/blowfish_SUITE.erl2
-rw-r--r--lib/crypto/test/crypto_SUITE.erl157
-rw-r--r--lib/crypto/test/engine_SUITE.erl4
-rw-r--r--lib/crypto/vsn.mk2
-rw-r--r--lib/debugger/doc/src/Makefile3
-rw-r--r--lib/debugger/doc/src/notes.xml17
-rw-r--r--lib/debugger/src/dbg_debugged.erl2
-rw-r--r--lib/debugger/src/dbg_icmd.erl6
-rw-r--r--lib/debugger/src/dbg_ieval.erl2
-rw-r--r--lib/debugger/src/dbg_wx_mon.erl2
-rw-r--r--lib/debugger/src/dbg_wx_trace.erl6
-rw-r--r--lib/debugger/src/dbg_wx_win.erl4
-rw-r--r--lib/debugger/src/debugger.app.src2
-rw-r--r--lib/debugger/test/guard_SUITE.erl2
-rw-r--r--lib/debugger/test/int_eval_SUITE.erl2
-rw-r--r--lib/debugger/test/int_eval_SUITE_data/my_int_eval_module.erl2
-rw-r--r--lib/debugger/vsn.mk2
-rw-r--r--lib/dialyzer/doc/src/Makefile1
-rw-r--r--lib/dialyzer/doc/src/notes.xml56
-rw-r--r--lib/dialyzer/src/dialyzer.erl4
-rw-r--r--lib/dialyzer/src/dialyzer_contracts.erl99
-rw-r--r--lib/dialyzer/src/dialyzer_dataflow.erl44
-rw-r--r--lib/dialyzer/src/typer.erl4
-rw-r--r--lib/dialyzer/test/options1_SUITE_data/results/compiler2
-rw-r--r--lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_validator.erl2
-rw-r--r--lib/dialyzer/test/options1_SUITE_data/src/compiler/compile.erl6
-rw-r--r--lib/dialyzer/test/overspecs_SUITE_data/dialyzer_options1
-rw-r--r--lib/dialyzer/test/overspecs_SUITE_data/results/iodata2
-rw-r--r--lib/dialyzer/test/overspecs_SUITE_data/results/iolist2
-rw-r--r--lib/dialyzer/test/overspecs_SUITE_data/src/iodata.erl41
-rw-r--r--lib/dialyzer/test/overspecs_SUITE_data/src/iolist.erl41
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber.erl4
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber_bin_v2.erl4
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_esi.erl2
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_lib.erl2
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_tm.erl2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/maps_sum2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/unused_funs5
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/unused_funs.erl21
-rw-r--r--lib/dialyzer/test/specdiffs_SUITE_data/dialyzer_options1
-rw-r--r--lib/dialyzer/test/specdiffs_SUITE_data/results/iodata3
-rw-r--r--lib/dialyzer/test/specdiffs_SUITE_data/results/iolist2
-rw-r--r--lib/dialyzer/test/specdiffs_SUITE_data/src/iodata.erl41
-rw-r--r--lib/dialyzer/test/specdiffs_SUITE_data/src/iolist.erl41
-rw-r--r--lib/dialyzer/vsn.mk2
-rwxr-xr-xlib/diameter/bin/diameterc6
-rw-r--r--lib/diameter/doc/src/Makefile1
-rw-r--r--lib/diameter/doc/src/notes.xml17
-rw-r--r--lib/diameter/examples/code/node.erl2
-rw-r--r--lib/diameter/src/Makefile7
-rw-r--r--lib/diameter/src/app.sed41
-rw-r--r--lib/diameter/src/base/diameter_codec.erl14
-rw-r--r--lib/diameter/src/base/diameter_config.erl14
-rw-r--r--lib/diameter/src/base/diameter_gen.erl19
-rw-r--r--lib/diameter/src/base/diameter_internal.hrl5
-rw-r--r--lib/diameter/src/base/diameter_lib.erl15
-rw-r--r--lib/diameter/src/base/diameter_service.erl20
-rw-r--r--lib/diameter/src/compiler/diameter_exprecs.erl2
-rw-r--r--lib/diameter/src/compiler/diameter_make.erl6
-rw-r--r--lib/diameter/src/diameter.app.src17
-rw-r--r--lib/diameter/src/transport/diameter_tcp.erl6
-rw-r--r--lib/diameter/test/diameter_app_SUITE.erl14
-rw-r--r--lib/diameter/test/diameter_traffic_SUITE.erl6
-rw-r--r--lib/diameter/test/diameter_watchdog_SUITE.erl9
-rw-r--r--lib/edoc/doc/src/Makefile1
-rw-r--r--lib/edoc/doc/src/notes.xml29
-rw-r--r--lib/edoc/src/edoc_layout.erl2
-rw-r--r--lib/edoc/vsn.mk2
-rw-r--r--lib/eldap/doc/src/Makefile1
-rw-r--r--lib/eldap/doc/src/notes.xml17
-rw-r--r--lib/eldap/test/eldap_basic_SUITE.erl2
-rw-r--r--lib/eldap/vsn.mk2
-rw-r--r--lib/erl_docgen/doc/src/Makefile1
-rw-r--r--lib/erl_docgen/doc/src/notes.xml40
-rwxr-xr-xlib/erl_docgen/priv/bin/codeline_preprocessing.escript2
-rwxr-xr-xlib/erl_docgen/priv/bin/github_link.escript2
-rwxr-xr-xlib/erl_docgen/priv/bin/xml_from_edoc.escript2
-rw-r--r--lib/erl_docgen/priv/xsl/Makefile5
-rw-r--r--lib/erl_docgen/priv/xsl/db_man.xsl2
-rw-r--r--lib/erl_docgen/src/docgen_edoc_xml_cb.erl2
-rw-r--r--lib/erl_docgen/src/docgen_otp_specs.erl4
-rw-r--r--lib/erl_docgen/vsn.mk2
-rw-r--r--lib/erl_interface/configure.in2
-rw-r--r--lib/erl_interface/doc/src/Makefile1
-rw-r--r--lib/erl_interface/doc/src/notes.xml58
-rw-r--r--lib/erl_interface/src/INSTALL4
-rw-r--r--lib/erl_interface/src/Makefile2
-rw-r--r--lib/erl_interface/src/Makefile.in2
-rw-r--r--lib/erl_interface/src/connect/ei_connect.c46
-rw-r--r--lib/erl_interface/src/connect/ei_resolve.c2
-rw-r--r--lib/erl_interface/src/decode/decode_atom.c2
-rw-r--r--lib/erl_interface/src/legacy/erl_marshal.c2
-rw-r--r--lib/erl_interface/src/misc/ei_pthreads.c3
-rw-r--r--lib/erl_interface/src/prog/erl_call.c15
-rw-r--r--lib/erl_interface/test/ei_accept_SUITE.erl11
-rw-r--r--lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c13
-rw-r--r--lib/erl_interface/test/ei_connect_SUITE.erl16
-rw-r--r--lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c12
-rw-r--r--lib/erl_interface/test/ei_decode_SUITE.erl20
-rw-r--r--lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c5
-rw-r--r--lib/erl_interface/test/ei_decode_encode_SUITE.erl6
-rw-r--r--lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c1
-rw-r--r--lib/erl_interface/test/ei_encode_SUITE.erl22
-rw-r--r--lib/erl_interface/test/ei_format_SUITE.erl12
-rw-r--r--lib/erl_interface/test/ei_print_SUITE.erl12
-rw-r--r--lib/erl_interface/test/ei_tmo_SUITE.erl28
-rw-r--r--lib/erl_interface/test/ei_tmo_SUITE_data/ei_tmo_test.c2
-rw-r--r--lib/erl_interface/test/erl_connect_SUITE.erl10
-rw-r--r--lib/erl_interface/test/erl_eterm_SUITE.erl78
-rw-r--r--lib/erl_interface/test/erl_ext_SUITE.erl13
-rw-r--r--lib/erl_interface/test/erl_format_SUITE.erl10
-rw-r--r--lib/erl_interface/test/erl_global_SUITE.erl9
-rw-r--r--lib/erl_interface/test/erl_match_SUITE.erl7
-rw-r--r--lib/erl_interface/test/port_call_SUITE.erl6
-rw-r--r--lib/erl_interface/test/runner.erl58
-rw-r--r--lib/erl_interface/vsn.mk2
-rw-r--r--lib/et/doc/src/Makefile3
-rw-r--r--lib/et/doc/src/et_collector.xml8
-rw-r--r--lib/et/doc/src/et_selector.xml4
-rw-r--r--lib/et/doc/src/files.mk2
-rw-r--r--lib/et/doc/src/notes.xml17
-rw-r--r--lib/et/src/et.app.src2
-rw-r--r--lib/et/src/et_collector.erl2
-rw-r--r--lib/et/src/et_wx_contents_viewer.erl2
-rw-r--r--lib/et/test/et_test_lib.erl2
-rw-r--r--lib/et/test/ett.erl2
-rw-r--r--lib/et/vsn.mk2
-rw-r--r--lib/eunit/doc/src/Makefile1
-rw-r--r--lib/eunit/doc/src/notes.xml17
-rw-r--r--lib/eunit/vsn.mk2
-rw-r--r--lib/ftp/Makefile2
-rw-r--r--lib/ftp/doc/src/Makefile1
-rw-r--r--lib/ftp/doc/src/ftp.xml14
-rw-r--r--lib/ftp/src/Makefile2
-rw-r--r--lib/ftp/src/ftp.erl124
-rw-r--r--lib/ftp/src/ftp_progress.erl2
-rw-r--r--lib/ftp/src/ftp_response.erl2
-rw-r--r--lib/ftp/test/erl_make_certs.erl2
-rw-r--r--lib/ftp/test/ftp_SUITE.erl2
-rw-r--r--lib/ftp/test/ftp_format_SUITE.erl2
-rw-r--r--lib/ftp/test/ftp_property_test_SUITE.erl2
-rw-r--r--lib/ftp/test/property_test/ftp_simple_client_server.erl2
-rw-r--r--lib/hipe/cerl/Makefile2
-rw-r--r--lib/hipe/doc/src/Makefile1
-rw-r--r--lib/hipe/doc/src/hipe_app.xml68
-rw-r--r--lib/hipe/doc/src/notes.xml47
-rw-r--r--lib/hipe/icode/hipe_icode_range.erl2
-rw-r--r--lib/hipe/main/hipe.app.src2
-rw-r--r--lib/hipe/main/hipe.erl6
-rw-r--r--lib/hipe/rtl/hipe_icode2rtl.erl2
-rw-r--r--lib/hipe/rtl/hipe_rtl_arith.inc4
-rw-r--r--lib/hipe/rtl/hipe_rtl_lcm.erl9
-rw-r--r--lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl6
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl28
-rw-r--r--lib/hipe/vsn.mk2
-rw-r--r--lib/inets/doc/src/Makefile3
-rw-r--r--lib/inets/doc/src/http_client.xml2
-rw-r--r--lib/inets/doc/src/http_uri.xml2
-rw-r--r--lib/inets/doc/src/httpc.xml2
-rw-r--r--lib/inets/doc/src/httpd.xml4
-rw-r--r--lib/inets/doc/src/inets.xml2
-rw-r--r--lib/inets/doc/src/mod_esi.xml2
-rw-r--r--lib/inets/doc/src/mod_security.xml3
-rw-r--r--lib/inets/doc/src/notes.xml134
-rw-r--r--lib/inets/doc/src/notes_history.xml4
-rw-r--r--lib/inets/src/http_client/httpc.erl2
-rw-r--r--lib/inets/src/http_client/httpc_cookie.erl2
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl2
-rw-r--r--lib/inets/src/http_client/httpc_internal.hrl2
-rw-r--r--lib/inets/src/http_client/httpc_manager.erl2
-rw-r--r--lib/inets/src/http_client/httpc_request.erl2
-rw-r--r--lib/inets/src/http_client/httpc_response.erl43
-rw-r--r--lib/inets/src/http_lib/http_request.erl8
-rw-r--r--lib/inets/src/http_lib/http_uri.erl2
-rw-r--r--lib/inets/src/http_server/httpd.erl2
-rw-r--r--lib/inets/src/http_server/httpd_esi.erl2
-rw-r--r--lib/inets/src/http_server/httpd_example.erl2
-rw-r--r--lib/inets/src/http_server/httpd_file.erl3
-rw-r--r--lib/inets/src/http_server/httpd_request.erl8
-rw-r--r--lib/inets/src/http_server/httpd_response.erl10
-rw-r--r--lib/inets/src/http_server/httpd_script_env.erl2
-rw-r--r--lib/inets/src/http_server/mod_alias.erl2
-rw-r--r--lib/inets/src/http_server/mod_disk_log.erl2
-rw-r--r--lib/inets/src/http_server/mod_esi.erl4
-rw-r--r--lib/inets/src/http_server/mod_log.erl2
-rw-r--r--lib/inets/src/inets_app/Makefile2
-rw-r--r--lib/inets/src/inets_app/inets.app.src2
-rw-r--r--lib/inets/src/inets_app/inets.appup.src2
-rw-r--r--lib/inets/src/inets_app/inets.erl2
-rw-r--r--lib/inets/src/inets_app/inets_internal.hrl2
-rw-r--r--lib/inets/src/inets_app/inets_sup.erl2
-rw-r--r--lib/inets/test/Makefile2
-rw-r--r--lib/inets/test/http_format_SUITE.erl4
-rw-r--r--lib/inets/test/httpc_SUITE.erl100
-rw-r--r--lib/inets/test/httpc_proxy_SUITE.erl2
-rw-r--r--lib/inets/test/httpd_SUITE.erl70
-rw-r--r--lib/inets/test/httpd_bench_SUITE.erl2
-rw-r--r--lib/inets/test/httpd_mod.erl2
-rw-r--r--lib/inets/test/inets_SUITE.erl2
-rw-r--r--lib/inets/test/inets_socketwrap_SUITE.erl2
-rw-r--r--lib/inets/test/inets_sup_SUITE.erl2
-rw-r--r--lib/inets/test/inets_test_lib.erl2
-rw-r--r--lib/inets/test/uri_SUITE.erl2
-rw-r--r--lib/inets/vsn.mk4
-rw-r--r--lib/jinterface/doc/src/Makefile1
-rw-r--r--lib/jinterface/doc/src/notes.xml19
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile2
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java2
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java12
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java4
-rw-r--r--lib/jinterface/test/jinterface_SUITE.erl2
-rw-r--r--lib/jinterface/test/nc_SUITE.erl2
-rw-r--r--lib/jinterface/vsn.mk2
-rw-r--r--lib/kernel/doc/src/.gitignore1
-rw-r--r--lib/kernel/doc/src/Makefile18
-rw-r--r--lib/kernel/doc/src/application.xml12
-rw-r--r--lib/kernel/doc/src/book.xml2
-rw-r--r--lib/kernel/doc/src/code.xml6
-rw-r--r--lib/kernel/doc/src/config.xml15
-rw-r--r--lib/kernel/doc/src/erl_epmd.xml104
-rw-r--r--lib/kernel/doc/src/error_logger.xml326
-rw-r--r--lib/kernel/doc/src/file.xml2
-rw-r--r--lib/kernel/doc/src/heart.xml2
-rw-r--r--lib/kernel/doc/src/inet.xml21
-rw-r--r--lib/kernel/doc/src/introduction_chapter.xml3
-rw-r--r--lib/kernel/doc/src/kernel_app.xml271
-rw-r--r--lib/kernel/doc/src/logger.xml1031
-rw-r--r--lib/kernel/doc/src/logger_arch.diabin0 -> 2527 bytes
-rw-r--r--lib/kernel/doc/src/logger_arch.pngbin31459 -> 117205 bytes
-rw-r--r--lib/kernel/doc/src/logger_chapter.xml1634
-rw-r--r--lib/kernel/doc/src/logger_disk_log_h.xml150
-rw-r--r--lib/kernel/doc/src/logger_filters.xml227
-rw-r--r--lib/kernel/doc/src/logger_formatter.xml434
-rw-r--r--lib/kernel/doc/src/logger_std_h.xml117
-rw-r--r--lib/kernel/doc/src/net_kernel.xml6
-rw-r--r--lib/kernel/doc/src/notes.xml321
-rw-r--r--lib/kernel/doc/src/os.xml2
-rw-r--r--lib/kernel/doc/src/part.xml11
-rw-r--r--lib/kernel/doc/src/ref_man.xml7
-rw-r--r--lib/kernel/doc/src/seq_trace.xml2
-rw-r--r--lib/kernel/doc/src/specs.xml1
-rw-r--r--lib/kernel/include/dist.hrl2
-rw-r--r--lib/kernel/include/dist_util.hrl2
-rw-r--r--lib/kernel/include/logger.hrl4
-rw-r--r--lib/kernel/src/Makefile9
-rw-r--r--lib/kernel/src/application_controller.erl62
-rw-r--r--lib/kernel/src/application_master.erl6
-rw-r--r--lib/kernel/src/auth.erl2
-rw-r--r--lib/kernel/src/code.erl4
-rw-r--r--lib/kernel/src/code_server.erl6
-rw-r--r--lib/kernel/src/disk_log_1.erl2
-rw-r--r--lib/kernel/src/erl_epmd.erl66
-rw-r--r--lib/kernel/src/erl_signal_handler.erl2
-rw-r--r--lib/kernel/src/error_handler.erl2
-rw-r--r--lib/kernel/src/error_logger.erl135
-rw-r--r--lib/kernel/src/erts_debug.erl58
-rw-r--r--lib/kernel/src/file.erl2
-rw-r--r--lib/kernel/src/file_server.erl6
-rw-r--r--lib/kernel/src/gen_sctp.erl4
-rw-r--r--lib/kernel/src/gen_tcp.erl6
-rw-r--r--lib/kernel/src/gen_udp.erl4
-rw-r--r--lib/kernel/src/group.erl2
-rw-r--r--lib/kernel/src/inet_config.erl2
-rw-r--r--lib/kernel/src/inet_dns.erl2
-rw-r--r--lib/kernel/src/inet_tcp_dist.erl150
-rw-r--r--lib/kernel/src/kernel.app.src10
-rw-r--r--lib/kernel/src/kernel.erl16
-rw-r--r--lib/kernel/src/kernel_config.erl2
-rw-r--r--lib/kernel/src/kernel_refc.erl4
-rw-r--r--lib/kernel/src/logger.erl707
-rw-r--r--lib/kernel/src/logger_backend.erl10
-rw-r--r--lib/kernel/src/logger_config.erl52
-rw-r--r--lib/kernel/src/logger_disk_log_h.erl505
-rw-r--r--lib/kernel/src/logger_filters.erl76
-rw-r--r--lib/kernel/src/logger_formatter.erl484
-rw-r--r--lib/kernel/src/logger_h_common.erl202
-rw-r--r--lib/kernel/src/logger_h_common.hrl57
-rw-r--r--lib/kernel/src/logger_handler_watcher.erl113
-rw-r--r--lib/kernel/src/logger_internal.hrl26
-rw-r--r--lib/kernel/src/logger_server.erl440
-rw-r--r--lib/kernel/src/logger_simple_h.erl (renamed from lib/kernel/src/logger_simple.erl)86
-rw-r--r--lib/kernel/src/logger_std_h.erl391
-rw-r--r--lib/kernel/src/logger_sup.erl8
-rw-r--r--lib/kernel/src/net_kernel.erl9
-rw-r--r--lib/kernel/src/os.erl2
-rw-r--r--lib/kernel/src/seq_trace.erl2
-rw-r--r--lib/kernel/src/user_drv.erl2
-rw-r--r--lib/kernel/test/Makefile6
-rw-r--r--lib/kernel/test/application_SUITE.erl55
-rw-r--r--lib/kernel/test/code_SUITE.erl2
-rw-r--r--lib/kernel/test/erl_distribution_SUITE.erl10
-rw-r--r--lib/kernel/test/erl_prim_loader_SUITE.erl2
-rw-r--r--lib/kernel/test/error_logger_SUITE.erl22
-rw-r--r--lib/kernel/test/error_logger_warn_SUITE.erl16
-rw-r--r--lib/kernel/test/file_SUITE.erl6
-rw-r--r--lib/kernel/test/gen_sctp_SUITE.erl2
-rw-r--r--lib/kernel/test/gen_tcp_api_SUITE.erl2
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl2
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl14
-rw-r--r--lib/kernel/test/heart_SUITE.erl10
-rw-r--r--lib/kernel/test/inet_SUITE.erl2
-rw-r--r--lib/kernel/test/inet_res_SUITE.erl4
-rw-r--r--lib/kernel/test/kernel.spec1
-rw-r--r--lib/kernel/test/kernel_SUITE.erl2
-rw-r--r--lib/kernel/test/kernel_config_SUITE.erl4
-rw-r--r--lib/kernel/test/logger.cover2
-rw-r--r--lib/kernel/test/logger.spec2
-rw-r--r--lib/kernel/test/logger_SUITE.erl635
-rw-r--r--lib/kernel/test/logger_bench_SUITE.erl500
-rw-r--r--lib/kernel/test/logger_bench_SUITE_data/Emakefile1
-rw-r--r--lib/kernel/test/logger_bench_SUITE_data/lager_helper.erl73
-rw-r--r--lib/kernel/test/logger_disk_log_h_SUITE.erl796
-rw-r--r--lib/kernel/test/logger_env_var_SUITE.erl932
-rw-r--r--lib/kernel/test/logger_filters_SUITE.erl123
-rw-r--r--lib/kernel/test/logger_formatter_SUITE.erl497
-rw-r--r--lib/kernel/test/logger_legacy_SUITE.erl32
-rw-r--r--lib/kernel/test/logger_simple_SUITE.erl247
-rw-r--r--lib/kernel/test/logger_simple_h_SUITE.erl210
-rw-r--r--lib/kernel/test/logger_std_h_SUITE.erl864
-rw-r--r--lib/kernel/test/logger_test_lib.erl82
-rw-r--r--lib/kernel/test/os_SUITE.erl8
-rw-r--r--lib/kernel/test/pdict_SUITE.erl2
-rw-r--r--lib/kernel/test/prim_file_SUITE.erl2
-rw-r--r--lib/kernel/test/seq_trace_SUITE.erl20
-rw-r--r--lib/kernel/test/wrap_log_reader_SUITE.erl2
-rw-r--r--lib/kernel/test/wrap_log_reader_SUITE_data/wrap_log_test.erl2
-rw-r--r--lib/kernel/test/zlib_SUITE.erl2
-rw-r--r--lib/kernel/vsn.mk2
-rw-r--r--lib/megaco/doc/src/Makefile1
-rw-r--r--lib/mnesia/doc/src/Makefile3
-rw-r--r--lib/mnesia/doc/src/Mnesia_chap2.xmlsrc2
-rw-r--r--lib/mnesia/doc/src/Mnesia_chap5.xmlsrc2
-rw-r--r--lib/mnesia/doc/src/company.erl2
-rw-r--r--lib/mnesia/doc/src/company_o.erl2
-rw-r--r--lib/mnesia/doc/src/mnesia_frag_hash.xml2
-rw-r--r--lib/mnesia/doc/src/notes.xml47
-rw-r--r--lib/mnesia/src/mnesia.erl24
-rw-r--r--lib/mnesia/src/mnesia.hrl2
-rw-r--r--lib/mnesia/src/mnesia_bup.erl2
-rw-r--r--lib/mnesia/src/mnesia_checkpoint.erl2
-rw-r--r--lib/mnesia/src/mnesia_controller.erl32
-rw-r--r--lib/mnesia/src/mnesia_dumper.erl2
-rw-r--r--lib/mnesia/src/mnesia_frag.erl2
-rw-r--r--lib/mnesia/src/mnesia_index.erl2
-rw-r--r--lib/mnesia/src/mnesia_late_loader.erl2
-rw-r--r--lib/mnesia/src/mnesia_lib.erl4
-rw-r--r--lib/mnesia/src/mnesia_loader.erl10
-rw-r--r--lib/mnesia/src/mnesia_locker.erl2
-rw-r--r--lib/mnesia/src/mnesia_log.erl2
-rw-r--r--lib/mnesia/src/mnesia_recover.erl2
-rw-r--r--lib/mnesia/src/mnesia_schema.erl2
-rw-r--r--lib/mnesia/src/mnesia_subscr.erl2
-rw-r--r--lib/mnesia/src/mnesia_text.erl2
-rw-r--r--lib/mnesia/src/mnesia_tm.erl4
-rw-r--r--lib/mnesia/test/mnesia_SUITE.erl2
-rw-r--r--lib/mnesia/test/mnesia_atomicity_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_bench_SUITE.erl2
-rw-r--r--lib/mnesia/test/mnesia_consistency_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_cost.erl2
-rw-r--r--lib/mnesia/test/mnesia_dirty_access_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_durability_test.erl109
-rw-r--r--lib/mnesia/test/mnesia_evil_coverage_test.erl49
-rw-r--r--lib/mnesia/test/mnesia_examples_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_frag_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_install_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_isolation_test.erl13
-rw-r--r--lib/mnesia/test/mnesia_majority_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_measure_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_nice_coverage_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_qlc_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_recovery_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_registry_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_schema_recovery_test.erl2
-rw-r--r--lib/mnesia/test/mnesia_test_lib.erl2
-rw-r--r--lib/mnesia/test/mnesia_test_lib.hrl2
-rw-r--r--lib/mnesia/test/mnesia_trans_access_test.erl2
-rw-r--r--lib/mnesia/vsn.mk2
-rw-r--r--lib/observer/doc/src/Makefile1
-rw-r--r--lib/observer/doc/src/notes.xml31
-rw-r--r--lib/observer/include/etop.hrl2
-rw-r--r--lib/observer/src/cdv_atom_cb.erl2
-rw-r--r--lib/observer/src/cdv_bin_cb.erl4
-rw-r--r--lib/observer/src/cdv_detail_wx.erl2
-rw-r--r--lib/observer/src/cdv_dist_cb.erl2
-rw-r--r--lib/observer/src/cdv_html_wx.erl2
-rw-r--r--lib/observer/src/cdv_info_wx.erl2
-rw-r--r--lib/observer/src/cdv_mem_cb.erl2
-rw-r--r--lib/observer/src/cdv_multi_wx.erl2
-rw-r--r--lib/observer/src/cdv_port_cb.erl2
-rw-r--r--lib/observer/src/cdv_proc_cb.erl2
-rw-r--r--lib/observer/src/cdv_sched_cb.erl2
-rw-r--r--lib/observer/src/cdv_table_wx.erl2
-rw-r--r--lib/observer/src/cdv_term_cb.erl4
-rw-r--r--lib/observer/src/cdv_virtual_list_wx.erl2
-rw-r--r--lib/observer/src/cdv_wx.erl2
-rw-r--r--lib/observer/src/crashdump_viewer.erl2
-rw-r--r--lib/observer/src/crashdump_viewer.hrl2
-rw-r--r--lib/observer/src/etop_tr.erl2
-rw-r--r--lib/observer/src/multitrace.erl2
-rw-r--r--lib/observer/src/observer.app.src2
-rw-r--r--lib/observer/src/observer_alloc_wx.erl2
-rw-r--r--lib/observer/src/observer_html_lib.erl2
-rw-r--r--lib/observer/src/observer_lib.erl4
-rw-r--r--lib/observer/src/observer_perf_wx.erl2
-rw-r--r--lib/observer/src/observer_port_wx.erl2
-rw-r--r--lib/observer/src/observer_pro_wx.erl2
-rw-r--r--lib/observer/src/observer_procinfo.erl2
-rw-r--r--lib/observer/src/observer_traceoptions_wx.erl2
-rw-r--r--lib/observer/src/observer_tv_wx.erl6
-rw-r--r--lib/observer/src/observer_wx.erl2
-rw-r--r--lib/observer/src/ttb_et.erl2
-rw-r--r--lib/observer/test/crashdump_helper.erl2
-rw-r--r--lib/observer/test/crashdump_viewer_SUITE.erl2
-rw-r--r--lib/observer/test/crashdump_viewer_SUITE_data/old_format.dump8
-rw-r--r--lib/observer/test/observer_SUITE.erl4
-rw-r--r--lib/observer/test/ttb_SUITE.erl2
-rw-r--r--lib/observer/vsn.mk2
-rw-r--r--lib/odbc/doc/src/Makefile1
-rw-r--r--lib/odbc/doc/src/databases.xml2
-rw-r--r--lib/odbc/doc/src/error_handling.xml2
-rw-r--r--lib/odbc/doc/src/getting_started.xml2
-rw-r--r--lib/odbc/doc/src/notes_history.xml4
-rw-r--r--lib/odbc/doc/src/odbc.xml2
-rw-r--r--lib/odbc/test/odbc_connect_SUITE.erl2
-rw-r--r--lib/os_mon/doc/src/Makefile1
-rw-r--r--lib/os_mon/doc/src/notes.xml18
-rw-r--r--lib/os_mon/doc/src/os_mon_mib.xml7
-rw-r--r--lib/os_mon/src/cpu_sup.erl2
-rw-r--r--lib/os_mon/src/memsup.erl2
-rw-r--r--lib/os_mon/test/cpu_sup_SUITE.erl11
-rw-r--r--lib/os_mon/test/disksup_SUITE.erl2
-rw-r--r--lib/os_mon/vsn.mk2
-rw-r--r--lib/otp_mibs/doc/src/Makefile1
-rw-r--r--lib/otp_mibs/doc/src/notes.xml18
-rw-r--r--lib/otp_mibs/doc/src/otp_mib.xml7
-rw-r--r--lib/otp_mibs/src/otp_mib.erl5
-rw-r--r--lib/otp_mibs/vsn.mk2
-rw-r--r--lib/parsetools/doc/src/Makefile1
-rw-r--r--lib/parsetools/doc/src/notes.xml17
-rw-r--r--lib/parsetools/include/yeccpre.hrl2
-rw-r--r--lib/parsetools/src/yecc.erl10
-rw-r--r--lib/parsetools/src/yeccparser.erl2
-rw-r--r--lib/parsetools/test/yecc_SUITE.erl2
-rw-r--r--lib/parsetools/vsn.mk2
-rw-r--r--lib/public_key/doc/src/Makefile1
-rw-r--r--lib/public_key/doc/src/notes.xml79
-rw-r--r--lib/public_key/doc/src/public_key.xml81
-rw-r--r--lib/public_key/doc/src/public_key_records.xml2
-rw-r--r--lib/public_key/doc/src/using_public_key.xml6
-rw-r--r--lib/public_key/include/public_key.hrl2
-rw-r--r--lib/public_key/priv/moduli429
-rw-r--r--lib/public_key/src/pubkey_cert.erl2
-rw-r--r--lib/public_key/src/pubkey_crl.erl2
-rw-r--r--lib/public_key/src/pubkey_moduli.hrl502
-rw-r--r--lib/public_key/src/pubkey_pbe.erl2
-rw-r--r--lib/public_key/src/pubkey_pem.erl4
-rw-r--r--lib/public_key/src/public_key.erl78
-rw-r--r--lib/public_key/test/pbe_SUITE.erl12
-rw-r--r--lib/public_key/test/public_key_SUITE.erl78
-rw-r--r--lib/public_key/test/public_key_SUITE_data/dsa_key_pkcs8.pem9
-rw-r--r--lib/public_key/test/public_key_SUITE_data/ec_key_pkcs8.pem5
-rw-r--r--lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName.pem24
-rw-r--r--lib/public_key/test/public_key_SUITE_data/rsa_key_pkcs8.pem10
-rw-r--r--lib/public_key/test/public_key_SUITE_data/verify_hostname.conf3
-rw-r--r--lib/public_key/vsn.mk2
-rw-r--r--lib/reltool/doc/src/Makefile1
-rw-r--r--lib/reltool/doc/src/notes.xml19
-rw-r--r--lib/reltool/doc/src/reltool.xml2
-rw-r--r--lib/reltool/src/reltool.app.src2
-rw-r--r--lib/reltool/src/reltool.erl2
-rw-r--r--lib/reltool/src/reltool_app_win.erl2
-rw-r--r--lib/reltool/src/reltool_fgraph_win.erl2
-rw-r--r--lib/reltool/src/reltool_mod_win.erl2
-rw-r--r--lib/reltool/src/reltool_server.erl4
-rw-r--r--lib/reltool/src/reltool_sys_win.erl2
-rw-r--r--lib/reltool/src/reltool_target.erl2
-rw-r--r--lib/reltool/test/reltool_app_SUITE.erl2
-rw-r--r--lib/reltool/test/reltool_manual_gui_SUITE.erl2
-rw-r--r--lib/reltool/test/reltool_server_SUITE.erl6
-rw-r--r--lib/reltool/test/reltool_test_lib.erl2
-rw-r--r--lib/reltool/test/reltool_wx_SUITE.erl2
-rw-r--r--lib/reltool/test/rtt.erl2
-rw-r--r--lib/reltool/vsn.mk2
-rw-r--r--lib/runtime_tools/doc/src/LTTng.xml4
-rw-r--r--lib/runtime_tools/doc/src/Makefile3
-rw-r--r--lib/runtime_tools/doc/src/dbg.xml6
-rw-r--r--lib/runtime_tools/doc/src/notes.xml18
-rw-r--r--lib/runtime_tools/doc/src/ref_man.xml2
-rw-r--r--lib/runtime_tools/src/Makefile2
-rw-r--r--lib/runtime_tools/src/appmon_info.erl2
-rw-r--r--lib/runtime_tools/src/erts_alloc_config.erl2
-rw-r--r--lib/runtime_tools/src/msacc.erl2
-rw-r--r--lib/runtime_tools/src/observer_backend.erl4
-rw-r--r--lib/runtime_tools/src/runtime_tools.app.src2
-rw-r--r--lib/runtime_tools/src/system_information.erl1
-rw-r--r--lib/runtime_tools/test/dbg_SUITE.erl2
-rw-r--r--lib/runtime_tools/test/dyntrace_SUITE.erl2
-rw-r--r--lib/runtime_tools/vsn.mk2
-rw-r--r--lib/sasl/doc/src/Makefile1
-rw-r--r--lib/sasl/doc/src/appup.xml2
-rw-r--r--lib/sasl/doc/src/error_logging.xml55
-rw-r--r--lib/sasl/doc/src/notes.xml84
-rw-r--r--lib/sasl/doc/src/release_handler.xml2
-rw-r--r--lib/sasl/doc/src/sasl_app.xml59
-rw-r--r--lib/sasl/src/Makefile2
-rw-r--r--lib/sasl/src/rb.erl2
-rw-r--r--lib/sasl/src/release_handler.erl6
-rw-r--r--lib/sasl/src/release_handler_1.erl2
-rw-r--r--lib/sasl/src/sasl.app.src2
-rw-r--r--lib/sasl/src/sasl.appup.src2
-rw-r--r--lib/sasl/src/sasl.erl37
-rw-r--r--lib/sasl/src/sasl_report_file_h.erl2
-rw-r--r--lib/sasl/src/systools_make.erl2
-rw-r--r--lib/sasl/test/installer.erl2
-rw-r--r--lib/sasl/test/rb_SUITE.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE.erl2
-rw-r--r--lib/sasl/test/sasl_SUITE.erl2
-rw-r--r--lib/sasl/test/sasl_report_SUITE.erl89
-rw-r--r--lib/sasl/test/systools_SUITE.erl4
-rw-r--r--lib/sasl/vsn.mk2
-rw-r--r--lib/snmp/doc/src/Makefile1
-rw-r--r--lib/snmp/doc/src/notes.xml18
-rw-r--r--lib/snmp/src/agent/snmpa_set_lib.erl6
-rw-r--r--lib/snmp/src/agent/snmpa_trap.erl4
-rw-r--r--lib/snmp/src/compile/snmpc.erl66
-rw-r--r--lib/snmp/test/snmp_compiler_test.erl23
-rw-r--r--lib/snmp/test/snmp_test_data/OTP14196-MIB.mib47
-rw-r--r--lib/snmp/test/test-mibs/ALARM-MIB.mib2
-rw-r--r--lib/snmp/test/test-mibs/SNMPv2-TC.mib4
-rw-r--r--lib/snmp/vsn.mk2
-rw-r--r--lib/ssh/doc/src/Makefile3
-rw-r--r--lib/ssh/doc/src/configure_algos.xml2
-rw-r--r--lib/ssh/doc/src/introduction.xml2
-rw-r--r--lib/ssh/doc/src/notes.xml193
-rw-r--r--lib/ssh/doc/src/ref_man.xml2
-rw-r--r--lib/ssh/doc/src/ssh.xml4
-rw-r--r--lib/ssh/doc/src/ssh_app.xml57
-rw-r--r--lib/ssh/doc/src/ssh_client_channel.xml2
-rw-r--r--lib/ssh/doc/src/ssh_client_key_api.xml2
-rw-r--r--lib/ssh/doc/src/ssh_connection.xml2
-rw-r--r--lib/ssh/doc/src/ssh_protocol.xml2
-rw-r--r--lib/ssh/doc/src/ssh_server_channel.xml2
-rw-r--r--lib/ssh/doc/src/ssh_server_key_api.xml2
-rw-r--r--lib/ssh/doc/src/ssh_sftp.xml10
-rw-r--r--lib/ssh/doc/src/ssh_sftpd.xml2
-rw-r--r--lib/ssh/doc/src/usersguide.xml2
-rw-r--r--lib/ssh/doc/src/using_ssh.xml2
-rw-r--r--lib/ssh/src/Makefile2
-rw-r--r--lib/ssh/src/ssh.erl2
-rw-r--r--lib/ssh/src/ssh.hrl27
-rw-r--r--lib/ssh/src/ssh_acceptor.erl2
-rw-r--r--lib/ssh/src/ssh_acceptor_sup.erl2
-rw-r--r--lib/ssh/src/ssh_auth.erl2
-rw-r--r--lib/ssh/src/ssh_channel.erl2
-rw-r--r--lib/ssh/src/ssh_cli.erl2
-rw-r--r--lib/ssh/src/ssh_client_channel.erl8
-rw-r--r--lib/ssh/src/ssh_client_key_api.erl2
-rw-r--r--lib/ssh/src/ssh_connect.hrl2
-rw-r--r--lib/ssh/src/ssh_connection.erl44
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl14
-rw-r--r--lib/ssh/src/ssh_connection_sup.erl2
-rw-r--r--lib/ssh/src/ssh_daemon_channel.erl2
-rw-r--r--lib/ssh/src/ssh_dbg.erl118
-rw-r--r--lib/ssh/src/ssh_file.erl2
-rw-r--r--lib/ssh/src/ssh_info.erl2
-rw-r--r--lib/ssh/src/ssh_message.erl2
-rw-r--r--lib/ssh/src/ssh_no_io.erl2
-rw-r--r--lib/ssh/src/ssh_options.erl2
-rw-r--r--lib/ssh/src/ssh_server_channel.erl2
-rw-r--r--lib/ssh/src/ssh_server_channel_sup.erl2
-rw-r--r--lib/ssh/src/ssh_server_key_api.erl2
-rw-r--r--lib/ssh/src/ssh_sftp.erl40
-rw-r--r--lib/ssh/src/ssh_sftpd.erl8
-rw-r--r--lib/ssh/src/ssh_shell.erl2
-rw-r--r--lib/ssh/src/ssh_subsystem_sup.erl2
-rw-r--r--lib/ssh/src/ssh_sup.erl2
-rw-r--r--lib/ssh/src/ssh_system_sup.erl2
-rw-r--r--lib/ssh/src/ssh_transport.erl66
-rw-r--r--lib/ssh/src/ssh_transport.hrl2
-rw-r--r--lib/ssh/src/ssh_xfer.erl2
-rw-r--r--lib/ssh/src/sshc_sup.erl2
-rw-r--r--lib/ssh/src/sshd_sup.erl2
-rw-r--r--lib/ssh/test/Makefile7
-rw-r--r--lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl2
-rw-r--r--lib/ssh/test/property_test/ssh_eqc_subsys.erl2
-rw-r--r--lib/ssh/test/ssh_algorithms_SUITE.erl15
-rw-r--r--lib/ssh/test/ssh_basic_SUITE.erl2
-rw-r--r--lib/ssh/test/ssh_bench_dev_null.erl2
-rw-r--r--lib/ssh/test/ssh_chan_behaviours_SUITE.erl152
-rw-r--r--lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_dsa_key13
-rw-r--r--lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_dsa_key.pub11
-rw-r--r--lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_ecdsa_key6
-rw-r--r--lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_ecdsa_key.pub1
-rw-r--r--lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_rsa_key16
-rw-r--r--lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_rsa_key.pub5
-rw-r--r--lib/ssh/test/ssh_chan_behaviours_client.erl143
-rw-r--r--lib/ssh/test/ssh_chan_behaviours_server.erl96
-rw-r--r--lib/ssh/test/ssh_compat_SUITE.erl2
-rw-r--r--lib/ssh/test/ssh_connection_SUITE.erl2
-rw-r--r--lib/ssh/test/ssh_dbg_SUITE.erl68
-rw-r--r--lib/ssh/test/ssh_echo_server.erl2
-rw-r--r--lib/ssh/test/ssh_engine_SUITE.erl2
-rw-r--r--lib/ssh/test/ssh_options_SUITE.erl2
-rw-r--r--lib/ssh/test/ssh_peername_sockname_server.erl2
-rw-r--r--lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_dsa_key13
-rw-r--r--lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_dsa_key.pub11
-rw-r--r--lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_ecdsa_key5
-rw-r--r--lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_ecdsa_key.pub1
-rw-r--r--lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_rsa_key16
-rw-r--r--lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_rsa_key.pub5
-rw-r--r--lib/ssh/test/ssh_sup_SUITE.erl2
-rw-r--r--lib/ssh/test/ssh_test_lib.erl2
-rw-r--r--lib/ssh/test/ssh_to_openssh_SUITE.erl2
-rw-r--r--lib/ssh/vsn.mk3
-rw-r--r--lib/ssl/doc/src/Makefile1
-rw-r--r--lib/ssl/doc/src/notes.xml201
-rw-r--r--lib/ssl/doc/src/ssl.xml229
-rw-r--r--lib/ssl/doc/src/ssl_app.xml2
-rw-r--r--lib/ssl/doc/src/ssl_crl_cache.xml2
-rw-r--r--lib/ssl/doc/src/ssl_distribution.xml2
-rw-r--r--lib/ssl/doc/src/ssl_introduction.xml2
-rw-r--r--lib/ssl/doc/src/ssl_protocol.xml2
-rw-r--r--lib/ssl/doc/src/using_ssl.xml10
-rw-r--r--lib/ssl/examples/src/client_server.erl12
-rw-r--r--lib/ssl/src/Makefile11
-rw-r--r--lib/ssl/src/dtls_connection.erl34
-rw-r--r--lib/ssl/src/dtls_handshake.erl2
-rw-r--r--lib/ssl/src/dtls_listener_sup.erl (renamed from lib/ssl/src/dtls_udp_sup.erl)8
-rw-r--r--lib/ssl/src/dtls_packet_demux.erl (renamed from lib/ssl/src/dtls_udp_listener.erl)63
-rw-r--r--lib/ssl/src/dtls_record.erl2
-rw-r--r--lib/ssl/src/dtls_socket.erl36
-rw-r--r--lib/ssl/src/dtls_v1.erl2
-rw-r--r--lib/ssl/src/inet_tls_dist.erl385
-rw-r--r--lib/ssl/src/ssl.app.src6
-rw-r--r--lib/ssl/src/ssl.erl188
-rw-r--r--lib/ssl/src/ssl_alert.erl2
-rw-r--r--lib/ssl/src/ssl_alert.hrl2
-rw-r--r--lib/ssl/src/ssl_app.erl17
-rw-r--r--lib/ssl/src/ssl_certificate.erl22
-rw-r--r--lib/ssl/src/ssl_cipher.erl134
-rw-r--r--lib/ssl/src/ssl_cipher.hrl2
-rw-r--r--lib/ssl/src/ssl_config.erl8
-rw-r--r--lib/ssl/src/ssl_connection.erl188
-rw-r--r--lib/ssl/src/ssl_connection.hrl2
-rw-r--r--lib/ssl/src/ssl_connection_sup.erl12
-rw-r--r--lib/ssl/src/ssl_crl_cache.erl2
-rw-r--r--lib/ssl/src/ssl_crl_hash_dir.erl5
-rw-r--r--lib/ssl/src/ssl_handshake.erl181
-rw-r--r--lib/ssl/src/ssl_handshake.hrl13
-rw-r--r--lib/ssl/src/ssl_internal.hrl41
-rw-r--r--lib/ssl/src/ssl_logger.erl349
-rw-r--r--lib/ssl/src/ssl_manager.erl14
-rw-r--r--lib/ssl/src/ssl_pem_cache.erl12
-rw-r--r--lib/ssl/src/ssl_pkix_db.erl20
-rw-r--r--lib/ssl/src/ssl_record.erl2
-rw-r--r--lib/ssl/src/ssl_record.hrl2
-rw-r--r--lib/ssl/src/tls_connection.erl75
-rw-r--r--lib/ssl/src/tls_handshake.erl152
-rw-r--r--lib/ssl/src/tls_record.erl67
-rw-r--r--lib/ssl/src/tls_socket.erl2
-rw-r--r--lib/ssl/src/tls_v1.erl20
-rw-r--r--lib/ssl/test/Makefile2
-rw-r--r--lib/ssl/test/ssl_ECC.erl44
-rw-r--r--lib/ssl/test/ssl_ECC_SUITE.erl56
-rw-r--r--lib/ssl/test/ssl_ECC_openssl_SUITE.erl19
-rw-r--r--lib/ssl/test/ssl_alpn_handshake_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl258
-rw-r--r--lib/ssl/test/ssl_certificate_verify_SUITE.erl62
-rw-r--r--lib/ssl/test/ssl_crl_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_dist_bench_SUITE.erl15
-rw-r--r--lib/ssl/test/ssl_engine_SUITE.erl17
-rw-r--r--lib/ssl/test/ssl_handshake_SUITE.erl4
-rw-r--r--lib/ssl/test/ssl_npn_handshake_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_payload_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_pem_cache_SUITE.erl45
-rw-r--r--lib/ssl/test/ssl_sni_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_test_lib.erl106
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl30
-rw-r--r--lib/ssl/vsn.mk2
-rw-r--r--lib/stdlib/doc/src/Makefile4
-rw-r--r--lib/stdlib/doc/src/assert_hrl.xml2
-rw-r--r--lib/stdlib/doc/src/c.xml2
-rw-r--r--lib/stdlib/doc/src/calendar.xml9
-rw-r--r--lib/stdlib/doc/src/digraph.xml2
-rw-r--r--lib/stdlib/doc/src/ets.xml8
-rw-r--r--lib/stdlib/doc/src/gb_sets.xml2
-rw-r--r--lib/stdlib/doc/src/gen_event.xml7
-rw-r--r--lib/stdlib/doc/src/gen_server.xml8
-rw-r--r--lib/stdlib/doc/src/gen_statem.xml12
-rw-r--r--lib/stdlib/doc/src/io.xml17
-rw-r--r--lib/stdlib/doc/src/io_lib.xml34
-rw-r--r--lib/stdlib/doc/src/lib.xml103
-rw-r--r--lib/stdlib/doc/src/maps.xml36
-rw-r--r--lib/stdlib/doc/src/notes.xml446
-rw-r--r--lib/stdlib/doc/src/ordsets.xml2
-rw-r--r--lib/stdlib/doc/src/proc_lib.xml49
-rw-r--r--lib/stdlib/doc/src/ref_man.xml3
-rw-r--r--lib/stdlib/doc/src/sets.xml2
-rw-r--r--lib/stdlib/doc/src/specs.xml1
-rw-r--r--lib/stdlib/doc/src/string.xml2
-rw-r--r--lib/stdlib/doc/src/sys.xml2
-rw-r--r--lib/stdlib/doc/src/timer.xml2
-rw-r--r--lib/stdlib/include/assert.hrl6
-rw-r--r--lib/stdlib/src/Makefile5
-rw-r--r--lib/stdlib/src/array.erl2
-rw-r--r--lib/stdlib/src/beam_lib.erl25
-rw-r--r--lib/stdlib/src/binary.erl2
-rw-r--r--lib/stdlib/src/c.erl2
-rw-r--r--lib/stdlib/src/dets.erl2
-rw-r--r--lib/stdlib/src/dets_utils.erl2
-rw-r--r--lib/stdlib/src/edlin.erl2
-rw-r--r--lib/stdlib/src/epp.erl127
-rw-r--r--lib/stdlib/src/erl_error.erl (renamed from lib/stdlib/src/lib.erl)327
-rw-r--r--lib/stdlib/src/erl_eval.erl282
-rw-r--r--lib/stdlib/src/erl_internal.erl4
-rw-r--r--lib/stdlib/src/erl_parse.yrl4
-rw-r--r--lib/stdlib/src/erl_posix_msg.erl4
-rw-r--r--lib/stdlib/src/erl_pp.erl4
-rw-r--r--lib/stdlib/src/escript.erl4
-rw-r--r--lib/stdlib/src/ets.erl28
-rw-r--r--lib/stdlib/src/file_sorter.erl2
-rw-r--r--lib/stdlib/src/gen.erl2
-rw-r--r--lib/stdlib/src/gen_event.erl4
-rw-r--r--lib/stdlib/src/gen_fsm.erl42
-rw-r--r--lib/stdlib/src/gen_server.erl10
-rw-r--r--lib/stdlib/src/gen_statem.erl8
-rw-r--r--lib/stdlib/src/io.erl13
-rw-r--r--lib/stdlib/src/io_lib.erl49
-rw-r--r--lib/stdlib/src/io_lib_format.erl8
-rw-r--r--lib/stdlib/src/io_lib_pretty.erl14
-rw-r--r--lib/stdlib/src/maps.erl168
-rw-r--r--lib/stdlib/src/ms_transform.erl2
-rw-r--r--lib/stdlib/src/ordsets.erl2
-rw-r--r--lib/stdlib/src/otp_internal.erl13
-rw-r--r--lib/stdlib/src/pool.erl2
-rw-r--r--lib/stdlib/src/proc_lib.erl140
-rw-r--r--lib/stdlib/src/qlc.erl10
-rw-r--r--lib/stdlib/src/rand.erl2
-rw-r--r--lib/stdlib/src/sets.erl2
-rw-r--r--lib/stdlib/src/shell.erl6
-rw-r--r--lib/stdlib/src/slave.erl16
-rw-r--r--lib/stdlib/src/stdlib.app.src4
-rw-r--r--lib/stdlib/src/string.erl182
-rw-r--r--lib/stdlib/src/supervisor.erl8
-rw-r--r--lib/stdlib/src/supervisor_bridge.erl6
-rw-r--r--lib/stdlib/src/uri_string.erl231
-rw-r--r--lib/stdlib/src/zip.erl2
-rw-r--r--lib/stdlib/test/Makefile3
-rw-r--r--lib/stdlib/test/array_SUITE.erl2
-rw-r--r--lib/stdlib/test/beam_lib_SUITE.erl32
-rw-r--r--lib/stdlib/test/c_SUITE.erl2
-rw-r--r--lib/stdlib/test/dets_SUITE.erl2
-rw-r--r--lib/stdlib/test/epp_SUITE.erl173
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl2
-rw-r--r--lib/stdlib/test/error_logger_h_SUITE.erl2
-rw-r--r--lib/stdlib/test/ets_SUITE.erl108
-rw-r--r--lib/stdlib/test/id_transform_SUITE.erl2
-rw-r--r--lib/stdlib/test/io_SUITE.erl38
-rw-r--r--lib/stdlib/test/lists_SUITE.erl2
-rw-r--r--lib/stdlib/test/maps_SUITE.erl6
-rw-r--r--lib/stdlib/test/proc_lib_SUITE.erl12
-rw-r--r--lib/stdlib/test/property_test/uri_string_recompose.erl262
-rw-r--r--lib/stdlib/test/qlc_SUITE.erl8
-rw-r--r--lib/stdlib/test/re_SUITE.erl2
-rw-r--r--lib/stdlib/test/sets_SUITE.erl2
-rw-r--r--lib/stdlib/test/sets_test_lib.erl2
-rw-r--r--lib/stdlib/test/shell_SUITE.erl6
-rw-r--r--lib/stdlib/test/stdlib.spec2
-rw-r--r--lib/stdlib/test/stdlib_bench_SUITE.erl67
-rw-r--r--lib/stdlib/test/string_SUITE.erl26
-rw-r--r--lib/stdlib/test/supervisor_1.erl2
-rw-r--r--lib/stdlib/test/supervisor_SUITE.erl2
-rw-r--r--lib/stdlib/test/sys_SUITE.erl2
-rw-r--r--lib/stdlib/test/unicode_util_SUITE.erl2
-rw-r--r--lib/stdlib/test/uri_string_SUITE.erl273
-rw-r--r--lib/stdlib/test/uri_string_property_test_SUITE.erl9
-rw-r--r--lib/stdlib/test/zip_SUITE.erl2
-rw-r--r--lib/stdlib/vsn.mk2
-rw-r--r--lib/syntax_tools/doc/src/Makefile3
-rw-r--r--lib/syntax_tools/doc/src/notes.xml41
-rw-r--r--lib/syntax_tools/src/epp_dodger.erl36
-rw-r--r--lib/syntax_tools/src/erl_prettypr.erl7
-rw-r--r--lib/syntax_tools/src/erl_syntax.erl45
-rw-r--r--lib/syntax_tools/src/erl_syntax_lib.erl4
-rw-r--r--lib/syntax_tools/src/igor.erl2
-rw-r--r--lib/syntax_tools/test/syntax_tools_SUITE.erl25
-rw-r--r--lib/syntax_tools/vsn.mk2
-rw-r--r--lib/tftp/Makefile2
-rw-r--r--lib/tftp/doc/src/Makefile1
-rw-r--r--lib/tftp/doc/src/tftp.xml6
-rw-r--r--lib/tftp/src/Makefile2
-rw-r--r--lib/tftp/src/tftp.erl2
-rw-r--r--lib/tftp/src/tftp.hrl2
-rw-r--r--lib/tftp/src/tftp_binary.erl2
-rw-r--r--lib/tftp/src/tftp_engine.erl2
-rw-r--r--lib/tftp/src/tftp_file.erl2
-rw-r--r--lib/tftp/src/tftp_lib.erl2
-rw-r--r--lib/tftp/src/tftp_logger.erl2
-rw-r--r--lib/tftp/src/tftp_sup.erl2
-rw-r--r--lib/tftp/test/tftp_SUITE.erl2
-rw-r--r--lib/tftp/test/tftp_test_lib.erl2
-rw-r--r--lib/tftp/test/tftp_test_lib.hrl2
-rw-r--r--lib/tools/doc/src/Makefile3
-rw-r--r--lib/tools/doc/src/cover.xml6
-rw-r--r--lib/tools/doc/src/fprof.xml12
-rw-r--r--lib/tools/doc/src/instrument.xml13
-rw-r--r--lib/tools/doc/src/lcnt.xml2
-rw-r--r--lib/tools/doc/src/notes.xml23
-rw-r--r--lib/tools/emacs/erlang.el16
-rw-r--r--lib/tools/priv/styles.css91
-rw-r--r--lib/tools/src/Makefile5
-rw-r--r--lib/tools/src/cover.erl111
-rw-r--r--lib/tools/src/fprof.erl2
-rw-r--r--lib/tools/src/lcnt.erl2
-rw-r--r--lib/tools/test/emacs_SUITE.erl2
-rw-r--r--lib/tools/test/eprof_SUITE_data/eed.erl6
-rw-r--r--lib/tools/test/instrument_SUITE.erl35
-rw-r--r--lib/tools/test/lcnt_SUITE.erl2
-rw-r--r--lib/tools/test/xref_SUITE.erl6
-rw-r--r--lib/tools/vsn.mk2
-rw-r--r--lib/wx/api_gen/gen_util.erl2
-rw-r--r--lib/wx/api_gen/gl_gen.erl2
-rw-r--r--lib/wx/api_gen/gl_gen_erl.erl2
-rw-r--r--lib/wx/api_gen/gl_scan_doc.erl2
-rw-r--r--lib/wx/api_gen/wx_gen.erl2
-rw-r--r--lib/wx/api_gen/wx_gen_cpp.erl2
-rw-r--r--lib/wx/api_gen/wx_gen_erl.erl2
-rw-r--r--lib/wx/api_gen/wxapi.conf2
-rw-r--r--lib/wx/c_src/wxe_driver.c167
-rw-r--r--lib/wx/c_src/wxe_driver.h2
-rw-r--r--lib/wx/c_src/wxe_main.cpp15
-rw-r--r--lib/wx/c_src/wxe_ps_init.c2
-rw-r--r--lib/wx/doc/overview.edoc2
-rw-r--r--lib/wx/doc/src/Makefile5
-rw-r--r--lib/wx/doc/src/notes.xml18
-rw-r--r--lib/wx/examples/demo/ex_aui.erl2
-rw-r--r--lib/wx/examples/demo/ex_graphicsContext.erl2
-rw-r--r--lib/wx/examples/simple/hello.erl2
-rw-r--r--lib/wx/examples/simple/hello2.erl2
-rw-r--r--lib/wx/examples/simple/menu.erl2
-rw-r--r--lib/wx/examples/simple/minimal.erl2
-rw-r--r--lib/wx/examples/sudoku/sudoku.erl2
-rw-r--r--lib/wx/examples/sudoku/sudoku_game.erl2
-rw-r--r--lib/wx/examples/sudoku/sudoku_gui.erl2
-rw-r--r--lib/wx/examples/xrc/xrc.erl2
-rw-r--r--lib/wx/src/wx.erl2
-rw-r--r--lib/wx/src/wxe_master.erl2
-rw-r--r--lib/wx/src/wxe_server.erl2
-rw-r--r--lib/wx/test/wx_app_SUITE.erl2
-rw-r--r--lib/wx/test/wx_class_SUITE.erl2
-rw-r--r--lib/wx/test/wx_event_SUITE.erl6
-rw-r--r--lib/wx/test/wx_opengl_SUITE.erl2
-rw-r--r--lib/wx/test/wx_test_lib.erl2
-rw-r--r--lib/wx/test/wx_xtra_SUITE.erl2
-rwxr-xr-xlib/wx/test/wxt4
-rw-r--r--lib/wx/test/wxt.erl2
-rw-r--r--lib/wx/vsn.mk2
-rw-r--r--lib/xmerl/doc/src/Makefile3
-rw-r--r--lib/xmerl/doc/src/notes.xml17
-rw-r--r--lib/xmerl/src/xmerl_scan.erl2
-rw-r--r--lib/xmerl/src/xmerl_xsd.erl2
-rw-r--r--lib/xmerl/test/xmerl_SUITE_data/eventp/CMOM.xml26
-rw-r--r--lib/xmerl/test/xmerl_SUITE_data/eventp/CelloMOM.xml26
-rw-r--r--lib/xmerl/vsn.mk2
-rwxr-xr-xmake/cross_check_erl2
-rwxr-xr-xmake/emd2exml.in2
-rwxr-xr-xmake/make_emakefile.in2
-rw-r--r--make/otp.mk.in7
-rw-r--r--make/otp_release_targets.mk11
-rw-r--r--otp_versions.table15
-rwxr-xr-xscripts/build-otp46
-rwxr-xr-xscripts/bundle-otp41
-rwxr-xr-xscripts/diffable15
-rwxr-xr-xscripts/pre-push37
-rwxr-xr-xscripts/run-dialyzer5
-rw-r--r--system/doc/design_principles/Makefile1
-rw-r--r--system/doc/design_principles/applications.xml12
-rw-r--r--system/doc/design_principles/gen_server_concepts.xml2
-rw-r--r--system/doc/design_principles/release_structure.xml2
-rw-r--r--system/doc/design_principles/spec_proc.xml2
-rw-r--r--system/doc/design_principles/statem.xml49
-rw-r--r--system/doc/efficiency_guide/Makefile3
-rw-r--r--system/doc/efficiency_guide/advanced.xml7
-rw-r--r--system/doc/efficiency_guide/binaryhandling.xml2
-rw-r--r--system/doc/efficiency_guide/profiling.xml2
-rw-r--r--system/doc/efficiency_guide/xmlfiles.mk2
-rw-r--r--system/doc/embedded/Makefile3
-rw-r--r--system/doc/embedded/starting.xml2
-rw-r--r--system/doc/getting_started/Makefile3
-rw-r--r--system/doc/getting_started/conc_prog.xml2
-rw-r--r--system/doc/installation_guide/Makefile3
-rw-r--r--system/doc/installation_guide/xmlfiles.mk2
-rw-r--r--system/doc/oam/Makefile3
-rw-r--r--system/doc/programming_examples/Makefile3
-rw-r--r--system/doc/programming_examples/xmlfiles.mk2
-rw-r--r--system/doc/reference_manual/Makefile3
-rw-r--r--system/doc/reference_manual/expressions.xml5
-rw-r--r--system/doc/reference_manual/introduction.xml4
-rw-r--r--system/doc/reference_manual/macros.xml37
-rw-r--r--system/doc/reference_manual/modules.xml2
-rw-r--r--system/doc/reference_manual/xmlfiles.mk2
-rw-r--r--system/doc/system_architecture_intro/Makefile3
-rw-r--r--system/doc/system_architecture_intro/sys_arch_intro.xml2
-rw-r--r--system/doc/system_principles/Makefile3
-rw-r--r--system/doc/system_principles/create_target.xmlsrc2
-rw-r--r--system/doc/system_principles/error_logging.xml117
-rw-r--r--system/doc/system_principles/misc.xml198
-rw-r--r--system/doc/system_principles/part.xml3
-rw-r--r--system/doc/system_principles/system_principles.xml4
-rw-r--r--system/doc/system_principles/versions.xml41
-rw-r--r--system/doc/system_principles/xmlfiles.mk5
-rw-r--r--system/doc/top/Makefile2
-rw-r--r--system/doc/top/book.xml2
-rw-r--r--system/doc/tutorial/Makefile3
-rw-r--r--system/doc/tutorial/xmlfiles.mk2
-rw-r--r--xcomp/erl-xcomp-armv8-rpi3-linux-gnueabihf.conf276
1477 files changed, 28826 insertions, 17903 deletions
diff --git a/.gitignore b/.gitignore
index 79b1d5dfad..0e9d07757f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -119,7 +119,9 @@ JAVADOC-GENERATED
/bootstrap/lib/common_test
/bootstrap/lib/edoc
/bootstrap/lib/erl_docgen
+/bootstrap/lib/erl_interface
/bootstrap/lib/hipe
+/bootstrap/lib/jinterface
/bootstrap/lib/parsetools
/bootstrap/lib/runtime_tools
/bootstrap/lib/sasl
diff --git a/.travis.yml b/.travis.yml
index 5499eb22c4..ee724f8947 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -23,25 +23,67 @@ addons:
matrix:
include:
- - env: Linux32
- os: linux
- services:
- - docker
- script:
- - ./scripts/build-docker-otp 32 sh -c "scripts/build-otp && ./otp_build tests && scripts/run-smoke-tests && bin/dialyzer --build_plt --apps erts kernel stdlib"
+ # Dialyzer is first as it takes the longest to run
- env: Linux64Dialyzer
- os: linux
+ addons:
+ apt:
+ packages:
+ # Don't build with wx, java or xslt to get faster build
+ - autoconf
+ - libncurses-dev
+ - build-essential
+ - libssl-dev
script:
- ./scripts/build-otp
- ./scripts/run-dialyzer
+ - env: Linux32
+ services:
+ - docker
+ script:
+ - ./scripts/build-docker-otp 32 sh -c "scripts/build-otp release && ./otp_build tests && scripts/run-smoke-tests && bin/dialyzer --build_plt --apps erts kernel stdlib"
- env: Linux64SmokeTest
- os: linux
script:
- ./scripts/build-otp
- ./otp_build tests
- - make release_docs
- - make xmllint
- ./scripts/run-smoke-tests
+ - env: Linux64Docbuild
+ script:
+ - ./scripts/build-otp docs
+ deploy:
+ provider: pages
+ repo: erlang/cd
+ target-branch: master
+ skip-cleanup: true
+ keep-history: true
+ verbose: true
+ github-token: $ERLANG_CD_GITHUB_TOKEN
+ on:
+ # We only deploy on pushes to branches
+ all_branches: true
+ tags: false
+ condition: $TRAVIS_PULL_REQUEST = "false"
+ repo: erlang/otp
+ # This stage publishes a otp bundle that contains multiple
+ # Erlang/OTP source repositories
+ - stage: deploy
+ env: Deploy
+ if: tag =~ ^OTP-[0-9]+\.[0-9]+$
+ script:
+ - ./scripts/bundle-otp
+ deploy:
+ provider: releases
+ skip_cleanup: true
+ api_key:
+ secure: vW5PN6zng5H5+TCvwfwpGZsABrdCWYcFwDm3KXq+plsecBmTayu/0jgNso5Z97FbzDGVTLHWchvywEYQWnmrEByyOrqH73v1LN6JEfN99VpSrdFr15IzhblcyU1R9ugYc3WEoYjX0Q1uGelDSWRuuQOPbzy8mZf3D4rSGonyraP7jPTdHhs5P3ZWk6OMFz+tCdF4XohXqbhXIBOeH/EKg0svX2u5IcV01/YOL8LHWz6G7+gqBryEXx1+ngjQXQmMQwd7Yg3WOKE4XV9gX8ixZsbpUPZXAQKF+VOYdEgeiIr1hI0tBQUYX7FYEzYH5MCxqng5RdaPTOAm1oQroyGkIcWSXzDwN4AhJ7xqa/0NRdEaBPdQzPBCc+pVUDkxBR1ytXjBQqdQMnI6184TDiU5XBnj3kmieLkkKPKQNoPve/Y8Q8zutw4GNc7gixGcQCjtAFUbrT73QVRrezQH0qIdt23rivvf2R7CCOWSmgzowrswmtHdgeEVbodUIBPTNp7qzlUk9gDp6vW0XrOC4qEFI+VaY5PsEOXrrxZmI3gGGJgsbfzRvzvvupQcLNERniJ67r/uumbForpL0x1c65scKuMWwcn1wqt2OLbDoIIuM31Ph2HX/09TTqECU7CTvqLT5MnbZHXGjY9c3ch+sY3tSfaEX6aazl/Dqx28c7boCEw=
+ file:
+ - ${TRAVIS_TAG}-bundle.txt
+ - ${TRAVIS_TAG}-bundle.tar.gz
+ on:
+ # We only deploy on pushes to tags that match the regexp
+ tags: true
+ condition: $TRAVIS_TAG =~ ^OTP-[0-9]+\.[0-9]+$
+ repo: erlang/otp
+
before_script:
- set -e
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c89301d0eb..96db464b52 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -43,6 +43,7 @@ for more information.
You can contribute to Erlang/OTP by opening a Pull Request.
Make sure you create a new branch for your pull request with `git checkout -b new-branch-name`.
+Give the branch a short but descriptive name, like `stdlib/lists-length-fix`.
Never do your work directly on `maint` or `master`.
## Fixing a bug
@@ -108,6 +109,7 @@ conflicts or include the latest changes.
compiled and that it works.
* Check for unnecessary whitespace before committing with `git diff --check`.
+However, do not fix preexisting whitespace errors in otherwise untouched source lines.
Check your coding style:
diff --git a/HOWTO/INSTALL-RASPBERRYPI3.md b/HOWTO/INSTALL-RASPBERRYPI3.md
new file mode 100644
index 0000000000..536d095cb4
--- /dev/null
+++ b/HOWTO/INSTALL-RASPBERRYPI3.md
@@ -0,0 +1,323 @@
+# Cross Compiling Erlang/OTP - Raspberry Pi 3
+
+
+## Introduction
+
+This document describes how to build a toolchain and cross compile Erlang/OTP
+to Raspberry Pi 3 on macOS High Sierra. It is recommended to consult
+[Building and Installing Erlang/OTP](https://github.com/erlang/otp/blob/master/HOWTO/INSTALL.md) and [Cross Compiling Erlang/OTP](https://github.com/erlang/otp/blob/master/HOWTO/INSTALL-CROSS.md) before attempting to follow the instructions in this guide.
+
+The whole process takes several hours and depending on the package versions different problems may arise that require additional
+fixes not described in this document. In other words, it is not fun to build a toolchain. I assume that you have a Mac and would
+like to develop Erlang/OTP applications based on the latest OTP release (or master) that not yet released as a binary for
+Raspberry Pi 3.
+
+The first and most time consuming step is building the toolchain from scratch. Once your cross compiler is ready you cross compile
+all library dependencies and create the sysroot file system. In the last step you cross compile Erlang/OTP using the new
+toolchain and sysroot.
+
+#### Tested Configuration
+
+macOS High Sierra 10.13.2<br>
+Raspberry Pi Model B Rev 1.2<br>
+Crosstools-NG 1.23.0_1
+
+> Note: /proc/device/tree/model contains model information of your
+> Raspberry Pi.
+
+
+#### Install Crosstool NG
+
+ (1)
+
+ $ brew install crosstool-ng
+ $ brew install grep --default-names # needed by crosstools-ng scripts
+ $ brew install md5sha1sum # needed by crosstools-ng populate script
+
+
+#### Create case-sensitive disk images
+
+ (2)
+
+Create two case-sensitive disk images using Disk Utility:
+
+`File -> New Image -> Blank Image...`
+
+Format: `Mac OS Extended (Case-sensitive, Journaled)`
+
+```
+/Volumes/xtools-build-env 15 GB
+/Volumes/xtools           500 MB
+```
+
+The first image holds all source and object files while building the toolchain. The second image houses the compiled
+toolchain.
+
+## Building the Toolchain
+
+
+#### Configure crosstool-ng
+
+ (4)
+
+ $ ct-ng armv8-rpi3-linux-gnueabihf
+ $ ct-ng menuconfig
+
+#### Modify *path* section
+
+* Local tarballs directory: `/Volumes/xtools-build-env/src`
+* Working directory: `/Volumes/xtools-build-env/.build`
+* Prefix directory: `/Volumes/xtools/${CT_TARGET}`
+
+#### Modify *Extracting* section
+
+* Check option: _Stop after extracting tarballs_.
+
+> Note: The build shall stop after the tarballs have been extracted to give us time to fix source code problems.
+
+#### Enable STOP / RESTART
+
+Edit /Volumes/xtools-build-env/.config
+  `CT_DEBUG_CT_SAVE_STEPS=y`
+
+Should the build break at a particular build step, you can fix the problem and continue the build from where it broke.
+
+Short summary of the most common `ct-ng` commands:
+
+* Listing all build steps
+
+```
+    $ ct-ng list-steps
+
+ Available build steps, in order:
+ - companion_tools_for_build
+ - companion_libs_for_build
+ - binutils_for_build
+ - companion_tools_for_host
+ - companion_libs_for_host
+ - binutils_for_host
+ - cc_core_pass_1
+ - kernel_headers
+ - libc_start_files
+ - cc_core_pass_2
+ - libc
+ - cc_for_build
+ - cc_for_host
+ - libc_post_cc
+ - companion_libs_for_target
+ - binutils_for_target
+ - debug
+ - test_suite
+    - finish
+```
+
+* Re-run step
+```
+    $ ct-ng step
+```
+
+* Restart from step
+```
+    $ ct-ng step+
+```
+
+* Run until step
+```
+    $ ct-ng +step
+```
+
+#### Fix file permissions on crosstool-NG.sh
+
+ (5)
+
+ $ chmod 744 /usr/local/Cellar/crosstool-ng/1.23.0_1/lib/crosstool-ng-1.23.0/scripts/crosstool-NG.sh
+
+#### Run build command
+
+Build process stops just after the tarballs have been extracted.
+
+ (6)
+
+ $ ct-ng build
+
+ Retrieving needed toolchain components' tarballs
+ [EXTRA] Retrieving 'make-4.2.1'
+ [EXTRA] Retrieving 'm4-1.4.18'
+ [EXTRA] Retrieving 'linux-4.10.8'
+ [EXTRA] Retrieving 'gmp-6.1.2'
+ [EXTRA] Retrieving 'mpfr-3.1.5'
+ [EXTRA] Retrieving 'isl-0.16.1'
+ [EXTRA] Retrieving 'mpc-1.0.3'
+ [EXTRA] Retrieving 'expat-2.2.0'
+ [EXTRA] Retrieving 'ncurses-6.0'
+ [EXTRA] Retrieving 'libiconv-1.15'
+ [EXTRA] Retrieving 'gettext-0.19.8.1'
+ [EXTRA] Retrieving 'binutils-2.28'
+ [EXTRA] Retrieving 'gcc-6.3.0'
+ [EXTRA] Retrieving 'glibc-2.25'
+ [EXTRA] Retrieving 'gdb-7.12.1'
+
+#### Fix source files
+
+ (7)
+
+Add macro to /Volumes/xtools-build-env/.build/src/gdb-7.12.1/gdb/doublest.c:
+```C
+#define min(a,b) \
+ ({ typeof (a) _a = (a); \
+ typeof (b) _b = (b); \
+    _a < _b ? _a : _b; })
+```
+
+  (8) Update ulimit
+
+ $ ulimit -n 1024
+
+#### Modify *extract* section
+
+ (8)
+
+ $ ct-ng menuconfig
+
+ Uncheck option: _Stop after extracting tarballs_
+
+#### Re-run build command
+
+Restarts build process from where it previously stopped.
+
+ (9)
+
+ $ ct-ng build
+
+#### Fix gettext
+
+Build will fail at step `companion_tools_for_build` but it can be fixed by running autoreconf:
+
+ (10)
+
+ $ cd .build/src/gettext-0.19.8.1/
+ $ ./autoreconf
+ $ ct-ng companion_tools_for_build+
+
+#### Test the toolchain
+
+ (11)
+
+ $ cat > test.c
+ $ int main() { printf("Hello, world!\n"); return 0; }
+ $ /Volumes/xtools/arm-unknown-linux-gnueabi-gcc -o test test.c
+
+ (12) OPTIONAL
+
+ “Render the toolchain read-only” from crosstool-NG’s “Paths and misc options” configuration page.
+
+
+## Cross compiling dependencies
+
+ (13)
+
+ $ export PATH=/Volumes/xtools/armv8-rpi3-linux-gnueabihf/bin:$PATH
+
+#### Cross compiling zlib
+
+ (14)
+
+ $ wget http://zlib.net/zlib-1.2.11.tar.gz
+ $ tar xf zlib-1.2.11.tar.gz
+ $ cd zlib-1.2.11
+ $ CHOST=armv8-rpi3-linux-gnueabihf ./configure --prefix=/Users/<username>/git/raspberrypi/arm
+ $ make
+ $ make install
+
+#### Cross compiling openssl
+
+ (15)
+
+ $ wget http://openssl.org/source/openssl-1.1.0g.tar.gz
+ $ tar xf openssl-1.1.0g.tar.gz
+ $ cd openssl-1.1.0g
+ $ ./Configure linux-generic32 --prefix=/Users/<username>/git/raspberrypi/arm --openssldir=/Users/<username>/git/raspberrypi/arm/openssl --cross-compile-prefix=armv8-rpi3-linux-gnueabihf
+ $ make
+ $ make install
+
+#### Cross compiling ncurses
+
+ (16)
+
+ $ wget http://ftp.gnu.org/pub/gnu/ncurses/ncurses-5.9.tar.gz
+
+
+ (17)
+
+Apply patch:
+
+```patch
+--- a/ncurses/base/MKlib_gen.sh
++++ b/ncurses/base/MKlib_gen.sh
+@@ -474,11 +474,22 @@ sed -n -f $ED1 \
+ -e 's/gen_$//' \
+ -e 's/ / /g' >>$TMP
+
++cat >$ED1 <<EOF
++s/ / /g
++s/^ //
++s/ $//
++s/P_NCURSES_BOOL/NCURSES_BOOL/g
++EOF
++
++# A patch discussed here:
++# https://gcc.gnu.org/ml/gcc-patches/2014-06/msg02185.html
++# introduces spurious #line markers. Work around that by ignoring the system's
++# attempt to define "bool" and using our own symbol here.
++sed -e 's/bool/P_NCURSES_BOOL/g' $TMP > $ED2
++cat $ED2 >$TMP
++
+ $preprocessor $TMP 2>/dev/null \
+-| sed \
+- -e 's/ / /g' \
+- -e 's/^ //' \
+- -e 's/_Bool/NCURSES_BOOL/g' \
++| sed -f $ED1 \
+ | $AWK -f $AW2 \
+ | sed -f $ED3 \
+ | sed \
+```
+
+  (18)
+
+ $ ./configure --build=x86_64-apple-darwin17.3.0 --host=armv8-rpi3-linux-gnueabihf --without-ada --without-cxx --without-cxx-binding --without-manpages --without-progs --without-tests --prefix=/usr --libdir=/lib --with-build-cc="gcc -D_GNU_SOURCE" --with-shared
+ $ make
+ $ make DESTDIR=/Users/<username>/git/raspberrypi/arm install
+
+ (19)
+
+Compile ncurses test program:
+
+ $ cd test
+ $ armv8-rpi3-linux-gnueabihf-gcc -o nctest ncurses.c -I${RPI_SYSROOT}/usr/include -L${RPI_SYSROOT}/lib -lncursesw
+
+
+## Populating sysroot
+
+ (19)
+
+ Edit /Volumes/xtools/armv8-rpi3-linux-gnueabihf/bin/armv8-rpi3-linux-gnueabihf-populate:
+
+ sed="gsed"
+
+ (20)
+
+ $ armv8-rpi3-linux-gnueabihf-populate -s /Users/<username>/git/raspberrypi/arm -d /Users/<username>/git/raspberrypi/sysroot
+ $ export RPI_SYSROOT=/Users/<username>/git/raspberrypi/sysroot
+
+
+## Cross compiling Erlang/OTP
+
+ (21)
+
+ $ LC_CTYPE=C && LANG=C && ./otp_build autoconf
+ $ ./otp_build configure --disable-dynamic-ssl-lib --xcomp-conf=./xcomp/erl-xcomp-armv8-rpi3-linux-gnueabihf.conf
+ $ ./otp_build boot -a
+ $ ./otp_build release -a /Users/<username>/git/raspberrypi/erlang
+ $ tar czf erlang.tgz ./erlang
+
diff --git a/HOWTO/INSTALL.md b/HOWTO/INSTALL.md
index 2597794496..456dafeba5 100644
--- a/HOWTO/INSTALL.md
+++ b/HOWTO/INSTALL.md
@@ -77,8 +77,6 @@ also find the utilities needed for building the documentation.
Download from <http://www.oracle.com/technetwork/java/javase/downloads>.
We have also tested with IBM's JDK 1.6.0.
-* X Windows -- Development headers and libraries are needed
- to build the Erlang/OTP application `gs` on Unix/Linux.
* `flex` -- Headers and libraries are needed to build the flex
scanner for the `megaco` application on Unix/Linux.
* wxWidgets -- Toolkit for GUI applications.
diff --git a/Makefile.in b/Makefile.in
index e75bcf7f10..d880bfefa2 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -351,6 +351,9 @@ is_cross_configured:
target_configured:
@echo @TARGET@
+erlang_inst_libdir_configured:
+ @echo $(ERLANG_INST_LIBDIR)
+
bootstrap: depend all_bootstraps
@@ -681,6 +684,14 @@ tertiary_bootstrap_copy:
$(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/common_test/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/common_test/include ; fi
$(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/runtime_tools ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/runtime_tools ; fi
$(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/runtime_tools/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/runtime_tools/include ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/erl_interface ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/erl_interface ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/erl_interface/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/erl_interface/include ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/ ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/ ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv/com ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv/com ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv/com/ericsson ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv/com/ericsson ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv/com/ericsson/otp ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv/com/ericsson/otp ; fi
+ $(V_at)if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv/com/ericsson/otp/erlang ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv/com/ericsson/otp/erlang ; fi
$(V_at)for x in lib/sasl/ebin/*.beam; do \
BN=`basename $$x`; \
TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/sasl/ebin/$$BN; \
@@ -749,6 +760,38 @@ tertiary_bootstrap_copy:
cp $$x $$TF; \
true; \
done
+# copy erl_interface includes
+ $(V_at)for x in lib/erl_interface/include/*; do \
+ BN=`basename $$x`; \
+ TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/erl_interface/include/$$BN; \
+ test -f $$TF && \
+ test '!' -z "`find $$x -newer $$TF -print`" && \
+ cp $$x $$TF; \
+ test '!' -f $$TF && \
+ cp $$x $$TF; \
+ true; \
+ done
+# copy jinterface priv directory
+ $(V_at)for x in lib/jinterface/priv/OtpErlang.jar; do \
+ BN=`basename $$x`; \
+ TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv/$$BN; \
+ test -f $$TF && \
+ test '!' -z "`find $$x -newer $$TF -print`" && \
+ cp $$x $$TF; \
+ test '!' -f $$TF && \
+ cp $$x $$TF; \
+ true; \
+ done
+ $(V_at)for x in lib/jinterface/priv/com/ericsson/otp/erlang/*; do \
+ BN=`basename $$x`; \
+ TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/jinterface/priv/com/ericsson/otp/erlang/$$BN; \
+ test -f $$TF && \
+ test '!' -z "`find $$x -newer $$TF -print`" && \
+ cp $$x $$TF; \
+ test '!' -f $$TF && \
+ cp $$x $$TF; \
+ true; \
+ done
# $(V_at)cp lib/syntax_tools/ebin/*.beam $(BOOTSTRAP_ROOT)/bootstrap/lib/syntax_tools/ebin
doc_bootstrap_build:
diff --git a/OTP_VERSION b/OTP_VERSION
index 2acad36e08..a12e109d04 100644
--- a/OTP_VERSION
+++ b/OTP_VERSION
@@ -1 +1 @@
-21.0-rc1
+22.0-rc0
diff --git a/bootstrap/bin/no_dot_erlang.boot b/bootstrap/bin/no_dot_erlang.boot
index fe11c1d256..127072b3ed 100644
--- a/bootstrap/bin/no_dot_erlang.boot
+++ b/bootstrap/bin/no_dot_erlang.boot
Binary files differ
diff --git a/bootstrap/bin/start.boot b/bootstrap/bin/start.boot
index fe11c1d256..127072b3ed 100644
--- a/bootstrap/bin/start.boot
+++ b/bootstrap/bin/start.boot
Binary files differ
diff --git a/bootstrap/bin/start_clean.boot b/bootstrap/bin/start_clean.boot
index fe11c1d256..127072b3ed 100644
--- a/bootstrap/bin/start_clean.boot
+++ b/bootstrap/bin/start_clean.boot
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_dead.beam b/bootstrap/lib/compiler/ebin/beam_dead.beam
index 8934cb5d11..534eb65372 100644
--- a/bootstrap/lib/compiler/ebin/beam_dead.beam
+++ b/bootstrap/lib/compiler/ebin/beam_dead.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_disasm.beam b/bootstrap/lib/compiler/ebin/beam_disasm.beam
index 5e3585ada7..2d9bc49992 100644
--- a/bootstrap/lib/compiler/ebin/beam_disasm.beam
+++ b/bootstrap/lib/compiler/ebin/beam_disasm.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_jump.beam b/bootstrap/lib/compiler/ebin/beam_jump.beam
index e13be6fb24..6af8a015c0 100644
--- a/bootstrap/lib/compiler/ebin/beam_jump.beam
+++ b/bootstrap/lib/compiler/ebin/beam_jump.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_peep.beam b/bootstrap/lib/compiler/ebin/beam_peep.beam
index 1bf1e5a79f..5f33584fe4 100644
--- a/bootstrap/lib/compiler/ebin/beam_peep.beam
+++ b/bootstrap/lib/compiler/ebin/beam_peep.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_trim.beam b/bootstrap/lib/compiler/ebin/beam_trim.beam
index 75fcff822e..32cc6efe88 100644
--- a/bootstrap/lib/compiler/ebin/beam_trim.beam
+++ b/bootstrap/lib/compiler/ebin/beam_trim.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_type.beam b/bootstrap/lib/compiler/ebin/beam_type.beam
index f21ede5043..266c04acfd 100644
--- a/bootstrap/lib/compiler/ebin/beam_type.beam
+++ b/bootstrap/lib/compiler/ebin/beam_type.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_utils.beam b/bootstrap/lib/compiler/ebin/beam_utils.beam
index 0eeb313856..5648719621 100644
--- a/bootstrap/lib/compiler/ebin/beam_utils.beam
+++ b/bootstrap/lib/compiler/ebin/beam_utils.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_validator.beam b/bootstrap/lib/compiler/ebin/beam_validator.beam
index db49f6f0fa..2bcec9ca3c 100644
--- a/bootstrap/lib/compiler/ebin/beam_validator.beam
+++ b/bootstrap/lib/compiler/ebin/beam_validator.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/cerl.beam b/bootstrap/lib/compiler/ebin/cerl.beam
index 97e0c72b15..4f8ae7ca43 100644
--- a/bootstrap/lib/compiler/ebin/cerl.beam
+++ b/bootstrap/lib/compiler/ebin/cerl.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/cerl_inline.beam b/bootstrap/lib/compiler/ebin/cerl_inline.beam
index 6b365ce68f..f0d6063f19 100644
--- a/bootstrap/lib/compiler/ebin/cerl_inline.beam
+++ b/bootstrap/lib/compiler/ebin/cerl_inline.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam
index 99a6c5d7f0..d1a9058417 100644
--- a/bootstrap/lib/compiler/ebin/compile.beam
+++ b/bootstrap/lib/compiler/ebin/compile.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/compiler.appup b/bootstrap/lib/compiler/ebin/compiler.appup
index a8847fc407..350a3924e7 100644
--- a/bootstrap/lib/compiler/ebin/compiler.appup
+++ b/bootstrap/lib/compiler/ebin/compiler.appup
@@ -16,7 +16,7 @@
%% limitations under the License.
%%
%% %CopyrightEnd%
-{"7.1.4",
+{"7.1.5",
[{<<".*">>,[{restart_application, compiler}]}],
[{<<".*">>,[{restart_application, compiler}]}]
}.
diff --git a/bootstrap/lib/compiler/ebin/core_lint.beam b/bootstrap/lib/compiler/ebin/core_lint.beam
index e24a473a4c..567e381ee8 100644
--- a/bootstrap/lib/compiler/ebin/core_lint.beam
+++ b/bootstrap/lib/compiler/ebin/core_lint.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/erl_bifs.beam b/bootstrap/lib/compiler/ebin/erl_bifs.beam
index be3dc425f4..37bd743796 100644
--- a/bootstrap/lib/compiler/ebin/erl_bifs.beam
+++ b/bootstrap/lib/compiler/ebin/erl_bifs.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/rec_env.beam b/bootstrap/lib/compiler/ebin/rec_env.beam
index bd0b9c004c..b0ef249e15 100644
--- a/bootstrap/lib/compiler/ebin/rec_env.beam
+++ b/bootstrap/lib/compiler/ebin/rec_env.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_core_fold.beam b/bootstrap/lib/compiler/ebin/sys_core_fold.beam
index 3b6f6637f0..073bb041d4 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_fold.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_fold.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_core_inline.beam b/bootstrap/lib/compiler/ebin/sys_core_inline.beam
index b4cdba519a..ebe35883b5 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_inline.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_inline.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_codegen.beam b/bootstrap/lib/compiler/ebin/v3_codegen.beam
index 5aeca65888..c537f1e550 100644
--- a/bootstrap/lib/compiler/ebin/v3_codegen.beam
+++ b/bootstrap/lib/compiler/ebin/v3_codegen.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/application_controller.beam b/bootstrap/lib/kernel/ebin/application_controller.beam
index 869c46939b..4f52e506c2 100644
--- a/bootstrap/lib/kernel/ebin/application_controller.beam
+++ b/bootstrap/lib/kernel/ebin/application_controller.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/code_server.beam b/bootstrap/lib/kernel/ebin/code_server.beam
index 736190c08c..93c354bf40 100644
--- a/bootstrap/lib/kernel/ebin/code_server.beam
+++ b/bootstrap/lib/kernel/ebin/code_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/disk_log.beam b/bootstrap/lib/kernel/ebin/disk_log.beam
index 19880724ba..4f0eae4984 100644
--- a/bootstrap/lib/kernel/ebin/disk_log.beam
+++ b/bootstrap/lib/kernel/ebin/disk_log.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/dist_util.beam b/bootstrap/lib/kernel/ebin/dist_util.beam
index e9f49343ba..3956e595f8 100644
--- a/bootstrap/lib/kernel/ebin/dist_util.beam
+++ b/bootstrap/lib/kernel/ebin/dist_util.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erl_ddll.beam b/bootstrap/lib/kernel/ebin/erl_ddll.beam
index baec5883a9..de9b1cb638 100644
--- a/bootstrap/lib/kernel/ebin/erl_ddll.beam
+++ b/bootstrap/lib/kernel/ebin/erl_ddll.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erl_epmd.beam b/bootstrap/lib/kernel/ebin/erl_epmd.beam
index d06aa1add3..449fd8dff1 100644
--- a/bootstrap/lib/kernel/ebin/erl_epmd.beam
+++ b/bootstrap/lib/kernel/ebin/erl_epmd.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erl_signal_handler.beam b/bootstrap/lib/kernel/ebin/erl_signal_handler.beam
index 881e36e6fb..1a1d9d28ee 100644
--- a/bootstrap/lib/kernel/ebin/erl_signal_handler.beam
+++ b/bootstrap/lib/kernel/ebin/erl_signal_handler.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/error_logger.beam b/bootstrap/lib/kernel/ebin/error_logger.beam
index 752c0f2bb1..8dd3c07f71 100644
--- a/bootstrap/lib/kernel/ebin/error_logger.beam
+++ b/bootstrap/lib/kernel/ebin/error_logger.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/file_io_server.beam b/bootstrap/lib/kernel/ebin/file_io_server.beam
index e889d294b8..d9ca62a82b 100644
--- a/bootstrap/lib/kernel/ebin/file_io_server.beam
+++ b/bootstrap/lib/kernel/ebin/file_io_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet.beam b/bootstrap/lib/kernel/ebin/inet.beam
index fd855be69b..7df45ea492 100644
--- a/bootstrap/lib/kernel/ebin/inet.beam
+++ b/bootstrap/lib/kernel/ebin/inet.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_db.beam b/bootstrap/lib/kernel/ebin/inet_db.beam
index 315d1126aa..513a7dc03d 100644
--- a/bootstrap/lib/kernel/ebin/inet_db.beam
+++ b/bootstrap/lib/kernel/ebin/inet_db.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_dns.beam b/bootstrap/lib/kernel/ebin/inet_dns.beam
index 7b04a63303..f483acd96c 100644
--- a/bootstrap/lib/kernel/ebin/inet_dns.beam
+++ b/bootstrap/lib/kernel/ebin/inet_dns.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_parse.beam b/bootstrap/lib/kernel/ebin/inet_parse.beam
index 561e53dcbd..175649cd81 100644
--- a/bootstrap/lib/kernel/ebin/inet_parse.beam
+++ b/bootstrap/lib/kernel/ebin/inet_parse.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam b/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam
index 9a7e36791e..c33a9e7f3a 100644
--- a/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam
+++ b/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/kernel.app b/bootstrap/lib/kernel/ebin/kernel.app
index b93a65e8fb..340ed8653f 100644
--- a/bootstrap/lib/kernel/ebin/kernel.app
+++ b/bootstrap/lib/kernel/ebin/kernel.app
@@ -68,7 +68,7 @@
logger_formatter,
logger_h_common,
logger_server,
- logger_simple,
+ logger_simple_h,
logger_std_h,
logger_sup,
net,
@@ -140,7 +140,9 @@
inet_db,
pg2]},
{applications, []},
- {env, []},
+ {env, [{logger_level, notice},
+ {logger_sasl_compatible, false}
+ ]},
{mod, {kernel, []}},
{runtime_dependencies, ["erts-10.0", "stdlib-3.5", "sasl-3.0"]}
]
diff --git a/bootstrap/lib/kernel/ebin/kernel.beam b/bootstrap/lib/kernel/ebin/kernel.beam
index 15dfd19ff8..b3f0783d25 100644
--- a/bootstrap/lib/kernel/ebin/kernel.beam
+++ b/bootstrap/lib/kernel/ebin/kernel.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger.beam b/bootstrap/lib/kernel/ebin/logger.beam
index 8b57370f82..e6d8f5b2c6 100644
--- a/bootstrap/lib/kernel/ebin/logger.beam
+++ b/bootstrap/lib/kernel/ebin/logger.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_backend.beam b/bootstrap/lib/kernel/ebin/logger_backend.beam
index ccc03d104c..be448bd75c 100644
--- a/bootstrap/lib/kernel/ebin/logger_backend.beam
+++ b/bootstrap/lib/kernel/ebin/logger_backend.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_config.beam b/bootstrap/lib/kernel/ebin/logger_config.beam
index 0fc49960b4..52f7847561 100644
--- a/bootstrap/lib/kernel/ebin/logger_config.beam
+++ b/bootstrap/lib/kernel/ebin/logger_config.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_disk_log_h.beam b/bootstrap/lib/kernel/ebin/logger_disk_log_h.beam
index 7a21b07c2d..cc1b649eb7 100644
--- a/bootstrap/lib/kernel/ebin/logger_disk_log_h.beam
+++ b/bootstrap/lib/kernel/ebin/logger_disk_log_h.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_filters.beam b/bootstrap/lib/kernel/ebin/logger_filters.beam
index 0e8c97c98e..57197e137c 100644
--- a/bootstrap/lib/kernel/ebin/logger_filters.beam
+++ b/bootstrap/lib/kernel/ebin/logger_filters.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_formatter.beam b/bootstrap/lib/kernel/ebin/logger_formatter.beam
index 2f225b0295..7f7d77ab28 100644
--- a/bootstrap/lib/kernel/ebin/logger_formatter.beam
+++ b/bootstrap/lib/kernel/ebin/logger_formatter.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_h_common.beam b/bootstrap/lib/kernel/ebin/logger_h_common.beam
index 528261f4e3..7d96f2d69e 100644
--- a/bootstrap/lib/kernel/ebin/logger_h_common.beam
+++ b/bootstrap/lib/kernel/ebin/logger_h_common.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_server.beam b/bootstrap/lib/kernel/ebin/logger_server.beam
index 2bf304e044..4885c0992a 100644
--- a/bootstrap/lib/kernel/ebin/logger_server.beam
+++ b/bootstrap/lib/kernel/ebin/logger_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_simple.beam b/bootstrap/lib/kernel/ebin/logger_simple.beam
deleted file mode 100644
index be8017391f..0000000000
--- a/bootstrap/lib/kernel/ebin/logger_simple.beam
+++ /dev/null
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_simple_h.beam b/bootstrap/lib/kernel/ebin/logger_simple_h.beam
new file mode 100644
index 0000000000..890de624b9
--- /dev/null
+++ b/bootstrap/lib/kernel/ebin/logger_simple_h.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_std_h.beam b/bootstrap/lib/kernel/ebin/logger_std_h.beam
index 7483dee399..e8c3bb83d0 100644
--- a/bootstrap/lib/kernel/ebin/logger_std_h.beam
+++ b/bootstrap/lib/kernel/ebin/logger_std_h.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/net_kernel.beam b/bootstrap/lib/kernel/ebin/net_kernel.beam
index 03627a3d53..0a565d542d 100644
--- a/bootstrap/lib/kernel/ebin/net_kernel.beam
+++ b/bootstrap/lib/kernel/ebin/net_kernel.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/ram_file.beam b/bootstrap/lib/kernel/ebin/ram_file.beam
index 658240ef1e..c2f265ede4 100644
--- a/bootstrap/lib/kernel/ebin/ram_file.beam
+++ b/bootstrap/lib/kernel/ebin/ram_file.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets_utils.beam b/bootstrap/lib/stdlib/ebin/dets_utils.beam
index 6f00fd917b..2b56a46eb1 100644
--- a/bootstrap/lib/stdlib/ebin/dets_utils.beam
+++ b/bootstrap/lib/stdlib/ebin/dets_utils.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets_v9.beam b/bootstrap/lib/stdlib/ebin/dets_v9.beam
index 088a58617c..2fda3ba53f 100644
--- a/bootstrap/lib/stdlib/ebin/dets_v9.beam
+++ b/bootstrap/lib/stdlib/ebin/dets_v9.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/epp.beam b/bootstrap/lib/stdlib/ebin/epp.beam
index 9695be2c1a..c87665ff86 100644
--- a/bootstrap/lib/stdlib/ebin/epp.beam
+++ b/bootstrap/lib/stdlib/ebin/epp.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_anno.beam b/bootstrap/lib/stdlib/ebin/erl_anno.beam
index 710a82f1fa..7a0a4c08d8 100644
--- a/bootstrap/lib/stdlib/ebin/erl_anno.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_anno.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_error.beam b/bootstrap/lib/stdlib/ebin/erl_error.beam
new file mode 100644
index 0000000000..dc9d0a8d39
--- /dev/null
+++ b/bootstrap/lib/stdlib/ebin/erl_error.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_eval.beam b/bootstrap/lib/stdlib/ebin/erl_eval.beam
index f3fc64ee32..eea70718c8 100644
--- a/bootstrap/lib/stdlib/ebin/erl_eval.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_eval.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_expand_records.beam b/bootstrap/lib/stdlib/ebin/erl_expand_records.beam
index a4bfe3d411..9a3daef51e 100644
--- a/bootstrap/lib/stdlib/ebin/erl_expand_records.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_expand_records.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_internal.beam b/bootstrap/lib/stdlib/ebin/erl_internal.beam
index c635408fde..c571d9f6f3 100644
--- a/bootstrap/lib/stdlib/ebin/erl_internal.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_internal.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_lint.beam b/bootstrap/lib/stdlib/ebin/erl_lint.beam
index fd2b331f69..3fa4a49c24 100644
--- a/bootstrap/lib/stdlib/ebin/erl_lint.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_lint.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_scan.beam b/bootstrap/lib/stdlib/ebin/erl_scan.beam
index 0f516803e3..a7a2910e1b 100644
--- a/bootstrap/lib/stdlib/ebin/erl_scan.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_scan.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/escript.beam b/bootstrap/lib/stdlib/ebin/escript.beam
index 79ed0a3876..781484fe0b 100644
--- a/bootstrap/lib/stdlib/ebin/escript.beam
+++ b/bootstrap/lib/stdlib/ebin/escript.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/ets.beam b/bootstrap/lib/stdlib/ebin/ets.beam
index 3d103b1624..ab4996ef4e 100644
--- a/bootstrap/lib/stdlib/ebin/ets.beam
+++ b/bootstrap/lib/stdlib/ebin/ets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/filename.beam b/bootstrap/lib/stdlib/ebin/filename.beam
index 42e8e24580..85d568a8e1 100644
--- a/bootstrap/lib/stdlib/ebin/filename.beam
+++ b/bootstrap/lib/stdlib/ebin/filename.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_event.beam b/bootstrap/lib/stdlib/ebin/gen_event.beam
index bb1d4f69ba..ef8d0cd929 100644
--- a/bootstrap/lib/stdlib/ebin/gen_event.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_event.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_fsm.beam b/bootstrap/lib/stdlib/ebin/gen_fsm.beam
index 769f82a528..3a4df3499c 100644
--- a/bootstrap/lib/stdlib/ebin/gen_fsm.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_fsm.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_server.beam b/bootstrap/lib/stdlib/ebin/gen_server.beam
index 7828b04453..1752276cc8 100644
--- a/bootstrap/lib/stdlib/ebin/gen_server.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_server.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_statem.beam b/bootstrap/lib/stdlib/ebin/gen_statem.beam
index e89eb4a65a..1c1b93a036 100644
--- a/bootstrap/lib/stdlib/ebin/gen_statem.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_statem.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/io.beam b/bootstrap/lib/stdlib/ebin/io.beam
index e1841e184c..197d9b7f9c 100644
--- a/bootstrap/lib/stdlib/ebin/io.beam
+++ b/bootstrap/lib/stdlib/ebin/io.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam
index de468aacca..dc91c318c5 100644
--- a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam
+++ b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/lib.beam b/bootstrap/lib/stdlib/ebin/lib.beam
deleted file mode 100644
index 2cc777b388..0000000000
--- a/bootstrap/lib/stdlib/ebin/lib.beam
+++ /dev/null
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/maps.beam b/bootstrap/lib/stdlib/ebin/maps.beam
index 85e997bb1c..e24b5955d5 100644
--- a/bootstrap/lib/stdlib/ebin/maps.beam
+++ b/bootstrap/lib/stdlib/ebin/maps.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/ms_transform.beam b/bootstrap/lib/stdlib/ebin/ms_transform.beam
index 03b4b75bb6..e465ca8d5d 100644
--- a/bootstrap/lib/stdlib/ebin/ms_transform.beam
+++ b/bootstrap/lib/stdlib/ebin/ms_transform.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/otp_internal.beam b/bootstrap/lib/stdlib/ebin/otp_internal.beam
index a64abac273..c42b18f6cf 100644
--- a/bootstrap/lib/stdlib/ebin/otp_internal.beam
+++ b/bootstrap/lib/stdlib/ebin/otp_internal.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/proc_lib.beam b/bootstrap/lib/stdlib/ebin/proc_lib.beam
index 9025f68b68..ce36bcf6fc 100644
--- a/bootstrap/lib/stdlib/ebin/proc_lib.beam
+++ b/bootstrap/lib/stdlib/ebin/proc_lib.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/qlc.beam b/bootstrap/lib/stdlib/ebin/qlc.beam
index 523f93a848..c1cd50f143 100644
--- a/bootstrap/lib/stdlib/ebin/qlc.beam
+++ b/bootstrap/lib/stdlib/ebin/qlc.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/shell.beam b/bootstrap/lib/stdlib/ebin/shell.beam
index abbe513b39..65ffc775ad 100644
--- a/bootstrap/lib/stdlib/ebin/shell.beam
+++ b/bootstrap/lib/stdlib/ebin/shell.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/slave.beam b/bootstrap/lib/stdlib/ebin/slave.beam
index 596dda4ed5..e832637c7c 100644
--- a/bootstrap/lib/stdlib/ebin/slave.beam
+++ b/bootstrap/lib/stdlib/ebin/slave.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/stdlib.app b/bootstrap/lib/stdlib/ebin/stdlib.app
index c24ca46516..20c978670e 100644
--- a/bootstrap/lib/stdlib/ebin/stdlib.app
+++ b/bootstrap/lib/stdlib/ebin/stdlib.app
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -43,6 +43,7 @@
erl_anno,
erl_bits,
erl_compile,
+ erl_error,
erl_eval,
erl_expand_records,
erl_internal,
@@ -71,7 +72,6 @@
io_lib_format,
io_lib_fread,
io_lib_pretty,
- lib,
lists,
log_mf_h,
maps,
diff --git a/bootstrap/lib/stdlib/ebin/string.beam b/bootstrap/lib/stdlib/ebin/string.beam
index 39ec49672a..57142f539a 100644
--- a/bootstrap/lib/stdlib/ebin/string.beam
+++ b/bootstrap/lib/stdlib/ebin/string.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/supervisor.beam b/bootstrap/lib/stdlib/ebin/supervisor.beam
index 1cb1178884..939f385c93 100644
--- a/bootstrap/lib/stdlib/ebin/supervisor.beam
+++ b/bootstrap/lib/stdlib/ebin/supervisor.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam b/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam
index cb61f6e6f9..6cfaa984df 100644
--- a/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam
+++ b/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/unicode.beam b/bootstrap/lib/stdlib/ebin/unicode.beam
index b3b0a4637a..bdd4374aef 100644
--- a/bootstrap/lib/stdlib/ebin/unicode.beam
+++ b/bootstrap/lib/stdlib/ebin/unicode.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/uri_string.beam b/bootstrap/lib/stdlib/ebin/uri_string.beam
index e14164a823..36aec511d8 100644
--- a/bootstrap/lib/stdlib/ebin/uri_string.beam
+++ b/bootstrap/lib/stdlib/ebin/uri_string.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/include/assert.hrl b/bootstrap/lib/stdlib/include/assert.hrl
index 2ec89e7d8a..28d25c6589 100644
--- a/bootstrap/lib/stdlib/include/assert.hrl
+++ b/bootstrap/lib/stdlib/include/assert.hrl
@@ -140,7 +140,7 @@
-endif.
%% This is mostly a convenience which gives more detailed reports.
-%% Note: Guard is a guarded pattern, and can not be used for value.
+%% Note: Guard is a guarded pattern, and cannot be used for value.
-ifdef(NOASSERT).
-define(assertMatch(Guard, Expr), ok).
-define(assertMatch(Guard, Expr, Comment), ok).
@@ -289,7 +289,7 @@
end).
-endif.
-%% Note: Class and Term are patterns, and can not be used for value.
+%% Note: Class and Term are patterns, and cannot be used for value.
%% Term can be a guarded pattern, but Class cannot.
-ifdef(NOASSERT).
-define(assertException(Class, Term, Expr), ok).
@@ -364,7 +364,7 @@
?assertException(throw, Term, Expr, Comment)).
%% This is the inverse case of assertException, for convenience.
-%% Note: Class and Term are patterns, and can not be used for value.
+%% Note: Class and Term are patterns, and cannot be used for value.
%% Both Class and Term can be guarded patterns.
-ifdef(NOASSERT).
-define(assertNotException(Class, Term, Expr), ok).
diff --git a/configure.in b/configure.in
index 559049aca1..c3a7e5018d 100644
--- a/configure.in
+++ b/configure.in
@@ -479,7 +479,7 @@ if test -f "erts/doc/CONF_INFO"; then
fi
done
if test $havexsltproc = "no"; then
- echo ' The documentation can not be built.'
+ echo ' The documentation cannot be built.'
else
echo ' Using fakefop to generate placeholder PDF files.'
fi
diff --git a/erts/aclocal.m4 b/erts/aclocal.m4
index a4d09810bd..3d227e462c 100644
--- a/erts/aclocal.m4
+++ b/erts/aclocal.m4
@@ -1,7 +1,7 @@
dnl
dnl %CopyrightBegin%
dnl
-dnl Copyright Ericsson AB 1998-2016. All Rights Reserved.
+dnl Copyright Ericsson AB 1998-2018. 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.
@@ -2645,7 +2645,7 @@ case $erl_gethrvtime in
dnl Check if clock_gettime (linux) is working
dnl
- AC_MSG_CHECKING([if clock_gettime can be used to get process CPU time])
+ AC_MSG_CHECKING([if clock_gettime can be used to get thread CPU time])
save_libs=$LIBS
LIBS="-lrt"
AC_TRY_RUN([
@@ -2659,11 +2659,11 @@ case $erl_gethrvtime in
int i;
struct timespec tp;
- if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp) < 0)
+ if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp) < 0)
exit(1);
start = ((long long)tp.tv_sec * 1000000000LL) + (long long)tp.tv_nsec;
for (i = 0; i < 100; i++)
- clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp);
+ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tp);
stop = ((long long)tp.tv_sec * 1000000000LL) + (long long)tp.tv_nsec;
if (start == 0)
exit(4);
@@ -2686,7 +2686,7 @@ case $erl_gethrvtime in
case $erl_clock_gettime_cpu_time in
yes)
AC_DEFINE(HAVE_CLOCK_GETTIME_CPU_TIME,[],
- [define if clock_gettime() works for getting process time])
+ [define if clock_gettime() works for getting thread time])
LIBRT=-lrt
;;
cross)
diff --git a/erts/autoconf/configure.vxworks b/erts/autoconf/configure.vxworks
index 18ca1718d6..a253848403 100755
--- a/erts/autoconf/configure.vxworks
+++ b/erts/autoconf/configure.vxworks
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -113,10 +113,11 @@ CONFIG_FILES="${ERL_TOP}/erts/emulator/$host/Makefile
$erlint_dir/$host/eidefs.mk
$epmd_dir/$host/Makefile
$internal_tools_dir/make/$host/otp.mk
+ $internal_tools_dir/make/$host/otp_ded.mk
$os_mon_dir/$host/Makefile
$zlibdir/$host/Makefile
$runtime_tools_dir/$host/Makefile
- $tools_dir/$host/Makefile
+ $tools_dir/$host/Makefile"
for file in $CONFIG_FILES; do
new_name=`echo $file|sed "s%/$host/%/$target/%"`
diff --git a/erts/autoconf/vxworks/sed.general b/erts/autoconf/vxworks/sed.general
index 96a70e4148..a30eb51169 100644
--- a/erts/autoconf/vxworks/sed.general
+++ b/erts/autoconf/vxworks/sed.general
@@ -43,6 +43,11 @@ s|@LDFLAGS@||
# FIXME: A bit strange to clear out remaining DED_*
s|@DED_LDFLAGS@||
s|@DED_CFLAGS@||
+s|@DED_EMU_THR_DEFS@||
+s|@DED_THR_DEFS@||
+s|@DED_SYS_INCLUDE@||
+s|@WERRORFLAGS@||
+s|@DED_STATIC_CFLAGS@||
s|@STATIC_CFLAGS@||
s|@GCCLIB@|libgcc.a|
s|@DEFS@||
diff --git a/erts/autoconf/vxworks/sed.vxworks_cpu32 b/erts/autoconf/vxworks/sed.vxworks_cpu32
index 71663676e7..961adc4104 100644
--- a/erts/autoconf/vxworks/sed.vxworks_cpu32
+++ b/erts/autoconf/vxworks/sed.vxworks_cpu32
@@ -28,6 +28,7 @@ s|@host@|vxworks_cpu32|
s|@system_type@|vxworks_cpu32|
s|@CC@|@TTPREFIX@cc68k|
s|@HCC@|gcc|
+s|@GCC@|yes|
s|@LD@|@TTPREFIX@ld68k|
s|@LIBS@||
s|@DED_LD@|@TTPREFIX@ld68k|
diff --git a/erts/autoconf/vxworks/sed.vxworks_ppc32 b/erts/autoconf/vxworks/sed.vxworks_ppc32
index 2146e862fd..1e2e760abc 100644
--- a/erts/autoconf/vxworks/sed.vxworks_ppc32
+++ b/erts/autoconf/vxworks/sed.vxworks_ppc32
@@ -33,6 +33,7 @@ s|@system_type@|vxworks_ppc32|
s|@ARCH@|ppc32|
s|@CC@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ccppc -mlongcall|
s|@HCC@|gcc|
+s|@GCC@|yes|
s|@LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldppc|
s|@STRIP@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/workbench-2.3/@HOST_TYPE@/bin/stripppc|
s|@SYMPREFIX@||
diff --git a/erts/autoconf/vxworks/sed.vxworks_ppc603 b/erts/autoconf/vxworks/sed.vxworks_ppc603
index fca1ba76d9..5beaae4fc9 100644
--- a/erts/autoconf/vxworks/sed.vxworks_ppc603
+++ b/erts/autoconf/vxworks/sed.vxworks_ppc603
@@ -29,6 +29,7 @@ s|@system_type@|vxworks_ppc603|
s|@ARCH@|ppc603|
s|@CC@|@TTPREFIX@ccppc -mlongcall|
s|@HCC@|gcc|
+s|@GCC@|yes|
s|@LD@|@TTPREFIX@ldppc|
s|@STRIP@|@TTPREFIX@stripppc|
s|@SYMPREFIX@||
diff --git a/erts/autoconf/vxworks/sed.vxworks_ppc603_nolongcall b/erts/autoconf/vxworks/sed.vxworks_ppc603_nolongcall
index 51c589d79a..2c2f2fa372 100644
--- a/erts/autoconf/vxworks/sed.vxworks_ppc603_nolongcall
+++ b/erts/autoconf/vxworks/sed.vxworks_ppc603_nolongcall
@@ -29,6 +29,7 @@ s|@system_type@|vxworks_ppc603|
s|@ARCH@|ppc603|
s|@CC@|@TTPREFIX@ccppc|
s|@HCC@|gcc|
+s|@GCC@|yes|
s|@LD@|@TTPREFIX@ldppc|
s|@STRIP@|@TTPREFIX@stripppc|
s|@SYMPREFIX@||
diff --git a/erts/autoconf/vxworks/sed.vxworks_ppc860 b/erts/autoconf/vxworks/sed.vxworks_ppc860
index 485504e706..71cf887476 100644
--- a/erts/autoconf/vxworks/sed.vxworks_ppc860
+++ b/erts/autoconf/vxworks/sed.vxworks_ppc860
@@ -29,6 +29,7 @@ s|@system_type@|vxworks_ppc860|
s|@ARCH@|ppc860|
s|@CC@|@TTPREFIX@ccppc -mlongcall|
s|@HCC@|gcc|
+s|@GCC@|yes|
s|@LD@|@TTPREFIX@ldppc|
s|@STRIP@|@TTPREFIX@stripppc|
s|@SYMPREFIX@||
diff --git a/erts/autoconf/vxworks/sed.vxworks_simlinux b/erts/autoconf/vxworks/sed.vxworks_simlinux
index 10cd7bbb82..06b1847602 100644
--- a/erts/autoconf/vxworks/sed.vxworks_simlinux
+++ b/erts/autoconf/vxworks/sed.vxworks_simlinux
@@ -36,6 +36,7 @@ s|@ARCH@|simlinux|
s|@CC@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ccpentium|
s|@HCC@|gcc|
+s|@GCC@|yes|
s|@LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldpentium|
diff --git a/erts/autoconf/vxworks/sed.vxworks_simso b/erts/autoconf/vxworks/sed.vxworks_simso
index cd30f8c2b2..07606cad80 100644
--- a/erts/autoconf/vxworks/sed.vxworks_simso
+++ b/erts/autoconf/vxworks/sed.vxworks_simso
@@ -36,6 +36,7 @@ s|@ARCH@|simso|
s|@CC@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ccsparc|
s|@HCC@|gcc|
+s|@GCC@|yes|
# Tornado2.2: s|@LD@|@TTPREFIX@ldsimso|
s|@LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldsparc|
diff --git a/erts/autoconf/vxworks/sed.vxworks_sparc b/erts/autoconf/vxworks/sed.vxworks_sparc
index a3758423e8..59431fddf9 100644
--- a/erts/autoconf/vxworks/sed.vxworks_sparc
+++ b/erts/autoconf/vxworks/sed.vxworks_sparc
@@ -30,6 +30,7 @@ s/@host@/vxworks_sparc/
s/@system_type@/vxworks_sparc/
s/@CC@/\/home\/gandalf\/bsproj\/tools\/vw-gnu\/solaris.sparc\/bin\/ccsparc/
s/@HCC@/gcc/
+s/@GCC@/yes/
s/@LD@/\/home\/gandalf\/bsproj\/tools\/vw-gnu\/solaris.sparc\/bin\/ldsparc/
s/@DEBUG_FLAGS@/-g/
s/@GCCLIB_PATH@/\/home\/gandalf\/bsproj\/tools\/vw-gnu\/solaris.sparc\/lib\/gcc-lib\/sparc-wrs-vxworks\/cygnus-2.2.3.1\/libgcc.a/
diff --git a/erts/configure.in b/erts/configure.in
index d1c5fe324b..2b3d97cfdd 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-2017. All Rights Reserved.
+dnl Copyright Ericsson AB 1997-2018. 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.
@@ -2012,29 +2012,6 @@ esac
AC_CHECK_DECLS([posix2time, time2posix],,,[#include <time.h>])
-disable_vfork=false
-if test "x$EMU_THR_LIB_NAME" != "x"; then
- AC_MSG_CHECKING([if vfork is known to hang multithreaded applications])
- case $host_os in
- osf*)
- AC_MSG_RESULT(yes)
- disable_vfork=true;;
- *)
- AC_MSG_RESULT(no);;
- esac
-fi
-
-if test $disable_vfork = false; then
- AC_FUNC_VFORK
- if test $ac_cv_func_vfork_works = no; then
- disable_vfork=true
- fi
-fi
-
-if test $disable_vfork = true; then
- AC_DEFINE(DISABLE_VFORK, 1, [Define if you want to disable vfork.])
-fi
-
AC_FUNC_VPRINTF
dnl The AC_DEFINEs are necessary for autoheader to work. :-(
@@ -2701,570 +2678,14 @@ if test X${enable_hipe} = Xyes; then
fi
AC_SUBST(HIPEBEAMLDFLAGS)
-if test X${enable_fp_exceptions} = Xauto ; then
- case $host_os in
- *linux*)
- enable_fp_exceptions=no
- AC_MSG_NOTICE([Floating point exceptions disabled by default on Linux]) ;;
- darwin*)
- enable_fp_exceptions=no
- AC_MSG_NOTICE([Floating point exceptions disabled by default on MacOS X]) ;;
- *)
- ;;
- esac
-fi
-
-if test X${enable_fp_exceptions} = Xauto ; then
- if test X${enable_hipe} = Xyes; then
- enable_fp_exceptions=yes
- else
- enable_fp_exceptions=no
- AC_MSG_NOTICE([Floating point exceptions disabled by default in this configuration])
- fi
-fi
-
-if test X${enable_fp_exceptions} != Xyes ; then
- AC_DEFINE(NO_FPE_SIGNALS,[],[Define if floating points exceptions are non-existing/not reliable])
- FPE=unreliable
-else
-
- AC_MSG_CHECKING([for unreliable floating point exceptions])
-
-
- AC_TRY_RUN([
-/* fpe-test.c */
-#include <stdio.h>
-#include <signal.h>
-#include <stdlib.h>
-
-#if defined(__clang__) || defined(__llvm__)
-#error "Clang/LLVM generates broken code for FP exceptions"
-#endif
-
-volatile int erl_fp_exception;
-
-/*
- * We expect a single SIGFPE in this test program.
- * Getting many more indicates an inadequate SIGFPE handler,
- * e.g. using the generic handler on x86.
- */
-static void new_fp_exception(void)
-{
- if (++erl_fp_exception > 50) {
- fprintf(stderr, "SIGFPE loop detected, bailing out\n");
- exit(1);
- }
-}
-
-/* Is there no standard identifier for Darwin/MacOSX ? */
-#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__)
-#define __DARWIN__ 1
-#endif
-
-/*
- * Implement unmask_fpe() and check_fpe() based on CPU/OS combination
- */
-
-#if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__) && !defined(__CYGWIN__) && !defined(__MINGW32__)
-
-static void unmask_x87(void)
-{
- unsigned short cw;
- __asm__ __volatile__("fstcw %0" : "=m"(cw));
- cw &= ~(0x01|0x04|0x08); /* unmask IM, ZM, OM */
- __asm__ __volatile__("fldcw %0" : : "m"(cw));
-}
-
-static void unmask_sse2(void)
-{
- unsigned int mxcsr;
- __asm__ __volatile__("stmxcsr %0" : "=m"(mxcsr));
- mxcsr &= ~(0x003F|0x0680); /* clear exn flags, unmask OM, ZM, IM (not PM, UM, DM) */
- __asm__ __volatile__("ldmxcsr %0" : : "m"(mxcsr));
-}
-
-#if defined(__x86_64__)
-
-static inline int cpu_has_sse2(void) { return 1; }
-
-#else /* !__x86_64__ */
-
-/*
- * Check if an x86-32 processor has SSE2.
- */
-static unsigned int xor_eflags(unsigned int mask)
-{
- unsigned int eax, edx;
-
- eax = mask; /* eax = mask */
- __asm__("pushfl\n\t"
- "popl %0\n\t" /* edx = original EFLAGS */
- "xorl %0, %1\n\t" /* eax = mask ^ EFLAGS */
- "pushl %1\n\t"
- "popfl\n\t" /* new EFLAGS = mask ^ original EFLAGS */
- "pushfl\n\t"
- "popl %1\n\t" /* eax = new EFLAGS */
- "xorl %0, %1\n\t" /* eax = new EFLAGS ^ old EFLAGS */
- "pushl %0\n\t"
- "popfl" /* restore original EFLAGS */
- : "=d"(edx), "=a"(eax)
- : "1"(eax));
- return eax;
-}
-
-static __inline__ unsigned int cpuid_eax(unsigned int op)
-{
- unsigned int eax, save_ebx;
-
- /* In PIC mode i386 reserves EBX. So we must save
- and restore it ourselves to not upset gcc. */
- __asm__(
- "movl %%ebx, %1\n\t"
- "cpuid\n\t"
- "movl %1, %%ebx"
- : "=a"(eax), "=m"(save_ebx)
- : "0"(op)
- : "cx", "dx");
- return eax;
-}
-
-static __inline__ unsigned int cpuid_edx(unsigned int op)
-{
- unsigned int eax, edx, save_ebx;
-
- /* In PIC mode i386 reserves EBX. So we must save
- and restore it ourselves to not upset gcc. */
- __asm__(
- "movl %%ebx, %2\n\t"
- "cpuid\n\t"
- "movl %2, %%ebx"
- : "=a"(eax), "=d"(edx), "=m"(save_ebx)
- : "0"(op)
- : "cx");
- return edx;
-}
-
-/* The AC bit, bit #18, is a new bit introduced in the EFLAGS
- * register on the Intel486 processor to generate alignment
- * faults. This bit cannot be set on the Intel386 processor.
- */
-static __inline__ int is_386(void)
-{
- return ((xor_eflags(1<<18) >> 18) & 1) == 0;
-}
-
-/* Newer x86 processors have a CPUID instruction, as indicated by
- * the ID bit (#21) in EFLAGS being modifiable.
- */
-static __inline__ int has_CPUID(void)
-{
- return (xor_eflags(1<<21) >> 21) & 1;
-}
-
-static int cpu_has_sse2(void)
-{
- unsigned int maxlev, features;
- static int has_sse2 = -1;
-
- if (has_sse2 >= 0)
- return has_sse2;
- has_sse2 = 0;
-
- if (is_386())
- return 0;
- if (!has_CPUID())
- return 0;
- maxlev = cpuid_eax(0);
- /* Intel A-step Pentium had a preliminary version of CPUID.
- It also didn't have SSE2. */
- if ((maxlev & 0xFFFFFF00) == 0x0500)
- return 0;
- /* If max level is zero then CPUID cannot report any features. */
- if (maxlev == 0)
- return 0;
- features = cpuid_edx(1);
- has_sse2 = (features & (1 << 26)) != 0;
-
- return has_sse2;
-}
-#endif /* !__x86_64__ */
-
-static void unmask_fpe(void)
-{
- unmask_x87();
- if (cpu_has_sse2())
- unmask_sse2();
-}
-
-static __inline__ int check_fpe(double f)
-{
- __asm__ __volatile__("fwait" : "=m"(erl_fp_exception) : "m"(f));
- if (!erl_fp_exception)
- return 0;
- __asm__ __volatile__("fninit");
- unmask_fpe();
- return 1;
-}
-
-#elif defined(__sparc__) && defined(__linux__)
-
-#if defined(__arch64__)
-#define LDX "ldx"
-#define STX "stx"
-#else
-#define LDX "ld"
-#define STX "st"
-#endif
-
-static void unmask_fpe(void)
-{
- unsigned long fsr;
-
- __asm__(STX " %%fsr, %0" : "=m"(fsr));
- fsr &= ~(0x1FUL << 23); /* clear FSR[TEM] field */
- fsr |= (0x1AUL << 23); /* enable NV, OF, DZ exceptions */
- __asm__ __volatile__(LDX " %0, %%fsr" : : "m"(fsr));
-}
-
-static __inline__ int check_fpe(double f)
-{
- __asm__ __volatile__("" : "=m"(erl_fp_exception) : "em"(f));
- return erl_fp_exception;
-}
-
-#elif (defined(__powerpc__) && defined(__linux__)) || (defined(__ppc__) && defined(__DARWIN__))
-
-#if defined(__linux__)
-
-#include <sys/prctl.h>
-
-static void set_fpexc_precise(void)
-{
- if (prctl(PR_SET_FPEXC, PR_FP_EXC_PRECISE) < 0) {
- perror("PR_SET_FPEXC");
- exit(1);
- }
-}
-
-#elif defined(__DARWIN__)
-
-#include <mach/mach.h>
-#include <pthread.h>
-
-/*
- * FE0 FE1 MSR bits
- * 0 0 floating-point exceptions disabled
- * 0 1 floating-point imprecise nonrecoverable
- * 1 0 floating-point imprecise recoverable
- * 1 1 floating-point precise mode
- *
- * Apparently:
- * - Darwin 5.5 (MacOS X <= 10.1) starts with FE0 == FE1 == 0,
- * and resets FE0 and FE1 to 0 after each SIGFPE.
- * - Darwin 6.0 (MacOS X 10.2) starts with FE0 == FE1 == 1,
- * and does not reset FE0 or FE1 after a SIGFPE.
- */
-#define FE0_MASK (1<<11)
-#define FE1_MASK (1<<8)
-
-/* a thread cannot get or set its own MSR bits */
-static void *fpu_fpe_enable(void *arg)
-{
- thread_t t = *(thread_t*)arg;
- struct ppc_thread_state state;
- unsigned int state_size = PPC_THREAD_STATE_COUNT;
-
- if (thread_get_state(t, PPC_THREAD_STATE, (natural_t*)&state, &state_size) != KERN_SUCCESS) {
- perror("thread_get_state");
- exit(1);
- }
- if ((state.srr1 & (FE1_MASK|FE0_MASK)) != (FE1_MASK|FE0_MASK)) {
-#if 0
- /* This would also have to be performed in the SIGFPE handler
- to work around the MSR reset older Darwin releases do. */
- state.srr1 |= (FE1_MASK|FE0_MASK);
- thread_set_state(t, PPC_THREAD_STATE, (natural_t*)&state, state_size);
-#else
- fprintf(stderr, "srr1 == 0x%08x, your Darwin is too old\n", state.srr1);
- exit(1);
-#endif
- }
- return NULL; /* Ok, we appear to be on Darwin 6.0 or later */
-}
-
-static void set_fpexc_precise(void)
-{
- thread_t self = mach_thread_self();
- pthread_t enabler;
-
- if (pthread_create(&enabler, NULL, fpu_fpe_enable, &self)) {
- perror("pthread_create");
- } else if (pthread_join(enabler, NULL)) {
- perror("pthread_join");
- }
-}
-
-#endif
-
-static void set_fpscr(unsigned int fpscr)
-{
- union {
- double d;
- unsigned int fpscr[2];
- } u;
- u.fpscr[0] = 0xFFF80000;
- u.fpscr[1] = fpscr;
- __asm__ __volatile__("mtfsf 255,%0" : : "f"(u.d));
-}
-
-static void unmask_fpe(void)
-{
- set_fpexc_precise();
- set_fpscr(0x80|0x40|0x10); /* VE, OE, ZE; not UE or XE */
-}
-
-static __inline__ int check_fpe(double f)
-{
- __asm__ __volatile__("" : "=m"(erl_fp_exception) : "fm"(f));
- return erl_fp_exception;
-}
-
-#else
-
-#include <ieeefp.h>
-
-#define unmask_fpe() fpsetmask(FP_X_INV | FP_X_OFL | FP_X_DZ)
-
-static __inline__ int check_fpe(double f)
-{
- __asm__ __volatile__("" : "=m"(erl_fp_exception) : "g"(f));
- return erl_fp_exception;
-}
-
-#endif
-
-/*
- * Implement SIGFPE handler based on CPU/OS combination
- */
-
-#if (defined(__linux__) && (defined(__i386__) || defined(__x86_64__) || defined(__sparc__) || defined(__powerpc__))) || (defined(__DARWIN__) && (defined(__i386__) || defined(__x86_64__) || defined(__ppc__))) || (defined(__FreeBSD__) && (defined(__i386__) || defined(__x86_64__))) || ((defined(__OpenBSD__) || defined(__NetBSD__)) && defined(__x86_64__)) || (defined(__sun__) && defined(__x86_64__))
-
-#if defined(__linux__) && defined(__i386__)
-#if !defined(X86_FXSR_MAGIC)
-#define X86_FXSR_MAGIC 0x0000
-#endif
-#elif defined(__FreeBSD__) && defined(__i386__)
-#include <sys/types.h>
-#include <machine/npx.h>
-#elif defined(__FreeBSD__) && defined(__x86_64__)
-#include <sys/types.h>
-#include <machine/fpu.h>
-#elif defined(__DARWIN__)
-#include <machine/signal.h>
-#elif defined(__OpenBSD__) && defined(__x86_64__)
-#include <sys/types.h>
-#include <machine/fpu.h>
-#endif
-#if !(defined(__OpenBSD__) && defined(__x86_64__))
-#include <ucontext.h>
-#endif
-#include <string.h>
-
-static void fpe_sig_action(int sig, siginfo_t *si, void *puc)
-{
- ucontext_t *uc = puc;
-#if defined(__linux__)
-#if defined(__x86_64__)
- mcontext_t *mc = &uc->uc_mcontext;
- fpregset_t fpstate = mc->fpregs;
- fpstate->mxcsr = 0x1F80;
- fpstate->swd &= ~0xFF;
-#elif defined(__i386__)
- mcontext_t *mc = &uc->uc_mcontext;
- fpregset_t fpstate = mc->fpregs;
- if ((fpstate->status >> 16) == X86_FXSR_MAGIC)
- ((struct _fpstate*)fpstate)->mxcsr = 0x1F80;
- fpstate->sw &= ~0xFF;
-#elif defined(__sparc__) && defined(__arch64__)
- /* on SPARC the 3rd parameter points to a sigcontext not a ucontext */
- struct sigcontext *sc = (struct sigcontext*)puc;
- sc->sigc_regs.tpc = sc->sigc_regs.tnpc;
- sc->sigc_regs.tnpc += 4;
-#elif defined(__sparc__)
- /* on SPARC the 3rd parameter points to a sigcontext not a ucontext */
- struct sigcontext *sc = (struct sigcontext*)puc;
- sc->si_regs.pc = sc->si_regs.npc;
- sc->si_regs.npc = (unsigned long)sc->si_regs.npc + 4;
-#elif defined(__powerpc__)
-#if defined(__powerpc64__)
- mcontext_t *mc = &uc->uc_mcontext;
- unsigned long *regs = &mc->gp_regs[0];
-#else
- mcontext_t *mc = uc->uc_mcontext.uc_regs;
- unsigned long *regs = &mc->gregs[0];
-#endif
- regs[PT_NIP] += 4;
- regs[PT_FPSCR] = 0x80|0x40|0x10; /* VE, OE, ZE; not UE or XE */
-#endif
-#elif defined(__DARWIN__)
-#if defined(DARWIN_MODERN_MCONTEXT)
-#if defined(__x86_64__)
- mcontext_t mc = uc->uc_mcontext;
- struct __darwin_x86_float_state64 *fpstate = &mc->__fs;
- fpstate->__fpu_mxcsr = 0x1F80;
- *(unsigned short *)&fpstate->__fpu_fsw &= ~0xFF;
-#elif defined(__i386__)
- mcontext_t mc = uc->uc_mcontext;
- struct __darwin_i386_float_state *fpstate = &mc->__fs;
- fpstate->__fpu_mxcsr = 0x1F80;
- *(unsigned short *)&fpstate->__fpu_fsw &= ~0xFF;
-#elif defined(__ppc__)
- mcontext_t mc = uc->uc_mcontext;
- mc->ss.srr0 += 4;
- mc->fs.fpscr = 0x80|0x40|0x10;
-#endif
-#else
-#if defined(__x86_64__)
- mcontext_t mc = uc->uc_mcontext;
- struct x86_float_state64_t *fpstate = &mc->fs;
- fpstate->fpu_mxcsr = 0x1F80;
- *(unsigned short *)&fpstate->fpu_fsw &= ~0xFF;
-#elif defined(__i386__)
- mcontext_t mc = uc->uc_mcontext;
- x86_float_state32_t *fpstate = &mc->fs;
- fpstate->fpu_mxcsr = 0x1F80;
- *(unsigned short *)&fpstate->fpu_fsw &= ~0xFF;
-#elif defined(__ppc__)
- mcontext_t mc = uc->uc_mcontext;
- mc->ss.srr0 += 4;
- mc->fs.fpscr = 0x80|0x40|0x10;
-#endif
-#endif
-#elif defined(__FreeBSD__) && defined(__x86_64__)
- mcontext_t *mc = &uc->uc_mcontext;
- struct savefpu *savefpu = (struct savefpu*)&mc->mc_fpstate;
- struct envxmm *envxmm = &savefpu->sv_env;
- envxmm->en_mxcsr = 0x1F80;
- envxmm->en_sw &= ~0xFF;
-#elif defined(__FreeBSD__) && defined(__i386__)
- mcontext_t *mc = &uc->uc_mcontext;
- union savefpu *savefpu = (union savefpu*)&mc->mc_fpstate;
- if (mc->mc_fpformat == _MC_FPFMT_XMM) {
- struct envxmm *envxmm = &savefpu->sv_xmm.sv_env;
- envxmm->en_mxcsr = 0x1F80;
- envxmm->en_sw &= ~0xFF;
- } else {
- struct env87 *env87 = &savefpu->sv_87.sv_env;
- env87->en_sw &= ~0xFF;
- }
-#elif defined(__OpenBSD__) && defined(__x86_64__)
- struct fxsave64 *fxsave = uc->sc_fpstate;
- fxsave->fx_mxcsr = 0x1F80;
- fxsave->fx_fsw &= ~0xFF;
-#elif defined(__NetBSD__) && defined(__x86_64__)
- mcontext_t *mc = &uc->uc_mcontext;
- struct fxsave64 *fxsave = (struct fxsave64 *)&mc->__fpregs;
- fxsave->fx_mxcsr = 0x1F80;
- fxsave->fx_fsw &= ~0xFF;
-#elif defined(__sun__) && defined(__x86_64__)
- mcontext_t *mc = &uc->uc_mcontext;
- struct fpchip_state *fpstate = &mc->fpregs.fp_reg_set.fpchip_state;
- fpstate->mxcsr = 0x1F80;
- fpstate->sw &= ~0xFF;
-#endif
- new_fp_exception();
-}
-
-static void catch_sigfpe(void)
-{
- struct sigaction act;
-
- memset(&act, 0, sizeof act);
- act.sa_sigaction = fpe_sig_action;
- act.sa_flags = SA_SIGINFO;
- sigaction(SIGFPE, &act, NULL);
-}
-
-#else
-
-static void fpe_sig_handler(int sig)
-{
- new_fp_exception();
-}
-
-static void catch_sigfpe(void)
-{
- signal(SIGFPE, fpe_sig_handler);
-}
-
-#endif
-
-/*
- * Generic test code
- */
-
-static void do_init(void)
-{
- catch_sigfpe();
- unmask_fpe();
-}
-
-double a = 3.23e133;
-double b = 3.57e257;
-double res;
-
-void do_fmul(void)
-{
- res = a * b;
-}
-
-int do_check(void)
-{
- if (check_fpe(res)) {
- fprintf(stderr, "res = %g, FPE worked\n", res);
- return 0;
- } else {
- fprintf(stderr, "res = %g, FPE failed\n", res);
- return 1;
- }
-}
-
-int main(int argc, const char **argv)
-{
- if (argc == 3) {
- a = atof(argv[1]);
- b = atof(argv[2]);
- }
- do_init();
- do_fmul();
- return do_check();
-}
-],
-erl_ok=yes,
-erl_ok=no,
-[
-case X$erl_xcomp_reliable_fpe in
- X) erl_ok=cross;;
- Xyes|Xno) erl_ok=$erl_xcomp_reliable_fpe;;
- *) AC_MSG_ERROR([Bad erl_xcomp_reliable_fpe value: $erl_xcomp_reliable_fpe]);;
-esac
-])
-
- if test $erl_ok = yes; then
- FPE=reliable
- AC_MSG_RESULT(reliable)
- else
- FPE=unreliable
- AC_MSG_RESULT([unreliable; testing in software instead])
- AC_DEFINE(NO_FPE_SIGNALS,[],[Define if floating points exceptions are non-existing/not reliable])
- if test $erl_ok = cross; then
- AC_MSG_WARN([result unreliable guessed because of cross compilation])
- fi
- fi
-fi
-
+dnl Permanently disable floating point exceptions.
+dnl On x86/amd64, floating points exceptions have
+dnl unresolved stability issues.
+AC_MSG_CHECKING([for unreliable floating point exceptions])
+FPE=unreliable
AC_SUBST(FPE)
-
+AC_MSG_RESULT([unreliable])
+AC_DEFINE(NO_FPE_SIGNALS,[],[Define if floating points exceptions are non-existing/not reliable])
dnl
dnl Some operating systems allow you to redefine FD_SETSIZE to be able
diff --git a/erts/doc/src/Makefile b/erts/doc/src/Makefile
index 5fa8b0673a..21aa3db864 100644
--- a/erts/doc/src/Makefile
+++ b/erts/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2017. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -74,6 +74,7 @@ XML_CHAPTER_FILES = \
match_spec.xml \
crash_dump.xml \
alt_dist.xml \
+ alt_disco.xml \
driver.xml \
absform.xml \
inet_cfg.xml \
@@ -148,6 +149,7 @@ debug opt:
clean:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN1DIR)/*
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml
index 158f4dc4e8..f29bb7b8f9 100644
--- a/erts/doc/src/absform.xml
+++ b/erts/doc/src/absform.xml
@@ -801,7 +801,8 @@
<c>{ann_type,LINE,[Rep(A),Rep(T_0)]}</c>.</p>
</item>
<item>
- <p>If T is an atom or integer literal L, then Rep(T) = Rep(L).</p>
+ <p>If T is an atom, a character, or an integer literal L,
+ then Rep(T) = Rep(L).</p>
</item>
<item>
<p>If T is a bitstring type <c>&lt;&lt;_:M,_:_*N>></c>,
diff --git a/erts/doc/src/alt_disco.xml b/erts/doc/src/alt_disco.xml
new file mode 100644
index 0000000000..d04221b9b3
--- /dev/null
+++ b/erts/doc/src/alt_disco.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2018</year><year>2018</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>How to Implement an Alternative Service Discovery for Erlang Distribution
+ </title>
+ <prepared>Timmo Verlaan</prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date>2018-04-25</date>
+ <rev>PA1</rev>
+ <file>alt_disco.xml</file>
+ </header>
+ <p>
+ This section describes how to implement an alternative discovery mechanism
+ for Erlang distribution. Discovery is normally done using DNS and the
+ Erlang Port Mapper Daemon (EPMD) for port discovery.
+ </p>
+
+ <note><p>
+ Support for alternative service discovery mechanisms was added in Erlang/OTP
+ 21.
+ </p></note>
+
+
+ <section>
+ <title>Introduction</title>
+ <p>To implement your own service discovery module you have to write your own
+ EPMD module. The <seealso marker="kernel:erl_epmd">EPMD module</seealso> is
+ responsible for providing the location of another node. The distribution
+ modules (<c>inet_tcp_dist</c>/<c>inet_tls_dist</c>) call the EPMD module to
+ get the IP address and port of the other node. The EPMD module that is part
+ of Erlang/OTP will resolve the hostname using DNS and uses the EPMD unix
+ process to get the port of another node. The EPMD unix process does this by
+ connecting to the other node on a well-known port, port 4369.</p>
+ </section>
+
+ <section>
+ <title>Discovery module</title>
+ <p>The discovery module needs to implement the same API as the regular
+ <seealso marker="kernel:erl_epmd">EPMD module</seealso>. However, instead of
+ communicating with EPMD you can connect to any service to find out
+ connection details of other nodes. A discovery module is enabled
+ by setting <seealso marker="erts:erl#epmd_module">-epmd_module</seealso>
+ when starting erlang. The discovery module must implement the following
+ callbacks:</p>
+
+ <taglist>
+ <tag><seealso marker="kernel:erl_epmd#start_link/0">start_link/0</seealso></tag>
+ <item>Start any processes needed by the discovery module.</item>
+ <tag><seealso marker="kernel:erl_epmd#names/1">names/1</seealso></tag>
+ <item>Return node names held by the registrar for the given host.</item>
+ <tag><seealso marker="kernel:erl_epmd#register_node/2">register_node/2</seealso></tag>
+ <item>Register the given node name with the registrar.</item>
+ <tag><seealso marker="kernel:erl_epmd#port_please/3">port_please/3</seealso></tag>
+ <item>Return the distribution port used by the given node.</item>
+ </taglist>
+
+ <p>The discovery module may implement the following callback:</p>
+
+ <taglist>
+ <tag><seealso marker="kernel:erl_epmd#address_please/3">address_please/3</seealso></tag>
+ <item><p>Return the address of the given node.
+ If not implemented, <seealso marker="kernel:inet#gethostbyname/1">
+ inet:gethostbyname/1</seealso> will be used instead</p>
+ <p>This callback may also return the port of the given node. In that case
+ <seealso marker="kernel:erl_epmd#port_please/3">port_please/3</seealso>
+ may be omitted.</p></item>
+ </taglist>
+ </section>
+</chapter>
diff --git a/erts/doc/src/alt_dist.xml b/erts/doc/src/alt_dist.xml
index 92d40d8558..e6245130fc 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>2016</year>
+ <year>2000</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/driver_entry.xml b/erts/doc/src/driver_entry.xml
index e8c7e26457..fd7d6223f6 100644
--- a/erts/doc/src/driver_entry.xml
+++ b/erts/doc/src/driver_entry.xml
@@ -4,7 +4,7 @@
<cref>
<header>
<copyright>
- <year>2001</year><year>2016</year>
+ <year>2001</year><year>2018</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 74654a295d..05a9895687 100644
--- a/erts/doc/src/erl.xml
+++ b/erts/doc/src/erl.xml
@@ -4,7 +4,7 @@
<comref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -631,14 +631,16 @@
of process heaps is destroyed by the crash dump generation.</p>
<p>Option <c>+d</c> instructs the emulator to produce only a
core dump and no crash dump if an internal error is detected.</p>
- <p>Calling <seealso marker="erlang:halt/1">
+ <p>Calling <seealso marker="erlang#halt/1">
<c>erlang:halt/1</c></seealso> with a string argument still
produces a crash dump. On Unix systems, sending an emulator process
a <c>SIGUSR1</c> signal also forces a crash dump.</p>
</item>
<tag><marker id="+e"/><c><![CDATA[+e Number]]></c></tag>
<item>
- <p>Sets the maximum number of ETS tables.</p>
+ <p>Sets the maximum number of ETS tables. This limit is
+ <seealso marker="stdlib:ets#max_ets_tables">partially obsolete</seealso>.
+ </p>
</item>
<tag><c><![CDATA[+ec]]></c></tag>
<item>
diff --git a/erts/doc/src/erl_dist_protocol.xml b/erts/doc/src/erl_dist_protocol.xml
index 98a9a76b60..c90c8f9521 100644
--- a/erts/doc/src/erl_dist_protocol.xml
+++ b/erts/doc/src/erl_dist_protocol.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2007</year>
- <year>2017</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/erl_driver.xml b/erts/doc/src/erl_driver.xml
index e6c9905039..7055889e4a 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>2017</year>
+ <year>2001</year><year>2018</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 8a9ae58e99..a20b8ee884 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>2017</year>
+ <year>2001</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -194,7 +194,7 @@ ok
<p>Binaries are sequences of whole bytes. Bitstrings with an arbitrary
bit length have no support yet.</p>
</item>
- <tag>Resource objects</tag>
+ <tag><marker id="resource_objects"/>Resource objects</tag>
<item>
<p>The use of resource objects is a safe way to return pointers to
native data structures from a NIF. A resource object is
@@ -1250,8 +1250,9 @@ typedef struct {
<fsummary>Format strings and Erlang terms.</fsummary>
<desc>
<p>Similar to <c>fprintf</c> but this format string also accepts
- <c>"%T"</c>, which formats Erlang terms.</p>
- <p>This function was originally intenden for debugging purpose. It is not
+ <c>"%T"</c>, which formats Erlang terms of type
+ <seealso marker="#ERL_NIF_TERM"><c>ERL_NIF_TERM</c></seealso>.</p>
+ <p>This function is primarily intenden for debugging purpose. It is not
recommended to print very large terms with <c>%T</c>. The function may
change <c>errno</c>, even if successful.</p>
</desc>
@@ -3191,8 +3192,9 @@ if (retval &amp; ERL_NIF_SELECT_STOP_CALLED) {
<fsummary>Format strings and Erlang terms.</fsummary>
<desc>
<p>Similar to <c>snprintf</c> but this format string also accepts
- <c>"%T"</c>, which formats Erlang terms.</p>
- <p>This function was originally intenden for debugging purpose. It is not
+ <c>"%T"</c>, which formats Erlang terms of type
+ <seealso marker="#ERL_NIF_TERM"><c>ERL_NIF_TERM</c></seealso>.</p>
+ <p>This function is primarily intenden for debugging purpose. It is not
recommended to print very large terms with <c>%T</c>. The function may
change <c>errno</c>, even if successful.</p>
</desc>
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 3154fdaf8c..bd33e35603 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -36,8 +36,8 @@
in this module. Some of the BIFs are viewed more
or less as part of the Erlang programming language and are
<em>auto-imported</em>. Thus, it is not necessary to specify the
- module name. For example, the calls <c>atom_to_list(Erlang)</c>
- and <c>erlang:atom_to_list(Erlang)</c> are identical.</p>
+ module name. For example, the calls <c>atom_to_list(erlang)</c>
+ and <c>erlang:atom_to_list(erlang)</c> are identical.</p>
<p>Auto-imported BIFs are listed without module prefix.
BIFs listed with module prefix are not auto-imported.</p>
@@ -197,6 +197,15 @@
</desc>
</datatype>
+ <datatype>
+ <name name="nif_resource"></name>
+ <desc>
+ <p>An opaque handle identifing a
+ <seealso marker="erl_nif#resource_objects">NIF resource object
+ </seealso>.</p>
+ </desc>
+ </datatype>
+
</datatypes>
<funcs>
@@ -1742,6 +1751,10 @@ true</pre>
<item>
<p><c>Pid</c> is the process identifier of the process
that originally created the fun.</p>
+ <p>It might point to the <c>init</c> process if the
+ <c>Fun</c> was statically allocated when module was
+ loaded (this optimisation is performed for local
+ functions that do not capture the enviornment).</p>
</item>
<tag><c>{index, Index}</c></tag>
<item>
@@ -2068,8 +2081,15 @@ end</pre>
Typically, this is used when a process started from a
certain shell is to have another group leader than
<c>init</c>.</p>
+ <p>The group leader should be rarely changed in
+ applications with a supervision tree, because OTP
+ assumes the group leader of their processes is
+ their application master.</p>
<p>See also
- <seealso marker="#group_leader/0"><c>group_leader/0</c></seealso>.</p>
+ <seealso marker="#group_leader/0"><c>group_leader/0</c></seealso>
+ and <seealso marker="doc/design_principles:applications#stopping">OTP
+ design principles</seealso> related to starting and stopping
+ applications.</p>
</desc>
</func>
@@ -3765,13 +3785,6 @@ RealSystem = system + MissedSystem</code>
If found, that driver is started. A driver runs in the Erlang
work space, which means that it is linked with the Erlang
runtime system.</p>
- <p>When starting external programs on Solaris, the system
- call <c>vfork</c> is used in preference to <c>fork</c>
- for performance reasons, although it has a history of
- being less robust. If there are problems using
- <c>vfork</c>, setting environment variable
- <c>ERL_NO_VFORK</c> to any value causes <c>fork</c>
- to be used instead.</p>
<p>For external programs, <c>PATH</c> is searched
(or an equivalent method is used to find programs,
depending on the OS). This is done by invoking
@@ -4832,11 +4845,11 @@ RealSystem = system + MissedSystem</code>
</item>
<tag><c>error_logger</c></tag>
<item>
- <p>When set to <c>true</c>, the runtime system sends a
- message to the current <seealso marker="kernel:error_logger">
- <c>error_logger</c></seealso>
+ <p>When set to <c>true</c>, the runtime system logs an
+ error event via <seealso marker="kernel:logger">
+ <c>logger</c></seealso>,
containing details about the process when the maximum
- heap size is reached. One <c>error_logger</c> report is sent
+ heap size is reached. One log event is sent
each time the limit is reached.</p>
<p>If <c>error_logger</c> is not defined in the map, the system
default is used. The default system default is <c>true</c>.
@@ -4850,7 +4863,7 @@ RealSystem = system + MissedSystem</code>
amount of memory that is used during the garbage collection. When
contemplating using this option, it is recommended to first run
it in production with <c>kill</c> set to <c>false</c> and inspect
- the <c>error_logger</c> reports to see what the normal peak sizes
+ the log events to see what the normal peak sizes
of the processes in the system is and then tune the value
accordingly.
</p>
@@ -5288,10 +5301,10 @@ RealSystem = system + MissedSystem</code>
<p><c><anno>MinBinVHeapSize</anno></c> is the minimum binary virtual
heap size for the process.</p>
</item>
- <tag><c>{monitored_by, <anno>Pids</anno>}</c></tag>
+ <tag><c>{monitored_by, <anno>MonitoredBy</anno>}</c></tag>
<item>
- <p>A list of process identifiers monitoring the process (with
- <c>monitor/2</c>).</p>
+ <p>A list of identifiers for all the processes, ports and NIF
+ resources, that are monitoring the process.</p>
</item>
<tag><c>{monitors, <anno>Monitors</anno>}</c></tag>
<item>
@@ -6163,7 +6176,7 @@ true</pre>
<p>Monitors the new process (like
<seealso marker="#monitor/2"><c>monitor/2</c></seealso> does).</p>
</item>
- <tag><c>{priority, <anno>Level</anno></c></tag>
+ <tag><c>{priority, <anno>Level</anno>}</c></tag>
<item>
<p>Sets the priority of the new process. Equivalent to
executing <seealso marker="#process_flag_priority">
@@ -7005,10 +7018,47 @@ ok
from other events in the system. It is only guaranteed that
<c><anno>Suspendee</anno></c> <em>eventually</em> suspends
(unless it
- is resumed). If option <c>asynchronous</c> has <em>not</em>
+ is resumed). If no <c>asynchronous</c> options has
been passed, the caller of <c>erlang:suspend_process/2</c> is
blocked until <c><anno>Suspendee</anno></c> has suspended.</p>
</item>
+ <tag><c>{asynchronous, ReplyTag}</c></tag>
+ <item>
+ <p>A suspend request is sent to the process identified by
+ <c><anno>Suspendee</anno></c>. When the suspend request
+ has been processed, a reply message is sent to the caller
+ of this function. The reply is on the form <c>{ReplyTag,
+ State}</c> where <c>State</c> is either:</p>
+ <taglist>
+ <tag><c>exited</c></tag>
+ <item>
+ <p>
+ <c><anno>Suspendee</anno></c> has exited.
+ </p>
+ </item>
+ <tag><c>suspended</c></tag>
+ <item>
+ <p>
+ <c><anno>Suspendee</anno></c> is now suspended.
+ </p>
+ </item>
+ <tag><c>not_suspended</c></tag>
+ <item>
+ <p>
+ <c><anno>Suspendee</anno></c> is not suspended.
+ This can only happen when the process that
+ issued this request, have called
+ <c>resume_process(<anno>Suspendee</anno>)</c>
+ before getting the reply.
+ </p>
+ </item>
+ </taglist>
+ <p>
+ Appart from the reply message, the <c>{asynchronous,
+ ReplyTag}</c> option behaves exactly the same as the
+ <c>asynchronous</c> option without reply tag.
+ </p>
+ </item>
<tag><c>unless_suspending</c></tag>
<item>
<p>The process identified by <c><anno>Suspendee</anno></c> is
@@ -7032,6 +7082,13 @@ ok
<warning>
<p>This BIF is intended for debugging only.</p>
</warning>
+ <warning>
+ <p>You can easily create deadlocks if processes suspends
+ each other (directly or in circles). In ERTS versions prior
+ to ERTS version 10.0, the runtime system prevented such
+ deadlocks, but this prevention has now been removed due
+ to performance reasons.</p>
+ </warning>
<p>Failures:</p>
<taglist>
<tag><c>badarg</c></tag>
@@ -7338,7 +7395,7 @@ ok
<note><p>If a scheduler fails to bind, this is often silently
ignored, as it is not always possible to verify valid
logical processor identifiers. If an error is reported,
- it is reported to <c>error_logger</c>. To verify that the
+ an error event is logged. To verify that the
schedulers have bound as requested, call
<seealso marker="#system_info_scheduler_bindings">
<c>erlang:system_info(scheduler_bindings)</c></seealso>.</p>
@@ -7530,7 +7587,7 @@ ok
</func>
<func>
- <name name="system_info" arity="1" clause_i="75"/>
+ <name name="system_info" arity="1" clause_i="76"/>
<fsummary>System info overview.</fsummary>
<desc>
<p>Returns information about the current system.
@@ -7578,6 +7635,7 @@ ok
<p>
<seealso marker="#system_info_atom_count"><c>atom_count</c></seealso>,
<seealso marker="#system_info_atom_limit"><c>atom_limit</c></seealso>,
+ <seealso marker="#system_info_ets_count"><c>ets_count</c></seealso>,
<seealso marker="#system_info_ets_limit"><c>ets_limit</c></seealso>,
<seealso marker="#system_info_port_count"><c>port_count</c></seealso>,
<seealso marker="#system_info_port_limit"><c>port_limit</c></seealso>,
@@ -7821,8 +7879,8 @@ ok
<name name="system_info" arity="1" clause_i="12"
anchor="system_info_cpu_topology"/> <!-- cpu_topology -->
<name name="system_info" arity="1" clause_i="13"/> <!-- {cpu_topology, _} -->
- <name name="system_info" arity="1" clause_i="37"/> <!-- logical_processors -->
- <name name="system_info" arity="1" clause_i="72"/> <!-- update_cpu_info -->
+ <name name="system_info" arity="1" clause_i="38"/> <!-- logical_processors -->
+ <name name="system_info" arity="1" clause_i="73"/> <!-- update_cpu_info -->
<fsummary>Information about the CPU topology of the system.</fsummary>
<type name="cpu_topology"/>
<type name="level_entry"/>
@@ -7973,16 +8031,16 @@ ok
</func>
<func>
- <name name="system_info" arity="1" clause_i="30"
+ <name name="system_info" arity="1" clause_i="31"
anchor="system_info_process"/> <!-- fullsweep_after -->
- <name name="system_info" arity="1" clause_i="31"/> <!-- garbage_collection -->
- <name name="system_info" arity="1" clause_i="32"/> <!-- heap_sizes -->
- <name name="system_info" arity="1" clause_i="33"/> <!-- heap_type -->
- <name name="system_info" arity="1" clause_i="39"/> <!-- max_heap_size -->
- <name name="system_info" arity="1" clause_i="40"/> <!-- message_queue_data -->
- <name name="system_info" arity="1" clause_i="41"/> <!-- min_heap_size -->
- <name name="system_info" arity="1" clause_i="42"/> <!-- min_bin_vheap_size -->
- <name name="system_info" arity="1" clause_i="56"/> <!-- procs -->
+ <name name="system_info" arity="1" clause_i="32"/> <!-- garbage_collection -->
+ <name name="system_info" arity="1" clause_i="33"/> <!-- heap_sizes -->
+ <name name="system_info" arity="1" clause_i="34"/> <!-- heap_type -->
+ <name name="system_info" arity="1" clause_i="40"/> <!-- max_heap_size -->
+ <name name="system_info" arity="1" clause_i="41"/> <!-- message_queue_data -->
+ <name name="system_info" arity="1" clause_i="42"/> <!-- min_heap_size -->
+ <name name="system_info" arity="1" clause_i="43"/> <!-- min_bin_vheap_size -->
+ <name name="system_info" arity="1" clause_i="57"/> <!-- procs -->
<fsummary>Information about the default process heap settings.</fsummary>
<type name="message_queue_data"/>
<type name="max_heap_size"/>
@@ -8092,14 +8150,14 @@ ok
</func>
<func>
- <name name="system_info" arity="1" clause_i="6"
- anchor="system_info_limits"/> <!-- atom_count -->
+ <name name="system_info" arity="1" clause_i="6" anchor="system_info_limits"/> <!-- atom_count -->
<name name="system_info" arity="1" clause_i="7"/> <!-- atom_limit -->
- <name name="system_info" arity="1" clause_i="29"/> <!-- ets_limit -->
- <name name="system_info" arity="1" clause_i="52"/> <!-- port_count -->
- <name name="system_info" arity="1" clause_i="53"/> <!-- port_limit -->
- <name name="system_info" arity="1" clause_i="54"/> <!-- process_count -->
- <name name="system_info" arity="1" clause_i="55"/> <!-- process_limit -->
+ <name name="system_info" arity="1" clause_i="29"/> <!-- ets_count -->
+ <name name="system_info" arity="1" clause_i="30"/> <!-- ets_limit -->
+ <name name="system_info" arity="1" clause_i="53"/> <!-- port_count -->
+ <name name="system_info" arity="1" clause_i="54"/> <!-- port_limit -->
+ <name name="system_info" arity="1" clause_i="55"/> <!-- process_count -->
+ <name name="system_info" arity="1" clause_i="56"/> <!-- process_limit -->
<fsummary>Information about various system limits.</fsummary>
<desc>
<marker id="system_info_limits"/>
@@ -8122,16 +8180,18 @@ ok
<c>erl(1)</c>.
</p>
</item>
+ <tag><marker id="system_info_ets_count"/>
+ <c>ets_count</c></tag>
+ <item>
+ <p>Returns the number of ETS tables currently existing at the
+ local node.</p>
+ </item>
<tag><marker id="system_info_ets_limit"/>
<c>ets_limit</c></tag>
<item>
- <p>Returns the maximum number of ETS tables allowed. This
- limit can be increased at startup by passing
- command-line flag
- <seealso marker="erts:erl#+e"><c>+e</c></seealso> to
- <c>erl(1)</c> or by setting environment variable
- <c>ERL_MAX_ETS_TABLES</c> before starting the Erlang
- runtime system.</p>
+ <p>Returns the limit for number of ETS tables. This limit is
+ <seealso marker="stdlib:ets#max_ets_tables">partially obsolete</seealso>
+ and number of tables are only limited by available memory.</p>
</item>
<tag><marker id="system_info_port_count"/><c>port_count</c></tag>
<item>
@@ -8172,13 +8232,13 @@ ok
<func>
<name name="system_info" arity="1" clause_i="26"
anchor="system_info_time"/> <!-- end_time -->
- <name name="system_info" arity="1" clause_i="49"/> <!-- os_monotonic_time_source -->
- <name name="system_info" arity="1" clause_i="50"/> <!-- os_system_time_source -->
- <name name="system_info" arity="1" clause_i="62"/> <!-- start_time -->
- <name name="system_info" arity="1" clause_i="67"/> <!-- time_correction -->
- <name name="system_info" arity="1" clause_i="68"/> <!-- time_offset -->
- <name name="system_info" arity="1" clause_i="69"/> <!-- time_warp_mode -->
- <name name="system_info" arity="1" clause_i="70"/> <!-- tolerant_timeofday -->
+ <name name="system_info" arity="1" clause_i="50"/> <!-- os_monotonic_time_source -->
+ <name name="system_info" arity="1" clause_i="51"/> <!-- os_system_time_source -->
+ <name name="system_info" arity="1" clause_i="63"/> <!-- start_time -->
+ <name name="system_info" arity="1" clause_i="68"/> <!-- time_correction -->
+ <name name="system_info" arity="1" clause_i="69"/> <!-- time_offset -->
+ <name name="system_info" arity="1" clause_i="70"/> <!-- time_warp_mode -->
+ <name name="system_info" arity="1" clause_i="71"/> <!-- tolerant_timeofday -->
<fsummary>Information about system time.</fsummary>
<desc>
<marker id="system_info_time_tags"/>
@@ -8402,16 +8462,16 @@ ok
anchor="system_info_scheduler"/> <!-- dirty_cpu_schedulers -->
<name name="system_info" arity="1" clause_i="18"/> <!-- dirty_cpu_schedulers_online -->
<name name="system_info" arity="1" clause_i="19"/> <!-- dirty_io_schedulers -->
- <name name="system_info" arity="1" clause_i="44"/> <!-- multi_scheduling -->
- <name name="system_info" arity="1" clause_i="45"/> <!-- multi_scheduling_blockers -->
- <name name="system_info" arity="1" clause_i="47"/> <!-- normal_multi_scheduling_blockers -->
- <name name="system_info" arity="1" clause_i="57"/> <!-- scheduler_bind_type -->
- <name name="system_info" arity="1" clause_i="58"/> <!-- scheduler_bindings -->
- <name name="system_info" arity="1" clause_i="59"/> <!-- scheduler_id -->
- <name name="system_info" arity="1" clause_i="60"/> <!-- schedulers -->
- <name name="system_info" arity="1" clause_i="61"/> <!-- smp_support -->
- <name name="system_info" arity="1" clause_i="65"/> <!-- threads -->
- <name name="system_info" arity="1" clause_i="66"/> <!-- thread_pool_size -->
+ <name name="system_info" arity="1" clause_i="45"/> <!-- multi_scheduling -->
+ <name name="system_info" arity="1" clause_i="46"/> <!-- multi_scheduling_blockers -->
+ <name name="system_info" arity="1" clause_i="49"/> <!-- normal_multi_scheduling_blockers -->
+ <name name="system_info" arity="1" clause_i="58"/> <!-- scheduler_bind_type -->
+ <name name="system_info" arity="1" clause_i="59"/> <!-- scheduler_bindings -->
+ <name name="system_info" arity="1" clause_i="60"/> <!-- scheduler_id -->
+ <name name="system_info" arity="1" clause_i="61"/> <!-- schedulers -->
+ <name name="system_info" arity="1" clause_i="62"/> <!-- smp_support -->
+ <name name="system_info" arity="1" clause_i="66"/> <!-- threads -->
+ <name name="system_info" arity="1" clause_i="67"/> <!-- thread_pool_size -->
<fsummary>Information about system schedulers.</fsummary>
<desc>
<marker id="system_info_scheduler_tags"/>
@@ -8798,53 +8858,54 @@ ok
<!-- <name name="system_info" arity="1" clause_i="26"/> end_time -->
<!-- <name name="system_info" arity="1" clause_i="27"/> elib_malloc -->
<!-- <name name="system_info" arity="1" clause_i="28"/> eager_check_io, removed -->
- <!-- <name name="system_info" arity="1" clause_i="29"/> ets_limit -->
- <!-- <name name="system_info" arity="1" clause_i="30"/> fullsweep_after -->
- <!-- <name name="system_info" arity="1" clause_i="31"/> garbage_collection -->
- <!-- <name name="system_info" arity="1" clause_i="32"/> heap_sizes -->
- <!-- <name name="system_info" arity="1" clause_i="33"/> heap_type -->
- <name name="system_info" arity="1" clause_i="34"/> <!-- info -->
- <name name="system_info" arity="1" clause_i="35"/> <!-- kernel_poll -->
- <name name="system_info" arity="1" clause_i="36"/> <!-- loaded -->
- <!-- <name name="system_info" arity="1" clause_i="37"/> logical_processors -->
- <name name="system_info" arity="1" clause_i="38"/> <!-- machine -->
- <!-- <name name="system_info" arity="1" clause_i="39"/> max_heap_size -->
- <!-- <name name="system_info" arity="1" clause_i="40"/> message_queue_data -->
- <!-- <name name="system_info" arity="1" clause_i="41"/> min_heap_size -->
- <!-- <name name="system_info" arity="1" clause_i="42"/> min_bin_vheap_size -->
- <name name="system_info" arity="1" clause_i="43"/> <!-- modified_timing_level -->
- <!-- <name name="system_info" arity="1" clause_i="44"/> multi_scheduling -->
- <!-- <name name="system_info" arity="1" clause_i="45"/> multi_scheduling_blockers -->
- <name name="system_info" arity="1" clause_i="46"/> <!-- nif_version -->
- <!-- n<name name="system_info" arity="1" clause_i="47"/> ormal_multi_scheduling_blockers -->
- <name name="system_info" arity="1" clause_i="48"/> <!-- otp_release -->
- <!-- <name name="system_info" arity="1" clause_i="49"/> os_monotonic_time_source -->
- <!-- <name name="system_info" arity="1" clause_i="50"/> os_system_time_source -->
- <name name="system_info" arity="1" clause_i="51"/> <!-- port_parallelism -->
- <!-- <name name="system_info" arity="1" clause_i="52"/> port_count -->
- <!-- <name name="system_info" arity="1" clause_i="53"/> port_limit -->
- <!-- <name name="system_info" arity="1" clause_i="54"/> process_count -->
- <!-- <name name="system_info" arity="1" clause_i="55"/> process_limit -->
- <!-- <name name="system_info" arity="1" clause_i="56"/> procs -->
- <!-- <name name="system_info" arity="1" clause_i="57"/> scheduler_bind_type -->
- <!-- <name name="system_info" arity="1" clause_i="58"/> scheduler_bindings -->
- <!-- <name name="system_info" arity="1" clause_i="59"/> scheduler_id -->
- <!-- <name name="system_info" arity="1" clause_i="60"/> schedulers -->
- <!-- <name name="system_info" arity="1" clause_i="61"/> smp_support -->
- <!-- <name name="system_info" arity="1" clause_i="62"/> start_time -->
- <name name="system_info" arity="1" clause_i="63"/> <!-- system_version -->
- <name name="system_info" arity="1" clause_i="64"/> <!-- system_architecture -->
- <!-- <name name="system_info" arity="1" clause_i="65"/> threads -->
- <!-- <name name="system_info" arity="1" clause_i="66"/> thread_pool_size -->
- <!-- <name name="system_info" arity="1" clause_i="67"/> time_correction -->
- <!-- <name name="system_info" arity="1" clause_i="68"/> time_offset -->
- <!-- <name name="system_info" arity="1" clause_i="69"/> time_warp_mode -->
- <!-- <name name="system_info" arity="1" clause_i="70"/> tolerant_timeofday -->
- <name name="system_info" arity="1" clause_i="71"/> <!-- trace_control_word -->
- <!-- <name name="system_info" arity="1" clause_i="72"/> update_cpu_info -->
- <name name="system_info" arity="1" clause_i="73"/> <!-- version -->
- <name name="system_info" arity="1" clause_i="74"/> <!-- wordsize -->
- <!-- <name name="system_info" arity="1" clause_i="75"/> overview -->
+ <!-- <name name="system_info" arity="1" clause_i="29"/> ets_count -->
+ <!-- <name name="system_info" arity="1" clause_i="30"/> ets_limit -->
+ <!-- <name name="system_info" arity="1" clause_i="31"/> fullsweep_after -->
+ <!-- <name name="system_info" arity="1" clause_i="32"/> garbage_collection -->
+ <!-- <name name="system_info" arity="1" clause_i="33"/> heap_sizes -->
+ <!-- <name name="system_info" arity="1" clause_i="34"/> heap_type -->
+ <name name="system_info" arity="1" clause_i="35"/> <!-- info -->
+ <name name="system_info" arity="1" clause_i="36"/> <!-- kernel_poll -->
+ <name name="system_info" arity="1" clause_i="37"/> <!-- loaded -->
+ <!-- <name name="system_info" arity="1" clause_i="38"/> logical_processors -->
+ <name name="system_info" arity="1" clause_i="39"/> <!-- machine -->
+ <!-- <name name="system_info" arity="1" clause_i="40"/> max_heap_size -->
+ <!-- <name name="system_info" arity="1" clause_i="41"/> message_queue_data -->
+ <!-- <name name="system_info" arity="1" clause_i="42"/> min_heap_size -->
+ <!-- <name name="system_info" arity="1" clause_i="43"/> min_bin_vheap_size -->
+ <name name="system_info" arity="1" clause_i="44"/> <!-- modified_timing_level -->
+ <!-- <name name="system_info" arity="1" clause_i="45"/> multi_scheduling -->
+ <!-- <name name="system_info" arity="1" clause_i="46"/> multi_scheduling_blockers -->
+ <name name="system_info" arity="1" clause_i="47"/> <!-- nif_version -->
+ <!-- n<name name="system_info" arity="1" clause_i="48"/> ormal_multi_scheduling_blockers -->
+ <name name="system_info" arity="1" clause_i="49"/> <!-- otp_release -->
+ <!-- <name name="system_info" arity="1" clause_i="50"/> os_monotonic_time_source -->
+ <!-- <name name="system_info" arity="1" clause_i="51"/> os_system_time_source -->
+ <name name="system_info" arity="1" clause_i="52"/> <!-- port_parallelism -->
+ <!-- <name name="system_info" arity="1" clause_i="53"/> port_count -->
+ <!-- <name name="system_info" arity="1" clause_i="54"/> port_limit -->
+ <!-- <name name="system_info" arity="1" clause_i="55"/> process_count -->
+ <!-- <name name="system_info" arity="1" clause_i="56"/> process_limit -->
+ <!-- <name name="system_info" arity="1" clause_i="57"/> procs -->
+ <!-- <name name="system_info" arity="1" clause_i="58"/> scheduler_bind_type -->
+ <!-- <name name="system_info" arity="1" clause_i="59"/> scheduler_bindings -->
+ <!-- <name name="system_info" arity="1" clause_i="60"/> scheduler_id -->
+ <!-- <name name="system_info" arity="1" clause_i="61"/> schedulers -->
+ <!-- <name name="system_info" arity="1" clause_i="62"/> smp_support -->
+ <!-- <name name="system_info" arity="1" clause_i="63"/> start_time -->
+ <name name="system_info" arity="1" clause_i="64"/> <!-- system_version -->
+ <name name="system_info" arity="1" clause_i="65"/> <!-- system_architecture -->
+ <!-- <name name="system_info" arity="1" clause_i="66"/> threads -->
+ <!-- <name name="system_info" arity="1" clause_i="67"/> thread_pool_size -->
+ <!-- <name name="system_info" arity="1" clause_i="68"/> time_correction -->
+ <!-- <name name="system_info" arity="1" clause_i="69"/> time_offset -->
+ <!-- <name name="system_info" arity="1" clause_i="70"/> time_warp_mode -->
+ <!-- <name name="system_info" arity="1" clause_i="71"/> tolerant_timeofday -->
+ <name name="system_info" arity="1" clause_i="72"/> <!-- trace_control_word -->
+ <!-- <name name="system_info" arity="1" clause_i="73"/> update_cpu_info -->
+ <name name="system_info" arity="1" clause_i="74"/> <!-- version -->
+ <name name="system_info" arity="1" clause_i="75"/> <!-- wordsize -->
+ <!-- <name name="system_info" arity="1" clause_i="76"/> overview -->
<fsummary>Information about the system.</fsummary>
<desc>
<marker id="system_info_misc_tags"/>
diff --git a/erts/doc/src/erlc.xml b/erts/doc/src/erlc.xml
index 2214b76a51..be9b4e8d97 100644
--- a/erts/doc/src/erlc.xml
+++ b/erts/doc/src/erlc.xml
@@ -4,7 +4,7 @@
<comref>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</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 0893eb291c..962bc9a244 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>2017</year>
+ <year>2002</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -487,11 +487,10 @@
utilization value used. Once a carrier is abandoned, no new
allocations are made in it. When an allocator instance gets an
increased multiblock carrier need, it first tries to fetch an
- abandoned carrier from an allocator instance of the same
- allocator type. If no abandoned carrier can be fetched, it
- creates a new empty carrier. When an abandoned carrier has been
- fetched, it will function as an ordinary carrier. This feature has
- special requirements on the
+ abandoned carrier from another allocator instance. If no abandoned
+ carrier can be fetched, it creates a new empty carrier. When an
+ abandoned carrier has been fetched, it will function as an ordinary
+ carrier. This feature has special requirements on the
<seealso marker="#M_as">allocation strategy</seealso> used. Only
the strategies <c>aoff</c>, <c>aoffcbf</c>, <c>aoffcaobf</c>,
<c>ageffcaoff</c>m, <c>ageffcbf</c> and <c>ageffcaobf</c>
@@ -584,7 +583,7 @@
carriers are decided in section
<seealso marker="#mseg_mbc_sizes">
The alloc_util Framework</seealso>. On
- 32-bit Unix style OS this limit cannot be set &gt; 128 MB.</p>
+ 32-bit Unix style OS this limit cannot be set &gt; 64 MB.</p>
</item>
<tag><marker id="M_mbcgs"/><c><![CDATA[+M<S>mbcgs <ratio>]]></c></tag>
<item>
diff --git a/erts/doc/src/match_spec.xml b/erts/doc/src/match_spec.xml
index 46a3daebe8..5cd6dc1750 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>2016</year>
+ <year>1999</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index 929d569f16..fa02c9dd21 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,1185 @@
</header>
<p>This document describes the changes made to the ERTS application.</p>
+<section><title>Erts 10.0.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed a bug which caused an emulator crash when
+ <c>enif_send()</c> was called by a NIF that executed on a
+ dirty scheduler. The bug was either triggered when the
+ NIF called <c>enif_send()</c> without a message
+ environment, or when the process executing the NIF was
+ <c>send</c> traced.</p>
+ <p>
+ Own Id: OTP-15223</p>
+ </item>
+ <item>
+ <p>
+ Fixed a bug causing some Erlang references to be
+ inconsistently ordered. This could for example cause
+ failure to look up certain elements with references as
+ keys in search data structures. This bug was introduced
+ in R13B02.</p>
+ <p>
+ Thanks to Simon Cornish for finding the bug and supplying
+ a fix.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15225</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.0.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a bug that prevented the <c>noshell</c> option
+ from working correctly on Mac OS X and BSD.</p>
+ <p>
+ Own Id: OTP-15169</p>
+ </item>
+ <item>
+ <p>Fixed a crash when matching directly against a literal
+ map using a single key that had been saved on the
+ stack.</p>
+ <p>
+ Own Id: OTP-15184</p>
+ </item>
+ <item>
+ <p>Fix node crash when passing a bad time option to
+ <c>file:read_file_info/2</c>.</p>
+ <p>
+ Own Id: OTP-15196</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.0.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a scheduler bug that caused normal schedulers to
+ run dirty code.</p>
+ <p>
+ Own Id: OTP-15154</p>
+ </item>
+ <item>
+ <p>
+ Fixed a bug in <c>erlang:trace_info/2</c> which caused
+ the emulator to crash when a bad argument was passed. The
+ bug was introduced in ERTS version 10.0.</p>
+ <p>
+ Own Id: OTP-15183 Aux Id: ERL-670 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.0.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a rare bug that could cause processes to be
+ scheduled after they had been freed.</p>
+ <p>
+ Own Id: OTP-15067 Aux Id: ERL-573 </p>
+ </item>
+ <item>
+ <p>Fixed a race condition in the inet driver that could
+ cause receive to hang when the emulator was compiled with
+ gcc 8.</p>
+ <p>
+ Own Id: OTP-15158 Aux Id: ERL-654 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>The keys used in <c>os:getenv</c> and <c>os:putenv</c>
+ are case-insensitive again on Windows.</p>
+ <p>
+ Own Id: OTP-15147 Aux Id: ERL-644 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.0</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The type specifications for <c>file:posix/0</c> and
+ <c>inet:posix/0</c> have been updated according to which
+ errors file and socket operations should be able to
+ return.</p>
+ <p>
+ Own Id: OTP-14019 Aux Id: ERL-550 </p>
+ </item>
+ <item>
+ <p>
+ Fix error printout from run_erl and a bug that could
+ cause unintended fds to be leaked into the started
+ program.</p>
+ <p>
+ Own Id: OTP-14537 Aux Id: PR1529 </p>
+ </item>
+ <item>
+ <p> File operations used to accept <seealso
+ marker="kernel:file#type-name_all">filenames</seealso>
+ containing null characters (integer value zero). This
+ caused the name to be truncated and in some cases
+ arguments to primitive operations to be mixed up.
+ Filenames containing null characters inside the filename
+ are now <em>rejected</em> and will cause primitive file
+ operations to fail. </p> <p> Also environment variable
+ operations used to accept <seealso
+ marker="kernel:os#type-env_var_name">names</seealso> and
+ <seealso
+ marker="kernel:os#type-env_var_value">values</seealso> of
+ environment variables containing null characters (integer
+ value zero). This caused operations to silently produce
+ erroneous results. Environment variable names and values
+ containing null characters inside the name or value are
+ now <em>rejected</em> and will cause environment variable
+ operations to fail. </p> <p>Primitive environment
+ variable operations also used to accept the <c>$=</c>
+ character in environment variable names causing various
+ problems. <c>$=</c> characters in environment variable
+ names are now also <em>rejected</em>. </p> <p>Also
+ <seealso
+ marker="kernel:os#cmd/1"><c>os:cmd/1</c></seealso> now
+ reject null characters inside its <seealso
+ marker="kernel:os#type-os_command">command</seealso>.
+ </p> <p><seealso
+ marker="erts:erlang#open_port/2"><c>erlang:open_port/2</c></seealso>
+ will also reject null characters inside the port name
+ from now on.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14543 Aux Id: ERL-370 </p>
+ </item>
+ <item>
+ <p>
+ Fix bugs related to the bookkeeping of microstate
+ accounting states.</p>
+ <p>
+ Own Id: OTP-14652</p>
+ </item>
+ <item>
+ <p><c>os:putenv</c> and <c>os:getenv</c> no longer access
+ the process environment directly and instead work on a
+ thread-safe emulation. The only observable difference is
+ that it's <em>not</em> kept in sync with libc
+ <c>getenv(3)</c> / <c>putenv(3)</c>, so those who relied
+ on that behavior in drivers or NIFs will need to add
+ manual synchronization.</p> <p>On Windows this means that
+ you can no longer resolve DLL dependencies by modifying
+ the <c>PATH</c> just before loading the driver/NIF. To
+ make this less of a problem, the emulator now adds the
+ target DLL's folder to the DLL search path.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14666</p>
+ </item>
+ <item>
+ <p>Corrected <c>erlang:is_builtin(erlang, M, F)</c> to
+ return <c>true</c> for <c>apply/2</c> and
+ <c>yield/0</c>.</p>
+ <p>
+ Own Id: OTP-14713 Aux Id: ERL-500 </p>
+ </item>
+ <item>
+ <p>Fixed a bug where the PATH environment variable wasn't
+ updated correctly on a release downgrade, effectively
+ keeping the PATH of the new release.</p>
+ <p>
+ Own Id: OTP-14719</p>
+ </item>
+ <item>
+ <p>A receive optimization that avoids scanning the entire
+ message queue when receiving a message containing a
+ freshly created reference could in rare circumstances
+ (involving recursive calls to the functions that does the
+ receive) cause the receive to hang. This has been
+ corrected.</p>
+ <p>
+ Own Id: OTP-14782 Aux Id: ERL-511 </p>
+ </item>
+ <item>
+ <p>
+ Fix building of Erlang/OTP on platforms which have small
+ data area with short addressing. For example the
+ PowerPC/RTEMS platform.</p>
+ <p>
+ Own Id: OTP-14909 Aux Id: PR-1692 </p>
+ </item>
+ <item>
+ <p>Fixed a crash when <c>enif_make_binary</c> is called
+ with a binary produced by <c>enif_inspect_binary</c> in a
+ different environment.</p>
+ <p>
+ Own Id: OTP-14931</p>
+ </item>
+ <item>
+ <p>Fixed a crash when <c>enif_make_binary</c> is called
+ more than once with a binary that had previously been
+ added to an <c>enif_ioq</c>.</p>
+ <p>
+ Own Id: OTP-14932</p>
+ </item>
+ <item>
+ <p>
+ The erl_child_setup program now ignores SIGTERM signals.</p>
+ <p>
+ Own Id: OTP-14943 Aux Id: ERL-576 </p>
+ </item>
+ <item>
+ <p>
+ Force 64-bit alignment on pre-allocators on architectures
+ which needs it.</p>
+ <p>
+ Own Id: OTP-14977</p>
+ </item>
+ <item>
+ <p>
+ Fixed a bug where dirty scheduler picked up non-dirty
+ work.</p>
+ <p>
+ Own Id: OTP-14978</p>
+ </item>
+ <item>
+ <p>
+ Calls to <c>gen_tcp:send/2</c> on closed sockets now
+ returns <c>{error, closed}</c> instead of
+ <c>{error,enotconn}</c>.</p>
+ <p>
+ Own Id: OTP-15001</p>
+ </item>
+ <item>
+ <p>
+ <c>erlang:monotonic_time/1</c> failed with <c>badarg</c>
+ when passing the <c>perf_counter</c> time unit as
+ argument.</p>
+ <p>
+ Own Id: OTP-15008</p>
+ </item>
+ <item>
+ <p>
+ Fix bug where rapid <c>init:restart()</c> calls would
+ sometimes crash because a code load request leaked in
+ between the restarts.</p>
+ <p>
+ Own Id: OTP-15013</p>
+ </item>
+ <item>
+ <p>
+ Improve <c>float_to_list(F, [{decimals,D}])</c> to closer
+ conform with <c>io_lib:format("~.*f", [D,F])</c>.</p>
+ <p>
+ There are however, still cases when <c>float_to_list</c>
+ does not produce the exact same result as
+ <c>io_lib:format</c>, especially for large values
+ <c>F</c> and/or many decimals <c>D</c>.</p>
+ <p>
+ Own Id: OTP-15015 Aux Id: OTP-14890 </p>
+ </item>
+ <item>
+ <p>Fixed a deadlock that would occur on certain
+ allocators when a reallocation failed with <c>+ramv</c>
+ enabled.</p>
+ <p>
+ Own Id: OTP-15024</p>
+ </item>
+ <item>
+ <p>
+ Fix bug that made it impossible to use an erl_tracer as
+ the seq_trace trace receiver.</p>
+ <p>
+ Own Id: OTP-15029</p>
+ </item>
+ <item>
+ <p>
+ Fix bug where a large (> 1 GB) emulator generated error
+ logger message would cause the emulator to crash.</p>
+ <p>
+ Own Id: OTP-15032</p>
+ </item>
+ <item>
+ <p>The emulator will no longer crash when reading the
+ file information of an ordinary file that has an NTFS
+ reparse point, such as files stored in a OneDrive-mapped
+ folder.</p>
+ <p>
+ Own Id: OTP-15062 Aux Id: ERL-615 </p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in <c>enif_binary_to_term</c> which could cause
+ memory corruption for immediate terms (atoms, small
+ integers, pids, ports, empty lists).</p>
+ <p>
+ Own Id: OTP-15080</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in <c>erlang:system_profile/2</c> that could
+ cause superfluous <c>{profile,_,active,_,_}</c> messages
+ for terminating processes.</p>
+ <p>
+ Own Id: OTP-15085</p>
+ </item>
+ <item>
+ <p>
+ On OSs with per thread CPU time support, change
+ <c>cpu_timestamp</c> in <seealso
+ marker="erlang#trace/3">erlang:trace/3</seealso> to use
+ it instead of per process CPU time. This makes this
+ option useable on such OSs when running multiple
+ schedulers.</p>
+ <p>
+ Own Id: OTP-15090</p>
+ </item>
+ <item>
+ <p>
+ Fix segfault in abort_signal_task which could happen if a
+ port terminated while there were outstanding port tasks
+ that were not signals, for example a
+ ready_input/ready_output event.</p>
+ <p>
+ Own Id: OTP-15108 Aux Id: ERL-621 </p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in <c>ets</c> that could cause VM crash if
+ process A terminates after fixating a table and process B
+ deletes the table at "the same time". The table fixation
+ could be done with <c>ets:safe_fixtable</c> or if process
+ A terminates in the middle of a long running
+ <c>select</c> or <c>match</c> call.</p>
+ <p>
+ Own Id: OTP-15109</p>
+ </item>
+ <item>
+ <p>Owner and group changes through
+ <c>file:write_file_info</c>, <c>file:change_owner</c>,
+ and <c>file:change_group</c> will no longer report
+ success on permission errors.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15118</p>
+ </item>
+ <item>
+ <p>
+ Fix a bug error reporting from escripts on windows where
+ the error message would get garbled.</p>
+ <p>
+ Own Id: OTP-15119 Aux Id: PR-1826 </p>
+ </item>
+ <item>
+ <p>
+ Fix segfault when a process is interally re-scheduled
+ while being traced for in out events. This bug was
+ introduced in erts-8.0 (OTP-19.0).</p>
+ <p>
+ Own Id: OTP-15125</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>It is now possible to open device files and FIFOs with
+ <c>file:open/2</c>.</p>
+ <p>
+ Own Id: OTP-11462</p>
+ </item>
+ <item>
+ <p>
+ The <c>erlang:system_flag(scheduler_wall_time,Bool)</c>
+ call is now reference counted and will be turned off if
+ the (last) process that started the performance
+ statistics dies. Thus it is no longer possible to start
+ the statistics with <c>rpc:call(Node, erlang,
+ system_flag, [scheduler_wall_time, true])</c> since it
+ will be turned off directly afterwards when the rpc
+ process dies.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-11694</p>
+ </item>
+ <item>
+ <p>A new logging API is added to Erlang/OTP, see the
+ <seealso
+ marker="kernel:logger"><c>logger(3)</c></seealso> manual
+ page, and section <seealso
+ marker="kernel:logger_chapter">Logging</seealso> in the
+ Kernel User's Guide.</p>
+ <p>Calls to <c>error_logger</c> are automatically
+ redirected to the new API, and legacy error logger event
+ handlers can still be used. It is, however, recommended
+ to use the Logger API directly when writing new code.</p>
+ <p>Notice the following potential incompatibilities:</p>
+ <list> <item><p>Kernel configuration parameters
+ <c>error_logger</c> still works, but is overruled if the
+ default handler's output destination is configured with
+ Kernel configuration parameter <c>logger</c>.</p> <p>In
+ general, parameters for configuring error logger are
+ overwritten by new parameters for configuring
+ Logger.</p></item> <item><p>The concept of SASL error
+ logging is deprecated, meaning that by default the SASL
+ application does not affect which log events are
+ logged.</p> <p>By default, supervisor reports and crash
+ reports are logged by the default Logger handler started
+ by Kernel, and end up at the same destination (terminal
+ or file) as other standard log event from Erlang/OTP.</p>
+ <p>Progress reports are not logged by default, but can be
+ enabled by setting the primary log level to info, for
+ example with the Kernel configuration parameter
+ <c>logger_level</c>.</p> <p>To obtain backwards
+ compatibility with the SASL error logging functionality
+ from earlier releases, set Kernel configuration parameter
+ <c>logger_sasl_compatible</c> to <c>true</c>. This
+ prevents the default Logger handler from logging any
+ supervisor-, crash-, or progress reports. Instead, SASL
+ adds a separate Logger handler during application start,
+ which takes care of these log events. The SASL
+ configuration parameters <c>sasl_error_logger</c> and
+ <c>sasl_errlog_type</c> specify the destination (terminal
+ or file) and severity level to log for these
+ events.</p></item></list>
+ <p>
+ Since Logger is new in Erlang/OTP 21.0, we do reserve the
+ right to introduce changes to the Logger API and
+ functionality in patches following this release. These
+ changes might or might not be backwards compatible with
+ the initial version.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-13295</p>
+ </item>
+ <item>
+ <p>
+ <c>gen_sctp:connect_init/4</c> or rather connect in
+ <c>inet_drv.c</c> for SCTP has been fixed to not check
+ the write file descriptor for writeability after a
+ connect, since for SCTP (SOCK_SEQPACKET) that property
+ does not seem to be any kind of indicator for when a
+ connect has finished. This fixes connects that the OS
+ returned as "in progress" that was misinterpreted by
+ <c>gen_sctp:connect_init</c> as failed.</p>
+ <p>
+ Own Id: OTP-13760 Aux Id: PR-1592 </p>
+ </item>
+ <item>
+ <p>The file driver has been rewritten as a NIF,
+ decreasing the latency of file operations. Notable
+ incompatibilities are:</p> <list> <item><p>The
+ <c>use_threads</c> option for <c>file:sendfile/5</c> no
+ longer has any effect; we either use non-blocking
+ <c>sendfile(2)</c> or fall back to <c>file:read</c> +
+ <c>gen_tcp:send</c>. </p></item> <item><p>The
+ file-specific DTrace probes have been removed. The same
+ effect can be achieved with normal tracing together with
+ the <c>nif__entry</c>/<c>nif__return</c> probes to track
+ scheduling.</p></item> </list>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14256</p>
+ </item>
+ <item>
+ <p>The I/O polling functionality of erts has been
+ re-written to better make use of the OSs polling
+ mechanisms. This change means that erts will now always
+ prefer to use a kernel-polling mechanism if possible.
+ Also all of the I/O polling has been moved to dedicated
+ threads instead of being placed in the scheduler
+ loops.</p> <p>As a result of this, the <c>erl</c> options
+ <c>+K</c> and <c>+secio</c> have been removed. It is
+ still possible to disable kernel-poll, but it has to be
+ done at compile time through the configure option
+ <c>--disable-kernel-poll</c>.</p> <p>The new <c>erl</c>
+ options <seealso marker="erl#+IOt"><c>+IOt</c></seealso>
+ and <seealso marker="erl#+IOp"><c>+IOp</c></seealso> can
+ be used to change how many IO poll threads and poll sets
+ that erts should use. See their respective documentation
+ for more details.</p>
+ <p>
+ Own Id: OTP-14346</p>
+ </item>
+ <item>
+ <p>Truly asynchronous auto-connect. Earlier, when
+ <c>erlang:send</c> was aimed toward an unconnected node,
+ the function would not return until the connection setup
+ had completed (or failed). Now the function returns
+ directly after the message has been enqueued and the
+ connection setup started.</p>
+ <p>The same applies to all distributed operations that
+ may trigger auto-connect, i.e. <c>'!'</c>, <c>send</c>,
+ <c>link</c>, <c>monitor</c>, <c>monitor_node</c>,
+ <c>exit/2</c> and <c>group_leader</c>.</p>
+ <p>The interface for all these functions are unchanged as
+ they do not return connection failures. The only
+ exception is <c>erlang:monitor</c> where a <em>possible
+ incompatibility</em> is introduced: An attempt to monitor
+ a process on a primitive node (such as erl_interface or
+ jinterface), where remote process monitoring is not
+ implemented, will no longer fail with <c>badarg</c>
+ exception. Instead a monitor will be created, but it will
+ only supervise the connection to the node.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14370</p>
+ </item>
+ <item>
+ <p>Changed the default behaviour of <c>.erlang</c>
+ loading: <c>.erlang</c> is no longer loaded from the
+ current directory. <c>c:erlangrc(PathList)</c> can be
+ used to search and load an <c>.erlang</c> file from user
+ specified directories.</p> <p><c>escript</c>,
+ <c>erlc</c>, <c>dialyzer</c> and <c>typer</c> no longer
+ load an <c>.erlang</c> at all.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14439</p>
+ </item>
+ <item>
+ <p>
+ New functionality for implementation of alternative
+ carriers for the Erlang distribution has been introduced.
+ This mainly consists of support for usage of distribution
+ controller processes (previously only ports could be used
+ as distribution controllers). For more information see
+ <seealso marker="erts:alt_dist#distribution_module">ERTS
+ User's Guide ➜ How to implement an Alternative Carrier
+ for the Erlang Distribution ➜ Distribution
+ Module</seealso>.</p>
+ <p>
+ Own Id: OTP-14459</p>
+ </item>
+ <item>
+ <p>
+ Add support for the lcc compiler and in extension the
+ Elbrus 2000 platform.</p>
+ <p>
+ Own Id: OTP-14492</p>
+ </item>
+ <item>
+ <p>Support for "tuple calls" have been removed from the
+ run-time system. Tuple calls was an undocumented and
+ unsupported feature which allowed the module argument for
+ an apply operation to be a tuple: <c>Var = dict:new(),
+ Var:size()</c>. This "feature" frequently caused
+ confusion, especially when such call failed. The
+ stacktrace would point out functions that don't exist in
+ the source code.</p>
+ <p>For legacy code that need to use parameterized modules
+ or tuple calls for some other reason, there is a new
+ compiler option called <c>tuple_calls</c>. When this
+ option is given, the compiler will generate extra code
+ that emulates the old behavior for calls where the module
+ is a variable.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14497</p>
+ </item>
+ <item>
+ <p>Creation of small maps with literal keys has been
+ optimized to be faster and potentially use less memory.
+ The keys are combined into a literal key tuple which is
+ put into the literal pool. The key tuple can be shared
+ between many instances of maps having the same keys.</p>
+ <p>
+ Own Id: OTP-14502</p>
+ </item>
+ <item>
+ <p>
+ When an exception is thrown, include the arguments of the
+ call in the stacktrace for BIFs <c>band</c>, <c>bor</c>,
+ <c>bsl</c>, <c>bsr</c>, <c>bxor</c>, <c>div</c>,
+ <c>rem</c> and the operators <c>+</c>, <c>-</c>, <c>*</c>
+ and <c>/</c>.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14508</p>
+ </item>
+ <item>
+ <p>
+ The non-smp emulators have been removed. This means that
+ the configure options <c>--disable-threads</c> and
+ <c>--enable-plain-emulator</c> have been removed and
+ configure will now refuse to build Erlang/OTP on
+ platforms without thread support.</p>
+ <p>
+ In order to achieve a similar setup as the non-smp
+ emulator, it is possible to start Erlang/OTP with the
+ <c>+S 1</c> option.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14518</p>
+ </item>
+ <item>
+ <p>Modules that use floating point constants compiled
+ with R15 or earlier will need to be re-compiled before
+ they can be loaded.</p>
+ <p>
+ Own Id: OTP-14575</p>
+ </item>
+ <item>
+ <p>
+ Implementation of true asynchronous signaling between
+ processes in order to improve scalability. Signals
+ affected include exit, monitor, demonitor, monitor
+ triggered, link, unlink, and group leader.</p>
+ <p>
+ Own Id: OTP-14589</p>
+ </item>
+ <item>
+ <p>
+ Added a PGO (profile guided optimization) pass to the
+ build step of erts. This can be disabled by passing
+ --disable-pgo to configure.</p>
+ <p>
+ Own Id: OTP-14604</p>
+ </item>
+ <item>
+ <p>
+ Improved the performance of <c>binary:split</c> and
+ <c>binary:match</c>.</p>
+ <p>
+ Own Id: OTP-14610 Aux Id: PR-1480 </p>
+ </item>
+ <item>
+ <p>
+ It is not longer possible to disable dirty schedulers
+ when building erlang.</p>
+ <p>
+ Own Id: OTP-14613</p>
+ </item>
+ <item>
+ <p>Loaded BEAM code in a 64-bit system requires less
+ memory because of better packing of operands for
+ instructions.</p>
+ <p>These memory savings were achieved by major
+ improvements to the <c>beam_makeops</c> scripts used when
+ building the run time system and BEAM compiler. There is
+ also new for documentation for <c>beam_makeops</c> that
+ describes how new BEAM instructions and loader
+ transformations can be implemented. The documentation is
+ found in here in a source directory or git repository:
+ erts/emulator/internal_doc/beam_makeops.md. An online
+ version can be found here:
+ https://github.com/erlang/otp/blob/master/erts/emulator/internal_doc/beam_makeops.md</p>
+ <p>
+ Own Id: OTP-14626</p>
+ </item>
+ <item>
+ <p><c>file:read_file</c> has been changed to read the
+ content of files that report a size of 0 even when data
+ can be read from them. An example of such a file is
+ <c>/proc/cpuinfo</c> on Linux.</p>
+ <p>
+ Own Id: OTP-14637 Aux Id: ERL-327 PR-1524 </p>
+ </item>
+ <item>
+ <p>
+ It is no longer possible to disable the <c>temp_alloc</c>
+ allocator. Disabling it caused serious performance
+ degradations and was never what was wanted.</p>
+ <p>
+ Own Id: OTP-14651</p>
+ </item>
+ <item>
+ <p>The reduction cost of sending messages is now
+ constant. It will no longer scale according to the length
+ of the receiving process' message queue.</p>
+ <p>
+ Own Id: OTP-14667</p>
+ </item>
+ <item>
+ <p>
+ Improved loading of modules with <c>-on_load</c>
+ directive, to no longer block all schedulers when the
+ load operation is completed.</p>
+ <p>
+ Own Id: OTP-14680</p>
+ </item>
+ <item>
+ <p>
+ On platforms with real-time signals available, SIGRTMIN+1
+ is now used as the internal scheduler suspend signal
+ instead of SIGUSR2.</p>
+ <p>
+ Own Id: OTP-14682</p>
+ </item>
+ <item>
+ <p>When the value returned from a '<c>catch</c>'
+ expression is ignored, no stacktrace will be built if an
+ exception is caught. That will save time and produce less
+ garbage. There are also some minor optimizations of
+ '<c>try</c>/<c>catch</c>' both in the compiler and
+ run-time system.</p>
+ <p>
+ Own Id: OTP-14683</p>
+ </item>
+ <item>
+ <p>The guarantees and non-guarantees of
+ <c>erlang:get_stacktrace/0</c> are now documented.</p>
+ <p>
+ Own Id: OTP-14687</p>
+ </item>
+ <item>
+ <p>There is a new syntax in '<c>try/catch</c>' for
+ retrieving the stacktrace without calling
+ '<c>erlang:get_stacktrace/0</c>'. See the reference
+ manual for a description of the new syntax. The
+ '<c>erlang:get_stacktrace/0</c>' BIF is now
+ deprecated.</p>
+ <p>
+ Own Id: OTP-14692</p>
+ </item>
+ <item>
+ <p>
+ New 'used' option for <c>binary_to_term/2</c> that will
+ also return number of bytes actually read from the
+ binary. This enables easy access to any extra data in the
+ binary located directly after the returned term.</p>
+ <p>
+ Own Id: OTP-14780</p>
+ </item>
+ <item>
+ <p>
+ Added more statistics for
+ <c>erlang:system_info({allocator,A})</c> in the
+ <c>mbcs_pool</c> section.</p>
+ <p>
+ Own Id: OTP-14795 Aux Id: ERL-88 </p>
+ </item>
+ <item>
+ <p>Added <c>enif_ioq_peek_head</c> to retrieve Erlang
+ terms from NIF IO queues without having to resort to
+ copying.</p>
+ <p>
+ Own Id: OTP-14797</p>
+ </item>
+ <item>
+ <p>There is a new option '<c>makedep_side_effect</c>' for
+ the compiler and <c>-MMD</c> for '<c>erlc</c>' that
+ generates dependencies and continues to compile as
+ normal.</p>
+ <p>
+ Own Id: OTP-14830</p>
+ </item>
+ <item>
+ <p>Added <c>ets:whereis/1</c> for retrieving the table
+ identifier of a named table.</p>
+ <p>
+ Own Id: OTP-14884</p>
+ </item>
+ <item>
+ <p><c>seq_trace</c> labels may now be any erlang
+ term.</p>
+ <p>
+ Own Id: OTP-14899</p>
+ </item>
+ <item>
+ <p>
+ Optimized the common case of <c>monitor</c> followed by
+ <c>send</c> to the same local process. The monitor signal
+ is now delayed in order to be piggybacked with the sent
+ message and thereby only get one lock operation on the
+ message queue of the receiver. A delayed monitor signal
+ is flushed if no <c>send</c> has been done at the latest
+ when the process is scheduled out.</p>
+ <p>
+ Own Id: OTP-14901</p>
+ </item>
+ <item>
+ <p>
+ Make hipe compiled code work on x86_64 (amd64) with OS
+ security feature PIE, where executable code can be loaded
+ into a random location. Old behavior, if hipe was
+ enabled, was to disable PIE build options for the VM.</p>
+ <p>
+ Own Id: OTP-14903</p>
+ </item>
+ <item>
+ <p>The number of driver async threads will now default to
+ 1 as the standard drivers do not use them anymore. Users
+ that changed this value to tweak the file driver should
+ replace <c>+A</c> with <c>+SDio</c> since it now uses
+ dirty IO schedulers instead of async threads.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14928</p>
+ </item>
+ <item>
+ <p>
+ Optimize <c>==</c> and <c>/=</c> for binaries with
+ different sizes to be constant in time instead of
+ proportional to the size of their common prefix.</p>
+ <p>
+ Own Id: OTP-14934 Aux Id: PR-1708 </p>
+ </item>
+ <item>
+ <p>
+ Refactorings making some internal process flags available
+ for other usage.</p>
+ <p>
+ Own Id: OTP-14948</p>
+ </item>
+ <item>
+ <p>
+ Removed need for HiPE to allocate native executable
+ memory in low 2GB address space on x86_64. Command line
+ option <c>+MXscs</c> is thereby obsolete and ignored.</p>
+ <p>
+ Own Id: OTP-14951</p>
+ </item>
+ <item>
+ <p>Added <c>enif_make_map_from_arrays</c> for creating a
+ populated map, analogous to
+ <c>enif_make_list_from_array</c>.</p>
+ <p>
+ Own Id: OTP-14954</p>
+ </item>
+ <item>
+ <p>Added configuration switches for busy-wait and wake up
+ thresholds for dirty schedulers, and changing these
+ settings for normal schedulers will no longer affect
+ dirty schedulers. </p> <p>Refer to the documentation for
+ details. The new switches are <seealso
+ marker="erl#+sbwtdcpu">+sbwtdcpu</seealso>, <seealso
+ marker="erl#+sbwtdio">+sbwtdio</seealso>, <seealso
+ marker="erl#+swtdcpu">+swtdcpu</seealso>, and <seealso
+ marker="erl#+swtdio">+swtdio</seealso>.</p> <p>The
+ default busy wait threshold for dirty scheduler threads
+ has also been lowered to <c>short</c>.</p>
+ <p>
+ Own Id: OTP-14959</p>
+ </item>
+ <item>
+ <p>
+ The list of "taints" now also includes dynamic loaded
+ drivers in addition to NIF libraries. Statically linked
+ drivers and NIF libraries that are part of erts are not
+ included. The "taints" are returned by
+ <c>system_info(taints)</c> and printed in the header of
+ <c>erl_crash.dump</c> files.</p>
+ <p>
+ Own Id: OTP-14960</p>
+ </item>
+ <item>
+ <p>Added <c>instrument:allocations</c> and
+ <c>instrument:carriers</c> for retrieving information
+ about memory utilization and fragmentation.</p>
+ <p>The old <c>instrument</c> interface has been removed,
+ as have the related options <c>+Mim</c> and
+ <c>+Mis</c>.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14961</p>
+ </item>
+ <item>
+ <p>The process suspend functionality used by the <seealso
+ marker="erlang#suspend_process/2">erlang:suspend_process/2</seealso>
+ BIF has been reimplemented using the newly introduced
+ true asynchronous signaling between processes. This
+ mainly to reduce memory usage in the process control
+ block of all processes, but also in order to simplify the
+ implementation.</p> <warning> <p>You can easily create
+ deadlocks if processes suspends each other (directly or
+ in circles). In ERTS versions prior to ERTS version 10.0,
+ the runtime system prevented such deadlocks, but this
+ prevention has now been removed due to performance
+ reasons.</p> </warning> <p>Other ERTS internal
+ functionality that used the previous process suspend
+ functionality have also been reimplemented to use
+ asynchronous signaling instead.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14964 Aux Id: OTP-14589 </p>
+ </item>
+ <item>
+ <p>Added the <c>nifs</c> option to
+ <c>?MODULE:module_info/1</c> for listing a module's
+ installed NIF functions.</p>
+ <p>
+ Own Id: OTP-14965</p>
+ </item>
+ <item>
+ <p>
+ New implementation of <c>erlang:process_info/[1,2]</c>.</p>
+ <p>
+ In the general case when inspecting another process, the
+ new implementation sends an asynchronous process-info
+ request signal to the other process and waits for the
+ result instead of locking the other process and reading
+ the result directly. In some special cases where no
+ conflicts occur, signal order wont be violated, and the
+ amount of data requested is guaranteed to be small, the
+ inspected process may be inspected directly.</p>
+ <p>
+ Appropriate amount of reductions are now also bumped when
+ inspecting a process.</p>
+ <p>
+ Own Id: OTP-14966</p>
+ </item>
+ <item>
+ <p>
+ Removed process start time from crash dump in order to
+ save memory in process control block.</p>
+ <p>
+ Own Id: OTP-14975 Aux Id: PR-1597 </p>
+ </item>
+ <item>
+ <p>
+ Optimize <c>erlang:put/2</c> when updating existing key
+ with a new immediate value (atom, small integer, pid,
+ port).</p>
+ <p>
+ Own Id: OTP-14976</p>
+ </item>
+ <item>
+ <p>
+ <c>erlang:process_info/1</c> has been changed to no
+ longer include <c>messages</c> by default. Instead
+ <c>erlang:process_info/2</c> should be used.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14986 Aux Id: PR-1745 </p>
+ </item>
+ <item>
+ <p>
+ New <c>erlang:system_info(ets_count)</c> to get total
+ number of ets tables existing at the local node.</p>
+ <p>
+ Own Id: OTP-14987</p>
+ </item>
+ <item>
+ <p>
+ New NIF functions: <c>enif_mutex_name</c>,
+ <c>enif_cond_name</c>, <c>enif_rwlock_name</c>,
+ <c>enif_thread_name</c>, <c>enif_vfprintf</c>,
+ <c>enif_vsnprintf</c>.</p>
+ <p>
+ Own Id: OTP-14994</p>
+ </item>
+ <item>
+ <p>When <c>erlang:system_flag(backtrace_depth, 0)</c> has
+ been called, all exceptions will now contain the entry
+ for <em>one</em> function (despite the zero). It used to
+ be that a hand-made stack backtrace passed to
+ <c>erlang:raise/3</c> would be be truncated to an empty
+ list.</p>
+ <p>
+ Own Id: OTP-15026</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug for named <c>ets</c> tables which could cause
+ unexpected results from matchspec iteration functions
+ (<c>ets:select*</c> and <c>ets:match*</c>) if the table
+ was deleted and recreated with the same name during the
+ iteration. The iteration could incorrectly continue
+ through the recreated table. The expected correct
+ behavior is now for the iteration call to fail with a
+ <c>badarg</c> exception if the table is deleted before
+ the iteration has completed.</p>
+ <p>
+ Own Id: OTP-15031</p>
+ </item>
+ <item>
+ <p>Two new guards BIFs operating on maps have been added:
+ <c>map_get/2</c> and <c>is_map_key/2</c>. They do the
+ same as <c>maps:get/2</c> and <c>maps:is_key/2</c>,
+ respectively, except that they are allowed to be used in
+ guards.</p>
+ <p>
+ Own Id: OTP-15037 Aux Id: PR-1784, PR-1802 </p>
+ </item>
+ <item>
+ <p>
+ Release run-queue lock while cleaning up terminated dirty
+ process.</p>
+ <p>
+ Own Id: OTP-15081</p>
+ </item>
+ <item>
+ <p>The callback module passed as <c>-epmd_module</c> to
+ erl has been expanded to be able to do name and port
+ resolving.</p> <p>Documentation has also been added in
+ the <seealso
+ marker="kernel:erl_epmd"><c>erl_epmd</c></seealso>
+ reference manual and ERTS User's Guide <seealso
+ marker="erts:alt_disco">How to Implement an Alternative
+ Service Discovery for Erlang Distribution</seealso>.</p>
+ <p>
+ Own Id: OTP-15086 Aux Id: PR-1694 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 9.3.3.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed a bug which caused an emulator crash when
+ <c>enif_send()</c> was called by a NIF that executed on a
+ dirty scheduler. The bug was either triggered when the
+ NIF called <c>enif_send()</c> without a message
+ environment, or when the process executing the NIF was
+ <c>send</c> traced.</p>
+ <p>
+ Own Id: OTP-15223</p>
+ </item>
+ <item>
+ <p>
+ Fixed a bug causing some Erlang references to be
+ inconsistently ordered. This could for example cause
+ failure to look up certain elements with references as
+ keys in search data structures. This bug was introduced
+ in R13B02.</p>
+ <p>
+ Thanks to Simon Cornish for finding the bug and supplying
+ a fix.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15225</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 9.3.3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a race condition in the inet driver that could
+ cause receive to hang when the emulator was compiled with
+ gcc 8.</p>
+ <p>
+ Own Id: OTP-15158 Aux Id: ERL-654 </p>
+ </item>
+ <item>
+ <p>
+ Fix bug in generation of erl_crash.dump, which could
+ cause VM to crash.</p>
+ <p>
+ Bug exist since erts-9.2 (OTP-20.2).</p>
+ <p>
+ Own Id: OTP-15181</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 9.3.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a rare bug that could cause processes to be
+ scheduled after they had been freed.</p>
+ <p>
+ Own Id: OTP-15067 Aux Id: ERL-573 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 9.3.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed bug in <c>ets</c> that could cause VM crash if
+ process A terminates after fixating a table and process B
+ deletes the table at "the same time". The table fixation
+ could be done with <c>ets:safe_fixtable</c> or if process
+ A terminates in the middle of a long running
+ <c>select</c> or <c>match</c> call.</p>
+ <p>
+ Own Id: OTP-15109</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 9.3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed bug in <c>enif_binary_to_term</c> which could cause
+ memory corruption for immediate terms (atoms, small
+ integers, pids, ports, empty lists).</p>
+ <p>
+ Own Id: OTP-15080</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in <c>erlang:system_profile/2</c> that could
+ cause superfluous <c>{profile,_,active,_,_}</c> messages
+ for terminating processes.</p>
+ <p>
+ Own Id: OTP-15085</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 9.3.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -1413,6 +2592,63 @@
</section>
+<section><title>Erts 8.3.5.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a race condition in the inet driver that could
+ cause receive to hang when the emulator was compiled with
+ gcc 8.</p>
+ <p>
+ Own Id: OTP-15158 Aux Id: ERL-654 </p>
+ </item>
+ <item>
+ <p>
+ Fixed a bug causing some Erlang references to be
+ inconsistently ordered. This could for example cause
+ failure to look up certain elements with references as
+ keys in search data structures. This bug was introduced
+ in R13B02.</p>
+ <p>
+ Thanks to Simon Cornish for finding the bug and supplying
+ a fix.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15225</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 8.3.5.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a bug in file closure on Unix; close(2) was
+ retried on EINTR which could cause a different (recently
+ opened) file to be closed as well.</p>
+ <p>
+ Own Id: OTP-14775</p>
+ </item>
+ <item>
+ <p>
+ A race-condition when tearing down a connection with
+ active node monitors could cause the runtime system to
+ crash.</p>
+ <p>
+ This bug was introduced in ERTS version 8.0 (OTP 19.0).</p>
+ <p>
+ Own Id: OTP-14781 Aux Id: OTP-13047 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 8.3.5.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -8823,7 +10059,7 @@
you use erlang:halt/2 with an integer first argument and
an option list containing {flush,false} as the second
argument. Note that now is flushing not dependant of the
- exit code, and you can not only flush async threads
+ exit code, and you cannot only flush async threads
operations which we deemed as a strange behaviour anyway.
</p>
<p>Also, erlang:halt/1,2 has gotten a new feature: If the
diff --git a/erts/doc/src/part.xml b/erts/doc/src/part.xml
index d583b873a0..05e9a24af8 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>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -37,6 +37,7 @@
<xi:include href="match_spec.xml"/>
<xi:include href="crash_dump.xml"/>
<xi:include href="alt_dist.xml"/>
+ <xi:include href="alt_disco.xml"/>
<xi:include href="absform.xml"/>
<xi:include href="tty.xml"/>
<xi:include href="driver.xml"/>
diff --git a/erts/doc/src/run_erl.xml b/erts/doc/src/run_erl.xml
index e4c1b943c4..fa36457489 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>2016</year>
+ <year>1999</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/erts/doc/src/time_correction.xml b/erts/doc/src/time_correction.xml
index 77e7a40529..53b555387c 100644
--- a/erts/doc/src/time_correction.xml
+++ b/erts/doc/src/time_correction.xml
@@ -940,7 +940,7 @@ EventTag = {Time, UMI}</code>
</item>
<item>
<seealso marker="erlang#system_info_os_system_time_source">
- <c>erlang:system_info(os_system_time_source)</c></seealso>)
+ <c>erlang:system_info(os_system_time_source)</c></seealso>
</item>
</list>
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index 5dfa60ee74..054692819e 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -517,7 +517,9 @@ release_docs_spec:
# Generated source code. Put in $(TARGET) directory
#
+ifneq ($(strip $(CREATE_DIRS)),)
_create_dirs := $(shell mkdir -p $(CREATE_DIRS))
+endif
# has to be run after _create_dirs
@@ -570,7 +572,7 @@ $(TTF_DIR)/OPCODES-GENERATED: $(OPCODE_TABLES) utils/beam_makeops
-code-model @CODE_MODEL@ \
-outdir $(TTF_DIR) \
-DUSE_VM_PROBES=$(if $(USE_VM_PROBES),1,0) \
- -DNO_FPE_SIGNALS=$(if $filter(unreliable,$(FPE)),1,0) \
+ -DNO_FPE_SIGNALS=$(if $(filter unreliable,$(FPE)),1,0) \
-emulator $(OPCODE_TABLES) && echo $? >$(TTF_DIR)/OPCODES-GENERATED
GENERATE += $(TTF_DIR)/OPCODES-GENERATED
diff --git a/erts/emulator/beam/atom.c b/erts/emulator/beam/atom.c
index e5b7616a0d..5381611fab 100644
--- a/erts/emulator/beam/atom.c
+++ b/erts/emulator/beam/atom.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/atom.h b/erts/emulator/beam/atom.h
index 385120a8d9..ca920679c6 100644
--- a/erts/emulator/beam/atom.h
+++ b/erts/emulator/beam/atom.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index fba0611042..45b7540aeb 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -142,6 +142,7 @@ atom bsr
atom bsr_anycrlf
atom bsr_unicode
atom build_type
+atom busy
atom busy_dist_port
atom busy_port
atom call
@@ -252,6 +253,7 @@ atom exception_from
atom exception_trace
atom exclusive
atom exit_status
+atom exited
atom existing
atom existing_processes
atom existing_ports
@@ -445,6 +447,7 @@ atom no_float
atom no_integer
atom no_network
atom no_start_optimize
+atom not_suspended
atom not
atom not_a_list
atom not_loaded
diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c
index d9312f4df8..d221e6aea6 100644
--- a/erts/emulator/beam/beam_bif_load.c
+++ b/erts/emulator/beam/beam_bif_load.c
@@ -603,8 +603,9 @@ badarg:
BIF_RETTYPE erts_internal_check_dirty_process_code_2(BIF_ALIST_2)
{
+ erts_aint32_t state;
Process *rp;
- int reds = 0;
+ int dirty, busy, reds = 0;
Eterm res;
if (BIF_P != erts_dirty_process_signal_handler
@@ -618,20 +619,29 @@ BIF_RETTYPE erts_internal_check_dirty_process_code_2(BIF_ALIST_2)
if (is_not_atom(BIF_ARG_2))
BIF_ERROR(BIF_P, BADARG);
- 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_YIELD2(bif_export[BIF_erts_internal_check_dirty_process_code_2],
- BIF_P, BIF_ARG_1, BIF_ARG_2);
+ if (BIF_ARG_1 == BIF_P->common.id)
+ BIF_RET(am_normal);
+
+ rp = erts_proc_lookup_raw(BIF_ARG_1);
if (!rp)
- BIF_RET(am_false);
-
+ BIF_RET(am_false);
+
+ state = erts_atomic32_read_nob(&rp->state);
+ dirty = (state & (ERTS_PSFLG_DIRTY_RUNNING
+ | ERTS_PSFLG_DIRTY_RUNNING_SYS));
+ if (!dirty)
+ BIF_RET(am_normal);
+
+ busy = erts_proc_trylock(rp, ERTS_PROC_LOCK_MAIN) == EBUSY;
+
+ if (busy)
+ BIF_RET(am_busy);
+
res = erts_check_process_code(rp, BIF_ARG_2, &reds, BIF_P->fcalls);
- if (BIF_P != rp)
- erts_proc_unlock(rp, ERTS_PROC_LOCK_MAIN);
+ erts_proc_unlock(rp, ERTS_PROC_LOCK_MAIN);
- ASSERT(is_value(res));
+ ASSERT(res == am_true || res == am_false);
BIF_RET2(res, reds);
}
@@ -1743,6 +1753,7 @@ BIF_RETTYPE erts_internal_purge_module_2(BIF_ALIST_2)
if (literals) {
ErtsLiteralAreaRef *ref;
+ ErtsMessage *mp;
ref = erts_alloc(ERTS_ALC_T_LITERAL_REF,
sizeof(ErtsLiteralAreaRef));
ref->literal_area = literals;
@@ -1757,10 +1768,12 @@ BIF_RETTYPE erts_internal_purge_module_2(BIF_ALIST_2)
release_literal_areas.last = ref;
}
erts_mtx_unlock(&release_literal_areas.mtx);
+ mp = erts_alloc_message(0, NULL);
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
erts_queue_proc_message(BIF_P,
erts_literal_area_collector,
0,
- erts_alloc_message(0, NULL),
+ mp,
am_copy_literals);
}
diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c
index b8a8d06315..9633de2021 100644
--- a/erts/emulator/beam/beam_debug.c
+++ b/erts/emulator/beam/beam_debug.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1998-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -667,7 +667,7 @@ print_op(fmtfn_t to, void *to_arg, int op, int size, BeamInstr* addr)
ap++;
break;
case 'l': /* fr(N) */
- erts_print(to, to_arg, "fr(%d)", loader_reg_index(ap[0]));
+ erts_print(to, to_arg, "fr(%d)", ap[0] / sizeof(FloatDef));
ap++;
break;
default:
@@ -1191,6 +1191,7 @@ dirty_send_message(Process *c_p, Eterm to, Eterm tag)
mp = erts_alloc_message_heap(rp, &rp_locks, 3, &hp, &ohp);
msg = TUPLE2(hp, tag, c_p->common.id);
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
erts_queue_proc_message(c_p, rp, rp_locks, mp, msg);
if (rp == real_c_p)
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index ee287243a4..aa61a2d7f9 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -1166,6 +1166,9 @@ void erts_dirty_process_main(ErtsSchedulerData *esdp)
reds_used = treds > INT_MAX ? INT_MAX : (int) treds;
}
+ if (c_p && ERTS_PROC_GET_PENDING_SUSPEND(c_p))
+ erts_proc_sig_handle_pending_suspend(c_p);
+
PROCESS_MAIN_CHK_LOCKS(c_p);
ERTS_UNREQ_PROC_MAIN_LOCK(c_p);
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
@@ -3058,12 +3061,14 @@ erts_gc_update_map_exact(Process* p, Eterm* reg, Uint live, Uint n, Eterm* new_p
Uint need;
flatmap_t *old_mp, *mp;
Eterm res;
+ Eterm* old_hp;
Eterm* hp;
Eterm* E;
Eterm* old_keys;
Eterm* old_vals;
Eterm new_key;
Eterm map;
+ int changed = 0;
n /= 2; /* Number of values to be updated */
ASSERT(n > 0);
@@ -3130,6 +3135,7 @@ erts_gc_update_map_exact(Process* p, Eterm* reg, Uint live, Uint n, Eterm* new_p
* Update map, keeping the old key tuple.
*/
+ old_hp = p->htop;
hp = p->htop;
E = p->stop;
@@ -3152,20 +3158,26 @@ erts_gc_update_map_exact(Process* p, Eterm* reg, Uint live, Uint n, Eterm* new_p
/* Not same keys */
*hp++ = *old_vals;
} else {
- GET_TERM(new_p[1], *hp);
- hp++;
- n--;
+ GET_TERM(new_p[1], *hp);
+ if(*hp != *old_vals) changed = 1;
+ hp++;
+ n--;
if (n == 0) {
- /*
- * All updates done. Copy remaining values
- * and return the result.
- */
- for (i++, old_vals++; i < num_old; i++) {
- *hp++ = *old_vals++;
- }
- ASSERT(hp == p->htop + need);
- p->htop = hp;
- return res;
+ /*
+ * All updates done. Copy remaining values
+ * if any changed or return the original one.
+ */
+ if(changed) {
+ for (i++, old_vals++; i < num_old; i++) {
+ *hp++ = *old_vals++;
+ }
+ ASSERT(hp == p->htop + need);
+ p->htop = hp;
+ return res;
+ } else {
+ p->htop = old_hp;
+ return map;
+ }
} else {
new_p += 2;
GET_TERM(*new_p, new_key);
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index e61199a8fd..50cbb37f3e 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -4245,21 +4245,55 @@ gen_make_fun2(LoaderState* stp, GenOpArg idx)
{
ErlFunEntry* fe;
GenOp* op;
+ Uint arity, num_free;
if (idx.val >= stp->num_lambdas) {
- stp->lambda_error = "missing or short chunk 'FunT'";
- fe = 0;
+ stp->lambda_error = "missing or short chunk 'FunT'";
+ fe = 0;
+ num_free = 0;
+ arity = 0;
} else {
- fe = stp->lambdas[idx.val].fe;
+ fe = stp->lambdas[idx.val].fe;
+ num_free = stp->lambdas[idx.val].num_free;
+ arity = fe->arity;
}
NEW_GENOP(stp, op);
- op->op = genop_i_make_fun_2;
- op->arity = 2;
- op->a[0].type = TAG_u;
- op->a[0].val = (BeamInstr) fe;
- op->a[1].type = TAG_u;
- op->a[1].val = stp->lambdas[idx.val].num_free;
+
+ /*
+ * It's possible this is called before init process is started,
+ * skip the optimisation in such case.
+ */
+ if (num_free == 0 && erts_init_process_id != ERTS_INVALID_PID) {
+ Uint lit;
+ Eterm* hp;
+ ErlFunThing* funp;
+
+ lit = new_literal(stp, &hp, ERL_FUN_SIZE);
+ funp = (ErlFunThing *) hp;
+ erts_refc_inc(&fe->refc, 2);
+ funp->thing_word = HEADER_FUN;
+ funp->next = NULL;
+ funp->fe = fe;
+ funp->num_free = 0;
+ funp->creator = erts_init_process_id;
+ funp->arity = arity;
+
+ op->op = genop_move_2;
+ op->arity = 2;
+ op->a[0].type = TAG_q;
+ op->a[0].val = lit;
+ op->a[1].type = TAG_x;
+ op->a[1].val = 0;
+ } else {
+ op->op = genop_i_make_fun_2;
+ op->arity = 2;
+ op->a[0].type = TAG_u;
+ op->a[0].val = (BeamInstr) fe;
+ op->a[1].type = TAG_u;
+ op->a[1].val = num_free;
+ }
+
op->next = NULL;
return op;
}
diff --git a/erts/emulator/beam/beam_ranges.c b/erts/emulator/beam/beam_ranges.c
index f0c9496341..9f3153724a 100644
--- a/erts/emulator/beam/beam_ranges.c
+++ b/erts/emulator/beam/beam_ranges.c
@@ -35,10 +35,8 @@ typedef struct {
/*
* Used for crash dumping of literals. The size of erts_dump_lit_areas is
- * always twice the number of active ranges (to allow for literals in both
- * current and old code).
+ * always at least the number of active ranges.
*/
-
ErtsLiteralArea** erts_dump_lit_areas;
Uint erts_dump_num_lit_areas;
@@ -180,8 +178,8 @@ erts_end_staging_ranges(int commit)
(erts_aint_t) (r[dst].modules +
r[dst].n / 2));
- if (r[dst].allocated * 2 > erts_dump_num_lit_areas) {
- erts_dump_num_lit_areas *= 2;
+ if (r[dst].allocated > erts_dump_num_lit_areas) {
+ erts_dump_num_lit_areas = r[dst].allocated * 2;
erts_dump_lit_areas = (ErtsLiteralArea **)
erts_realloc(ERTS_ALC_T_CRASH_DUMP,
(void *) erts_dump_lit_areas,
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index 4c288d2892..56ac072449 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -1364,13 +1364,14 @@ BIF_RETTYPE exit_signal_2(BIF_ALIST_2)
/* Handle flags common to both process_flag_2 and process_flag_3. */
-static BIF_RETTYPE process_flag_aux(Process *BIF_P,
- Process *rp,
- Eterm flag,
- Eterm val)
+static Eterm process_flag_aux(Process *c_p, int *redsp, Eterm flag, Eterm val)
{
Eterm old_value = NIL; /* shut up warning about use before set */
Sint i;
+
+ if (redsp)
+ *redsp = 1;
+
if (flag == am_save_calls) {
struct saved_calls *scb;
if (!is_small(val))
@@ -1390,30 +1391,89 @@ static BIF_RETTYPE process_flag_aux(Process *BIF_P,
}
#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);
+ if (c_p->flags & F_HIPE_MODE) {
+ ASSERT(!ERTS_PROC_GET_SAVED_CALLS_BUF(c_p));
+ scb = ERTS_PROC_SET_SUSPENDED_SAVED_CALLS_BUF(c_p, scb);
}
else
#endif
{
#ifdef HIPE
- ASSERT(!ERTS_PROC_GET_SUSPENDED_SAVED_CALLS_BUF(rp));
+ ASSERT(!ERTS_PROC_GET_SUSPENDED_SAVED_CALLS_BUF(c_p));
#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);
- }
+ scb = ERTS_PROC_SET_SAVED_CALLS_BUF(c_p, scb);
+
+ if (((scb && i == 0) || (!scb && i != 0))) {
+
+ /*
+ * Make sure we reschedule immediately so the
+ * change take effect at once.
+ */
+ if (!redsp) {
+ /* Executed via BIF call.. */
+ via_bif:
+
+ /* Adjust fcalls to match save calls setting... */
+ if (i == 0)
+ c_p->fcalls += CONTEXT_REDS; /* disabled it */
+ else
+ c_p->fcalls -= CONTEXT_REDS; /* enabled it */
+
+ ERTS_VBUMP_ALL_REDS(c_p);
+ }
+ else {
+ erts_aint32_t state;
+ /*
+ * Executed via signal handler. Try to figure
+ * out in what context we are executing...
+ */
+
+ state = erts_atomic32_read_nob(&c_p->state);
+ if (state & (ERTS_PSFLG_RUNNING_SYS
+ | ERTS_PSFLG_DIRTY_RUNNING_SYS
+ | ERTS_PSFLG_DIRTY_RUNNING)) {
+ /*
+ * We are either processing signals before
+ * being executed or executing dirty. That
+ * is, no need to adjust anything...
+ */
+ *redsp = 1;
+ }
+ else {
+ ErtsSchedulerData *esdp;
+ ASSERT(state & ERTS_PSFLG_RUNNING);
+
+ /*
+ * F_DELAY_GC is currently only set when
+ * we handle signals in state running via
+ * receive helper...
+ */
+
+ if (!(c_p->flags & F_DELAY_GC)) {
+ *redsp = 1;
+ goto via_bif;
+ }
+
+ /*
+ * Executing via receive helper...
+ *
+ * We utilize the virtual reds counter
+ * in order to get correct calculation
+ * of reductions consumed when scheduling
+ * out the process...
+ */
+
+ esdp = erts_get_scheduler_data();
+
+ if (i == 0)
+ esdp->virtual_reds += CONTEXT_REDS; /* disabled it */
+ else
+ esdp->virtual_reds -= CONTEXT_REDS; /* enabled it */
+
+ *redsp = -1;
+ }
+ }
+ }
}
if (!scb)
@@ -1423,11 +1483,12 @@ static BIF_RETTYPE process_flag_aux(Process *BIF_P,
erts_free(ERTS_ALC_T_CALLS_BUF, (void *) scb);
}
- BIF_RET(old_value);
+ ASSERT(is_immed(old_value));
+ return old_value;
}
error:
- BIF_ERROR(BIF_P, BADARG);
+ return am_badarg;
}
BIF_RETTYPE process_flag_2(BIF_ALIST_2)
@@ -1596,29 +1657,73 @@ BIF_RETTYPE process_flag_2(BIF_ALIST_2)
/* Fall through and try process_flag_aux() ... */
}
- BIF_RET(process_flag_aux(BIF_P, BIF_P, BIF_ARG_1, BIF_ARG_2));
+ old_value = process_flag_aux(BIF_P, NULL, BIF_ARG_1, BIF_ARG_2);
+ if (old_value != am_badarg)
+ BIF_RET(old_value);
error:
BIF_ERROR(BIF_P, BADARG);
}
-BIF_RETTYPE process_flag_3(BIF_ALIST_3)
+typedef struct {
+ Eterm flag;
+ Eterm value;
+ ErlOffHeap oh;
+ Eterm heap[1];
+} ErtsProcessFlag3Args;
+
+static Eterm
+exec_process_flag_3(Process *c_p, void *arg, int *redsp, ErlHeapFragment **bpp)
{
- Process *rp;
- Eterm res;
+ ErtsProcessFlag3Args *pf3a = arg;
+ Eterm res;
+
+ if (ERTS_PROC_IS_EXITING(c_p))
+ res = am_badarg;
+ else
+ res = process_flag_aux(c_p, redsp, pf3a->flag, pf3a->value);
+ erts_cleanup_offheap(&pf3a->oh);
+ erts_free(ERTS_ALC_T_PF3_ARGS, arg);
+ return res;
+}
+
+
+BIF_RETTYPE erts_internal_process_flag_3(BIF_ALIST_3)
+{
+ Eterm res, *hp;
+ ErlOffHeap *ohp;
+ ErtsProcessFlag3Args *pf3a;
+ Uint flag_sz, value_sz;
+
+ if (BIF_P->common.id == BIF_ARG_1) {
+ res = process_flag_aux(BIF_P, NULL, BIF_ARG_2, BIF_ARG_3);
+ BIF_RET(res);
+ }
+
+ if (is_not_internal_pid(BIF_ARG_1))
+ BIF_RET(am_badarg);
+
+ flag_sz = is_immed(BIF_ARG_2) ? 0 : size_object(BIF_ARG_2);
+ value_sz = is_immed(BIF_ARG_3) ? 0 : size_object(BIF_ARG_3);
+
+ pf3a = erts_alloc(ERTS_ALC_T_PF3_ARGS,
+ sizeof(ErtsProcessFlag3Args)
+ + sizeof(Eterm)*(flag_sz+value_sz-1));
+
+ ohp = &pf3a->oh;
+ ERTS_INIT_OFF_HEAP(&pf3a->oh);
- 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);
+ hp = &pf3a->heap[0];
- if (!rp)
- BIF_ERROR(BIF_P, BADARG);
+ pf3a->flag = copy_struct(BIF_ARG_2, flag_sz, &hp, ohp);
+ pf3a->value = copy_struct(BIF_ARG_3, value_sz, &hp, ohp);
- res = process_flag_aux(BIF_P, rp, BIF_ARG_2, BIF_ARG_3);
+ res = erts_proc_sig_send_rpc_request(BIF_P, BIF_ARG_1,
+ !0,
+ exec_process_flag_3,
+ (void *) pf3a);
- if (rp != BIF_P)
- erts_proc_unlock(rp, ERTS_PROC_LOCK_MAIN);
+ if (is_non_value(res))
+ BIF_RET(am_badarg);
return res;
}
@@ -1961,7 +2066,7 @@ do_send(Process *p, Eterm to, Eterm msg, Eterm *refp, ErtsSendContext *ctx)
if (p == rp)
rp_locks |= ERTS_PROC_LOCK_MAIN;
/* send to local process */
- erts_send_message(p, rp, &rp_locks, msg, 0);
+ erts_send_message(p, rp, &rp_locks, msg);
erts_proc_unlock(rp,
p == rp
? (rp_locks & ~ERTS_PROC_LOCK_MAIN)
diff --git a/erts/emulator/beam/bif.h b/erts/emulator/beam/bif.h
index a47339253e..cf9f61c0b8 100644
--- a/erts/emulator/beam/bif.h
+++ b/erts/emulator/beam/bif.h
@@ -295,6 +295,19 @@ do { \
(Ret) = THE_NON_VALUE; \
} while (0)
+#define ERTS_BIF_PREP_TRAP4(Ret, Trap, Proc, A0, A1, A2, A3) \
+do { \
+ Eterm* reg = erts_proc_sched_data((Proc))->x_reg_array; \
+ (Proc)->arity = 4; \
+ reg[0] = (Eterm) (A0); \
+ reg[1] = (Eterm) (A1); \
+ reg[2] = (Eterm) (A2); \
+ reg[3] = (Eterm) (A3); \
+ (Proc)->i = (BeamInstr*) ((Trap)->addressv[erts_active_code_ix()]); \
+ (Proc)->freason = TRAP; \
+ (Ret) = THE_NON_VALUE; \
+} while (0)
+
#define ERTS_BIF_PREP_TRAP3_NO_RET(Trap, Proc, A0, A1, A2)\
do { \
Eterm* reg = erts_proc_sched_data((Proc))->x_reg_array; \
@@ -343,6 +356,18 @@ do { \
return THE_NON_VALUE; \
} while(0)
+#define BIF_TRAP4(Trap_, p, A0, A1, A2, A3) do { \
+ Eterm* reg = erts_proc_sched_data((p))->x_reg_array; \
+ (p)->arity = 4; \
+ reg[0] = (A0); \
+ reg[1] = (A1); \
+ reg[2] = (A2); \
+ reg[3] = (A3); \
+ (p)->i = (BeamInstr*) ((Trap_)->addressv[erts_active_code_ix()]); \
+ (p)->freason = TRAP; \
+ return THE_NON_VALUE; \
+ } while(0)
+
#define BIF_TRAP_CODE_PTR_0(p, Code_) do { \
(p)->arity = 0; \
(p)->i = (BeamInstr*) (Code_); \
@@ -401,6 +426,12 @@ do { \
ERTS_BIF_PREP_TRAP3(RET, (TRP), (P), (A0), (A1), (A2)); \
} while (0)
+#define ERTS_BIF_PREP_YIELD4(RET, TRP, P, A0, A1, A2, A3) \
+do { \
+ ERTS_VBUMP_ALL_REDS((P)); \
+ ERTS_BIF_PREP_TRAP4(RET, (TRP), (P), (A0), (A1), (A2), (A3)); \
+} while (0)
+
#define ERTS_BIF_YIELD0(TRP, P) \
do { \
ERTS_VBUMP_ALL_REDS((P)); \
@@ -425,6 +456,12 @@ do { \
BIF_TRAP3((TRP), (P), (A0), (A1), (A2)); \
} while (0)
+#define ERTS_BIF_YIELD4(TRP, P, A0, A1, A2, A3) \
+do { \
+ ERTS_VBUMP_ALL_REDS((P)); \
+ BIF_TRAP4((TRP), (P), (A0), (A1), (A2), (A3)); \
+} while (0)
+
#define ERTS_BIF_PREP_EXITED(RET, PROC) \
do { \
KILL_CATCHES((PROC)); \
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index 33738dc20b..a770524221 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -125,7 +125,7 @@ bif erlang:pid_to_list/1
bif erlang:ports/0
bif erlang:pre_loaded/0
bif erlang:process_flag/2
-bif erlang:process_flag/3
+bif erts_internal:process_flag/3
bif erlang:process_info/1
bif erlang:process_info/2
bif erlang:processes/0
@@ -154,7 +154,6 @@ bif erlang:unregister/1
bif erlang:whereis/1
bif erlang:spawn_opt/1
bif erlang:setnode/2
-bif erlang:setnode/3
bif erlang:dist_get_stat/1
bif erlang:dist_ctrl_input_handler/2
bif erlang:dist_ctrl_put_data/2
@@ -191,6 +190,8 @@ bif erts_internal:scheduler_wall_time/1
bif erts_internal:dirty_process_handle_signals/1
+bif erts_internal:create_dist_channel/4
+
# inet_db support
bif erlang:port_set_data/2
bif erlang:port_get_data/1
@@ -204,9 +205,9 @@ bif erlang:seq_trace/2
bif erlang:seq_trace_info/1
bif erlang:seq_trace_print/1
bif erlang:seq_trace_print/2
-bif erlang:suspend_process/2
+bif erts_internal:suspend_process/2
bif erlang:resume_process/1
-bif erlang:process_display/2
+bif erts_internal:process_display/2
bif erlang:bump_reductions/1
@@ -341,7 +342,6 @@ bif ets:internal_request_all/0
bif ets:new/2
bif ets:delete/1
bif ets:delete/2
-bif ets:delete_all_objects/1
bif ets:delete_object/2
bif ets:first/1
bif ets:is_compiled_ms/1
@@ -372,7 +372,6 @@ bif ets:select_count/2
bif ets:select_reverse/1
bif ets:select_reverse/2
bif ets:select_reverse/3
-bif ets:select_delete/2
bif ets:select_replace/2
bif ets:match_spec_compile/1
bif ets:match_spec_run_r/3
@@ -630,7 +629,6 @@ bif maps:from_list/1
bif maps:is_key/2
bif maps:keys/1
bif maps:merge/2
-bif maps:new/0
bif maps:put/3
bif maps:remove/2
bif maps:update/3
@@ -697,3 +695,5 @@ bif erts_internal:gather_alloc_histograms/1
bif erts_internal:gather_carrier_info/1
ubif erlang:map_get/2
ubif erlang:is_map_key/2
+bif ets:internal_delete_all/2
+bif ets:internal_select_delete/2
diff --git a/erts/emulator/beam/bif_instrs.tab b/erts/emulator/beam/bif_instrs.tab
index 0f074280db..00854471a9 100644
--- a/erts/emulator/beam/bif_instrs.tab
+++ b/erts/emulator/beam/bif_instrs.tab
@@ -2,7 +2,7 @@
//
// %CopyrightBegin%
//
-// Copyright Ericsson AB 2017. All Rights Reserved.
+// Copyright Ericsson AB 2017-2018. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/big.c b/erts/emulator/beam/big.c
index c5cb268f09..84338769e0 100644
--- a/erts/emulator/beam/big.c
+++ b/erts/emulator/beam/big.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/big.h b/erts/emulator/beam/big.h
index 7556205063..a1ad75708c 100644
--- a/erts/emulator/beam/big.h
+++ b/erts/emulator/beam/big.h
@@ -42,7 +42,7 @@ typedef Uint16 ErtsHalfDigit;
#undef BIG_HAVE_DOUBLE_DIGIT
typedef Uint32 ErtsHalfDigit;
#else
-#error "can not determine machine size"
+#error "cannot determine machine size"
#endif
typedef Uint dsize_t; /* Vector size type */
diff --git a/erts/emulator/beam/binary.c b/erts/emulator/beam/binary.c
index d53f75c279..6a349764b2 100644
--- a/erts/emulator/beam/binary.c
+++ b/erts/emulator/beam/binary.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c
index 9ff52c92b8..81531f6cc8 100644
--- a/erts/emulator/beam/break.c
+++ b/erts/emulator/beam/break.c
@@ -108,6 +108,7 @@ process_killer(void)
erts_exit(0, "");
switch(j) {
case 'k':
+ ASSERT(erts_init_process_id != ERTS_INVALID_PID);
/* Send a 'kill' exit signal from init process */
erts_proc_sig_send_exit(NULL, erts_init_process_id,
rp->common.id, am_kill, NIL,
diff --git a/erts/emulator/beam/bs_instrs.tab b/erts/emulator/beam/bs_instrs.tab
index 94e0000c8b..61eb02a7a2 100644
--- a/erts/emulator/beam/bs_instrs.tab
+++ b/erts/emulator/beam/bs_instrs.tab
@@ -2,7 +2,7 @@
//
// %CopyrightBegin%
//
-// Copyright Ericsson AB 2017. All Rights Reserved.
+// Copyright Ericsson AB 2017-2018. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/code_ix.c b/erts/emulator/beam/code_ix.c
index 34e46f5f33..50352b4084 100644
--- a/erts/emulator/beam/code_ix.c
+++ b/erts/emulator/beam/code_ix.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2012-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2012-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/copy.c b/erts/emulator/beam/copy.c
index 7769a914db..e7bfd04b73 100644
--- a/erts/emulator/beam/copy.c
+++ b/erts/emulator/beam/copy.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index abb08413d0..db594a23a0 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -1200,21 +1200,8 @@ erts_dsig_send_group_leader(ErtsDSigData *dsdp, Eterm leader, Eterm remote)
#include <valgrind/valgrind.h>
#include <valgrind/memcheck.h>
-#ifndef HAVE_VALGRIND_PRINTF_XML
-#define VALGRIND_PRINTF_XML VALGRIND_PRINTF
-#endif
-
# define PURIFY_MSG(msg) \
- do { \
- char buf__[1]; size_t bufsz__ = sizeof(buf__); \
- if (erts_sys_explicit_8bit_getenv("VALGRIND_LOG_XML", buf__, &bufsz__) >= 0) { \
- VALGRIND_PRINTF_XML("<erlang_error_log>" \
- "%s, line %d: %s</erlang_error_log>\n", \
- __FILE__, __LINE__, msg); \
- } else { \
- VALGRIND_PRINTF("%s, line %d: %s", __FILE__, __LINE__, msg); \
- } \
- } while (0)
+ VALGRIND_PRINTF("%s, line %d: %s", __FILE__, __LINE__, msg)
#else
# define PURIFY_MSG(msg)
#endif
@@ -3144,60 +3131,60 @@ BIF_RETTYPE setnode_2(BIF_ALIST_2)
BIF_ERROR(BIF_P, BADARG);
}
-/**********************************************************************
- ** Allocate a dist entry, set node name install the connection handler
- ** setnode_3({name@host, Creation}, Cid, {Type, Version, Initial, IC, OC})
- ** Type = flag field, where the flags are specified in dist.h
- ** Version = distribution version, >= 1
- ** IC = in_cookie (ignored)
- ** OC = out_cookie (ignored)
- **
- ** Note that in distribution protocols above 1, the Initial parameter
- ** is always NIL and the cookies are always the atom '', cookies are not
- ** sent in the distribution messages but are only used in
- ** the handshake.
- **
- ***********************************************************************/
+/*
+ * erts_internal:create_dist_channel/4 is used by
+ * erlang:setnode/3.
+ */
+
+typedef struct {
+ DistEntry *dep;
+ Uint flags;
+ Uint version;
+} ErtsSetupConnDistCtrl;
-BIF_RETTYPE setnode_3(BIF_ALIST_3)
+static void
+setup_connection_epiloge_rwunlock(Process *c_p, DistEntry *dep,
+ Eterm ctrlr, Uint flags,
+ Uint version);
+
+static Eterm
+setup_connection_distctrl(Process *c_p, void *arg,
+ int *redsp, ErlHeapFragment **bpp);
+
+BIF_RETTYPE erts_internal_create_dist_channel_4(BIF_ALIST_4)
{
BIF_RETTYPE ret;
Uint flags;
- unsigned long version;
- Eterm ic, oc;
- Eterm *tp;
+ Uint version;
+ Eterm *hp, res_tag = THE_NON_VALUE, res = THE_NON_VALUE;
DistEntry *dep = NULL;
- ErtsProcLocks proc_unlock = 0;
- Process *proc;
+ int de_locked = 0;
Port *pp = NULL;
- Eterm notify_proc;
- erts_aint32_t qflgs;
/*
* Check and pick out arguments
*/
- if (!is_node_name_atom(BIF_ARG_1) ||
- !(is_internal_port(BIF_ARG_2)
- || is_internal_pid(BIF_ARG_2))
- || (erts_this_node->sysname == am_Noname)) {
- goto badarg;
- }
+ /* Node name... */
+ if (!is_node_name_atom(BIF_ARG_1))
+ goto badarg;
- if (!is_tuple(BIF_ARG_3))
- goto badarg;
- tp = tuple_val(BIF_ARG_3);
- if (*tp++ != make_arityval(4))
- goto badarg;
- if (!is_small(*tp))
- goto badarg;
- flags = unsigned_val(*tp++);
- if (!is_small(*tp) || (version = unsigned_val(*tp)) == 0)
- goto badarg;
- ic = *(++tp);
- oc = *(++tp);
- if (!is_atom(ic) || !is_atom(oc))
- goto badarg;
+ /* Distribution controller... */
+ if (!is_internal_port(BIF_ARG_2) && !is_internal_pid(BIF_ARG_2))
+ goto badarg;
+
+ /* Dist flags... */
+ if (!is_small(BIF_ARG_3))
+ goto badarg;
+ flags = unsigned_val(BIF_ARG_3);
+
+ /* Version... */
+ if (!is_small(BIF_ARG_4))
+ goto badarg;
+ version = unsigned_val(BIF_ARG_4);
+
+ if (version == 0)
+ goto badarg;
if (~flags & DFLAG_DIST_MANDATORY) {
erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
@@ -3228,74 +3215,79 @@ BIF_RETTYPE setnode_3(BIF_ALIST_3)
else if (!dep)
goto system_limit; /* Should never happen!!! */
+ erts_de_rlock(dep);
+ de_locked = -1;
+
+ if (dep->state == ERTS_DE_STATE_EXITING) {
+ /* Suspend on dist entry waiting for the exit to finish */
+ ErtsProcList *plp = erts_proclist_create(BIF_P);
+ plp->next = NULL;
+ erts_suspend(BIF_P, ERTS_PROC_LOCK_MAIN, NULL);
+ erts_mtx_lock(&dep->qlock);
+ erts_proclist_store_last(&dep->suspended, plp);
+ erts_mtx_unlock(&dep->qlock);
+ goto yield;
+ }
+
+ erts_de_runlock(dep);
+ de_locked = 0;
+
if (is_internal_pid(BIF_ARG_2)) {
if (BIF_P->common.id == BIF_ARG_2) {
- proc_unlock = 0;
- proc = BIF_P;
- }
- else {
- proc_unlock = ERTS_PROC_LOCK_MAIN;
- proc = erts_pid2proc_not_running(BIF_P, ERTS_PROC_LOCK_MAIN,
- BIF_ARG_2, proc_unlock);
- }
- erts_de_rwlock(dep);
-
- if (!proc)
- goto badarg;
- else if (proc == ERTS_PROC_LOCK_BUSY) {
- proc_unlock = 0;
- goto yield;
- }
+ ErtsSetupConnDistCtrl scdc;
- erts_proc_lock(proc, ERTS_PROC_LOCK_STATUS);
- proc_unlock |= ERTS_PROC_LOCK_STATUS;
+ scdc.dep = dep;
+ scdc.flags = flags;
+ scdc.version = version;
- if (ERTS_PROC_GET_DIST_ENTRY(proc)) {
- if (dep == ERTS_PROC_GET_DIST_ENTRY(proc)
- && (proc->flags & F_DISTRIBUTION)
- && dep->cid == BIF_ARG_2) {
- ERTS_BIF_PREP_RET(ret, erts_make_dhandle(BIF_P, dep));
- goto done;
- }
- goto badarg;
- }
+ res = setup_connection_distctrl(BIF_P, &scdc, NULL, NULL);
+ BUMP_REDS(BIF_P, 5);
+ dep = NULL;
- if (dep->state == ERTS_DE_STATE_EXITING) {
- /* Suspend on dist entry waiting for the exit to finish */
- ErtsProcList *plp = erts_proclist_create(BIF_P);
- plp->next = NULL;
- erts_suspend(BIF_P, ERTS_PROC_LOCK_MAIN, NULL);
- erts_mtx_lock(&dep->qlock);
- erts_proclist_store_last(&dep->suspended, plp);
- erts_mtx_unlock(&dep->qlock);
- goto yield;
- }
- if (dep->state != ERTS_DE_STATE_PENDING) {
- if (dep->state == ERTS_DE_STATE_IDLE)
- erts_set_dist_entry_pending(dep);
- else
+ if (res == am_badarg)
goto badarg;
+
+ ASSERT(is_internal_magic_ref(res));
+ res_tag = am_ok; /* Connection up */
}
+ else {
+ ErtsSetupConnDistCtrl *scdcp;
- if (is_not_nil(dep->cid))
- goto badarg;
+ scdcp = erts_alloc(ERTS_ALC_T_SETUP_CONN_ARG,
+ sizeof(ErtsSetupConnDistCtrl));
- proc->flags |= F_DISTRIBUTION;
- ERTS_PROC_SET_DIST_ENTRY(proc, dep);
+ scdcp->dep = dep;
+ scdcp->flags = flags;
+ scdcp->version = version;
- proc_unlock &= ~ERTS_PROC_LOCK_STATUS;
- erts_proc_unlock(proc, ERTS_PROC_LOCK_STATUS);
+ res = erts_proc_sig_send_rpc_request(BIF_P,
+ BIF_ARG_2,
+ !0,
+ setup_connection_distctrl,
+ (void *) scdcp);
+ if (is_non_value(res))
+ goto badarg;
+
+ dep = NULL;
- dep->send = NULL; /* Only for distr ports... */
+ ASSERT(is_internal_ordinary_ref(res));
+ res_tag = am_message; /* Caller need to wait for dhandle in message */
+ }
+ hp = HAlloc(BIF_P, 3);
}
else {
+ int new;
pp = erts_id2port_sflgs(BIF_ARG_2,
BIF_P,
ERTS_PROC_LOCK_MAIN,
ERTS_PORT_SFLGS_INVALID_LOOKUP);
erts_de_rwlock(dep);
+ de_locked = 1;
+
+ if (dep->state == ERTS_DE_STATE_EXITING)
+ goto badarg;
if (!pp || (erts_atomic32_read_nob(&pp->state)
& ERTS_PORT_SFLG_EXITING))
@@ -3304,65 +3296,108 @@ BIF_RETTYPE setnode_3(BIF_ALIST_3)
if ((pp->drv_ptr->flags & ERL_DRV_FLAG_SOFT_BUSY) == 0)
goto badarg;
- if (dep->cid == BIF_ARG_2 && pp->dist_entry == dep) {
- ERTS_BIF_PREP_RET(ret, erts_make_dhandle(BIF_P, dep));
- goto done; /* Already set */
- }
+ if (dep->cid == BIF_ARG_2 && pp->dist_entry == dep)
+ new = 0;
+ else {
+ if (dep->state != ERTS_DE_STATE_PENDING) {
+ if (dep->state == ERTS_DE_STATE_IDLE)
+ erts_set_dist_entry_pending(dep);
+ else
+ goto badarg;
+ }
- if (dep->state == ERTS_DE_STATE_EXITING) {
- /* Suspend on dist entry waiting for the exit to finish */
- ErtsProcList *plp = erts_proclist_create(BIF_P);
- plp->next = NULL;
- erts_suspend(BIF_P, ERTS_PROC_LOCK_MAIN, NULL);
- erts_mtx_lock(&dep->qlock);
- erts_proclist_store_last(&dep->suspended, plp);
- erts_mtx_unlock(&dep->qlock);
- goto yield;
- }
- if (dep->state != ERTS_DE_STATE_PENDING) {
- if (dep->state == ERTS_DE_STATE_IDLE)
- erts_set_dist_entry_pending(dep);
- else
+ if (pp->dist_entry || is_not_nil(dep->cid))
goto badarg;
- }
- if (pp->dist_entry || is_not_nil(dep->cid))
- goto badarg;
+ erts_atomic32_read_bor_nob(&pp->state, ERTS_PORT_SFLG_DISTRIBUTION);
- erts_atomic32_read_bor_nob(&pp->state, ERTS_PORT_SFLG_DISTRIBUTION);
+ pp->dist_entry = dep;
- pp->dist_entry = dep;
+ ASSERT(pp->drv_ptr->outputv || pp->drv_ptr->output);
- ASSERT(pp->drv_ptr->outputv || pp->drv_ptr->output);
+ dep->send = (pp->drv_ptr->outputv
+ ? dist_port_commandv
+ : dist_port_command);
+ ASSERT(dep->send);
- dep->send = (pp->drv_ptr->outputv
- ? dist_port_commandv
- : dist_port_command);
- ASSERT(dep->send);
+ /*
+ * Dist-ports do not use the "busy port message queue" functionality, but
+ * instead use "busy dist entry" functionality.
+ */
+ {
+ ErlDrvSizeT disable = ERL_DRV_BUSY_MSGQ_DISABLED;
+ erl_drv_busy_msgq_limits(ERTS_Port2ErlDrvPort(pp), &disable, NULL);
+ }
- /*
- * Dist-ports do not use the "busy port message queue" functionality, but
- * instead use "busy dist entry" functionality.
- */
- {
- ErlDrvSizeT disable = ERL_DRV_BUSY_MSGQ_DISABLED;
- erl_drv_busy_msgq_limits(ERTS_Port2ErlDrvPort(pp), &disable, NULL);
+ setup_connection_epiloge_rwunlock(BIF_P, dep, BIF_ARG_2, flags, version);
+ de_locked = 0;
+ new = !0;
}
+ hp = HAlloc(BIF_P, 3 + ERTS_MAGIC_REF_THING_SIZE);
+ res = erts_build_dhandle(&hp, &BIF_P->off_heap, dep);
+ res_tag = am_ok; /* Connection up */
+ if (new)
+ dep = NULL; /* inc of refc transferred to port (dist_entry field) */
+ }
+
+ ASSERT(is_value(res) && is_value(res_tag));
+
+ res = TUPLE2(hp, res_tag, res);
+
+ ERTS_BIF_PREP_RET(ret, res);
+
+ done:
+
+ if (dep && dep != erts_this_dist_entry) {
+ if (de_locked) {
+ if (de_locked > 0)
+ erts_de_rwunlock(dep);
+ else
+ erts_de_runlock(dep);
+ }
+ erts_deref_dist_entry(dep);
}
+ if (pp)
+ erts_port_release(pp);
+
+ return ret;
+
+ yield:
+ ERTS_BIF_PREP_YIELD4(ret,
+ bif_export[BIF_erts_internal_create_dist_channel_4],
+ BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3, BIF_ARG_4);
+ goto done;
+
+ badarg:
+ ERTS_BIF_PREP_RET(ret, am_badarg);
+ goto done;
+
+ system_limit:
+ ERTS_BIF_PREP_RET(ret, am_system_limit);
+ goto done;
+}
+
+static void
+setup_connection_epiloge_rwunlock(Process *c_p, DistEntry *dep,
+ Eterm ctrlr, Uint flags,
+ Uint version)
+{
+ Eterm notify_proc = NIL;
+ erts_aint32_t qflgs;
+
dep->version = version;
dep->creation = 0;
-#ifdef DEBUG
+ ASSERT(is_internal_port(ctrlr) || is_internal_pid(ctrlr));
ASSERT(erts_atomic_read_nob(&dep->qsize) == 0
|| (dep->state == ERTS_DE_STATE_PENDING));
-#endif
if (flags & DFLAG_DIST_HDR_ATOM_CACHE)
create_cache(dep);
- erts_set_dist_entry_connected(dep, BIF_ARG_2, flags);
+ erts_set_dist_entry_connected(dep, ctrlr, flags);
notify_proc = NIL;
if (erts_atomic_read_nob(&dep->qsize)) {
@@ -3381,50 +3416,100 @@ BIF_RETTYPE setnode_3(BIF_ALIST_3)
}
}
}
- erts_de_rwunlock(dep);
- if (is_internal_pid(notify_proc))
- notify_dist_data(BIF_P, notify_proc);
- ERTS_BIF_PREP_RET(ret, erts_make_dhandle(BIF_P, dep));
+ erts_de_rwunlock(dep);
- dep = NULL; /* inc of refc transferred to port (dist_entry field) */
+ if (is_internal_pid(notify_proc))
+ notify_dist_data(c_p, notify_proc);
inc_no_nodes();
- send_nodes_mon_msgs(BIF_P,
+ send_nodes_mon_msgs(c_p,
am_nodeup,
- BIF_ARG_1,
+ dep->sysname,
flags & DFLAG_PUBLISHED ? am_visible : am_hidden,
NIL);
- done:
+}
- if (dep && dep != erts_this_dist_entry) {
- erts_de_rwunlock(dep);
- erts_deref_dist_entry(dep);
+static Eterm
+setup_connection_distctrl(Process *c_p, void *arg, int *redsp, ErlHeapFragment **bpp)
+{
+ ErtsSetupConnDistCtrl *scdcp = (ErtsSetupConnDistCtrl *) arg;
+ DistEntry *dep = scdcp->dep;
+ int dep_locked = 0;
+ Eterm *hp;
+ erts_aint32_t state;
+
+ if (redsp)
+ *redsp = 1;
+
+ state = erts_atomic32_read_nob(&c_p->state);
+
+ if (state & ERTS_PSFLG_EXITING)
+ goto badarg;
+
+ erts_de_rwlock(dep);
+ dep_locked = !0;
+
+ if (dep->state == ERTS_DE_STATE_EXITING)
+ goto badarg;
+
+ if (ERTS_PROC_GET_DIST_ENTRY(c_p)) {
+ if (dep == ERTS_PROC_GET_DIST_ENTRY(c_p)
+ && (c_p->flags & F_DISTRIBUTION)
+ && dep->cid == c_p->common.id) {
+ goto connected;
+ }
+ goto badarg;
}
- if (pp)
- erts_port_release(pp);
+ if (dep->state != ERTS_DE_STATE_PENDING) {
+ if (dep->state == ERTS_DE_STATE_IDLE)
+ erts_set_dist_entry_pending(dep);
+ else
+ goto badarg;
+ }
- if (proc_unlock)
- erts_proc_unlock(proc, proc_unlock);
+ if (is_not_nil(dep->cid))
+ goto badarg;
- return ret;
+ c_p->flags |= F_DISTRIBUTION;
+ ERTS_PROC_SET_DIST_ENTRY(c_p, dep);
- yield:
- ERTS_BIF_PREP_YIELD3(ret, bif_export[BIF_setnode_3], BIF_P,
- BIF_ARG_1, BIF_ARG_2, BIF_ARG_3);
- goto done;
+ dep->send = NULL; /* Only for distr ports... */
- badarg:
- ERTS_BIF_PREP_ERROR(ret, BIF_P, BADARG);
- goto done;
+ if (redsp)
+ *redsp = 5;
- system_limit:
- ERTS_BIF_PREP_ERROR(ret, BIF_P, SYSTEM_LIMIT);
- goto done;
+ setup_connection_epiloge_rwunlock(c_p, dep, c_p->common.id,
+ scdcp->flags, scdcp->version);
+connected:
+
+ /* we take over previous inc in refc of dep */
+
+ if (!bpp) /* called directly... */
+ return erts_make_dhandle(c_p, dep);
+
+ erts_free(ERTS_ALC_T_SETUP_CONN_ARG, arg);
+
+ *bpp = new_message_buffer(ERTS_MAGIC_REF_THING_SIZE);
+ hp = (*bpp)->mem;
+ return erts_build_dhandle(&hp, &(*bpp)->off_heap, dep);
+
+badarg:
+
+ if (bpp) /* not called directly */
+ erts_free(ERTS_ALC_T_SETUP_CONN_ARG, arg);
+
+ if (dep_locked)
+ erts_de_rwunlock(dep);
+
+ erts_deref_dist_entry(dep);
+
+ return am_badarg;
}
+
BIF_RETTYPE erts_internal_get_dflags_0(BIF_ALIST_0)
{
return erts_dflags_record;
@@ -3593,6 +3678,7 @@ int erts_auto_connect(DistEntry* dep, Process *proc, ErtsProcLocks proc_locks)
dhandle = erts_build_dhandle(&hp, ohp, dep);
msg = TUPLE4(hp, am_auto_connect, dep->sysname, make_small(conn_id),
dhandle);
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
erts_queue_proc_message(proc, net_kernel, nk_locks, mp, msg);
erts_proc_unlock(net_kernel, nk_locks);
}
diff --git a/erts/emulator/beam/erl_afit_alloc.c b/erts/emulator/beam/erl_afit_alloc.c
index 23efe3bba4..38289ea78a 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2003-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c
index d99d2ea57b..36c46fd7aa 100644
--- a/erts/emulator/beam/erl_alloc.c
+++ b/erts/emulator/beam/erl_alloc.c
@@ -64,9 +64,6 @@
# error "Too many schedulers; cannot create that many pref alloc instances"
#endif
-#define ERTS_ALC_FIX_TYPE_IX(T) \
- (ERTS_ALC_T2N((T)) - ERTS_ALC_N_MIN_A_FIXED_SIZE)
-
#define ERTS_ALC_DEFAULT_MAX_THR_PREF ERTS_MAX_NO_OF_SCHEDULERS
#if defined(SMALL_MEMORY) || defined(PURIFY) || defined(VALGRIND)
@@ -114,7 +111,7 @@ typedef union {
char align_afa[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(AFAllctr_t))];
AOFFAllctr_t aoffa;
char align_aoffa[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(AOFFAllctr_t))];
-} ErtsAllocatorState_t;
+} ErtsAllocatorState_t erts_align_attribute(ERTS_CACHE_LINE_SIZE);
static ErtsAllocatorState_t std_alloc_state;
static ErtsAllocatorState_t ll_alloc_state;
@@ -156,20 +153,13 @@ ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(aireq,
ErtsAlcType_t erts_fix_core_allocator_ix;
-enum allctr_type {
- GOODFIT,
- BESTFIT,
- AFIT,
- FIRSTFIT
-};
-
struct au_init {
int enable;
int thr_spec;
int disable_allowed;
int thr_spec_allowed;
int carrier_migration_allowed;
- enum allctr_type atype;
+ ErtsAlcStrat_t astrat;
struct {
AllctrInit_t util;
GFAllctrInit_t gf;
@@ -219,7 +209,9 @@ typedef struct {
struct au_init test_alloc;
} erts_alc_hndl_args_init_t;
-#define ERTS_AU_INIT__ {0, 0, 1, 1, 1, GOODFIT, DEFAULT_ALLCTR_INIT, {1,1,1,1}}
+#define ERTS_AU_INIT__ {0, 0, 1, 1, 1, \
+ ERTS_ALC_S_GOODFIT, DEFAULT_ALLCTR_INIT, \
+ {1,1,1,1}}
#define SET_DEFAULT_ALLOC_OPTS(IP) \
do { \
@@ -233,7 +225,7 @@ set_default_sl_alloc_opts(struct au_init *ip)
SET_DEFAULT_ALLOC_OPTS(ip);
ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
ip->thr_spec = 1;
- ip->atype = GOODFIT;
+ ip->astrat = ERTS_ALC_S_GOODFIT;
ip->init.util.name_prefix = "sl_";
ip->init.util.alloc_no = ERTS_ALC_A_SHORT_LIVED;
#ifndef SMALL_MEMORY
@@ -252,7 +244,7 @@ set_default_std_alloc_opts(struct au_init *ip)
SET_DEFAULT_ALLOC_OPTS(ip);
ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
ip->thr_spec = 1;
- ip->atype = BESTFIT;
+ ip->astrat = ERTS_ALC_S_BESTFIT;
ip->init.util.name_prefix = "std_";
ip->init.util.alloc_no = ERTS_ALC_A_STANDARD;
#ifndef SMALL_MEMORY
@@ -270,7 +262,7 @@ set_default_ll_alloc_opts(struct au_init *ip)
SET_DEFAULT_ALLOC_OPTS(ip);
ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
ip->thr_spec = 0;
- ip->atype = BESTFIT;
+ ip->astrat = ERTS_ALC_S_BESTFIT;
ip->init.bf.ao = 1;
ip->init.util.ramv = 0;
ip->init.util.mmsbc = 0;
@@ -299,7 +291,7 @@ set_default_literal_alloc_opts(struct au_init *ip)
ip->disable_allowed = 0;
ip->thr_spec_allowed = 0;
ip->carrier_migration_allowed = 0;
- ip->atype = BESTFIT;
+ ip->astrat = ERTS_ALC_S_BESTFIT;
ip->init.bf.ao = 1;
ip->init.util.ramv = 0;
ip->init.util.mmsbc = 0;
@@ -349,7 +341,7 @@ set_default_exec_alloc_opts(struct au_init *ip)
ip->disable_allowed = 0;
ip->thr_spec_allowed = 0;
ip->carrier_migration_allowed = 0;
- ip->atype = BESTFIT;
+ ip->astrat = ERTS_ALC_S_BESTFIT;
ip->init.bf.ao = 1;
ip->init.util.ramv = 0;
ip->init.util.mmsbc = 0;
@@ -378,7 +370,7 @@ set_default_temp_alloc_opts(struct au_init *ip)
ip->thr_spec = 1;
ip->disable_allowed = 0;
ip->carrier_migration_allowed = 0;
- ip->atype = AFIT;
+ ip->astrat = ERTS_ALC_S_AFIT;
ip->init.util.name_prefix = "temp_";
ip->init.util.alloc_no = ERTS_ALC_A_TEMPORARY;
#ifndef SMALL_MEMORY
@@ -397,7 +389,7 @@ set_default_eheap_alloc_opts(struct au_init *ip)
SET_DEFAULT_ALLOC_OPTS(ip);
ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
ip->thr_spec = 1;
- ip->atype = GOODFIT;
+ ip->astrat = ERTS_ALC_S_GOODFIT;
ip->init.util.name_prefix = "eheap_";
ip->init.util.alloc_no = ERTS_ALC_A_EHEAP;
#ifndef SMALL_MEMORY
@@ -416,7 +408,7 @@ set_default_binary_alloc_opts(struct au_init *ip)
SET_DEFAULT_ALLOC_OPTS(ip);
ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
ip->thr_spec = 1;
- ip->atype = BESTFIT;
+ ip->astrat = ERTS_ALC_S_BESTFIT;
ip->init.util.name_prefix = "binary_";
ip->init.util.alloc_no = ERTS_ALC_A_BINARY;
#ifndef SMALL_MEMORY
@@ -435,7 +427,7 @@ set_default_ets_alloc_opts(struct au_init *ip)
SET_DEFAULT_ALLOC_OPTS(ip);
ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
ip->thr_spec = 1;
- ip->atype = BESTFIT;
+ ip->astrat = ERTS_ALC_S_BESTFIT;
ip->init.util.name_prefix = "ets_";
ip->init.util.alloc_no = ERTS_ALC_A_ETS;
#ifndef SMALL_MEMORY
@@ -453,7 +445,7 @@ set_default_driver_alloc_opts(struct au_init *ip)
SET_DEFAULT_ALLOC_OPTS(ip);
ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
ip->thr_spec = 1;
- ip->atype = BESTFIT;
+ ip->astrat = ERTS_ALC_S_BESTFIT;
ip->init.util.name_prefix = "driver_";
ip->init.util.alloc_no = ERTS_ALC_A_DRIVER;
#ifndef SMALL_MEMORY
@@ -473,7 +465,7 @@ set_default_fix_alloc_opts(struct au_init *ip,
SET_DEFAULT_ALLOC_OPTS(ip);
ip->enable = AU_ALLOC_DEFAULT_ENABLE(1);
ip->thr_spec = 1;
- ip->atype = BESTFIT;
+ ip->astrat = ERTS_ALC_S_BESTFIT;
ip->init.bf.ao = 1;
ip->init.util.name_prefix = "fix_";
ip->init.util.fix_type_size = fix_type_sizes;
@@ -493,7 +485,7 @@ set_default_test_alloc_opts(struct au_init *ip)
SET_DEFAULT_ALLOC_OPTS(ip);
ip->enable = 0; /* Disabled by default */
ip->thr_spec = -1 * erts_no_schedulers;
- ip->atype = FIRSTFIT;
+ ip->astrat = ERTS_ALC_S_FIRSTFIT;
ip->init.aoff.crr_order = FF_AOFF;
ip->init.aoff.blk_order = FF_BF;
ip->init.util.name_prefix = "test_";
@@ -552,8 +544,8 @@ start_au_allocator(ErtsAlcType_t alctr_n,
static void
refuse_af_strategy(struct au_init *init)
{
- if (init->atype == AFIT)
- init->atype = GOODFIT;
+ if (init->astrat == ERTS_ALC_S_AFIT)
+ init->astrat = ERTS_ALC_S_GOODFIT;
}
#ifdef HARD_DEBUG
@@ -576,7 +568,10 @@ static void adjust_fix_alloc_sizes(UWord extra_block_size)
for (i=0; i < tspec->size; i++) {
Allctr_t* allctr = tspec->allctr[i];
for (j=0; j < ERTS_ALC_NO_FIXED_SIZES; ++j) {
- allctr->fix[j].type_size += extra_block_size;
+ size_t size = allctr->fix[j].type_size;
+ size = MAX(size + extra_block_size,
+ sizeof(ErtsAllctrDDBlock_t));
+ allctr->fix[j].type_size = size;
}
}
}
@@ -584,8 +579,11 @@ static void adjust_fix_alloc_sizes(UWord extra_block_size)
{
Allctr_t* allctr = erts_allctrs_info[ERTS_ALC_A_FIXED_SIZE].extra;
for (j=0; j < ERTS_ALC_NO_FIXED_SIZES; ++j) {
- allctr->fix[j].type_size += extra_block_size;
- }
+ size_t size = allctr->fix[j].type_size;
+ size = MAX(size + extra_block_size,
+ sizeof(ErtsAllctrDDBlock_t));
+ allctr->fix[j].type_size = size;
+ }
}
}
}
@@ -597,7 +595,7 @@ strategy_support_carrier_migration(struct au_init *auip)
* Currently only aoff* and ageff* support carrier
* migration, i.e, type AOFIRSTFIT.
*/
- return auip->atype == FIRSTFIT;
+ return auip->astrat == ERTS_ALC_S_FIRSTFIT;
}
static ERTS_INLINE void
@@ -612,7 +610,7 @@ adjust_carrier_migration_support(struct au_init *auip)
*/
if (!strategy_support_carrier_migration(auip)) {
/* Default to aoffcbf */
- auip->atype = FIRSTFIT;
+ auip->astrat = ERTS_ALC_S_FIRSTFIT;
auip->init.aoff.crr_order = FF_AOFF;
auip->init.aoff.blk_order = FF_BF;
}
@@ -1018,7 +1016,7 @@ start_au_allocator(ErtsAlcType_t alctr_n,
int i;
int size = 1;
void *as0;
- enum allctr_type atype;
+ ErtsAlcStrat_t astrat;
ErtsAllocatorFunctions_t *af = &erts_allctrs[alctr_n];
ErtsAllocatorInfo_t *ai = &erts_allctrs_info[alctr_n];
ErtsAllocatorThrSpec_t *tspec = &erts_allctr_thr_spec[alctr_n];
@@ -1077,7 +1075,7 @@ start_au_allocator(ErtsAlcType_t alctr_n,
for (i = 0; i < size; i++) {
Allctr_t *as;
- atype = init->atype;
+ astrat = init->astrat;
if (!init->thr_spec)
as0 = state;
@@ -1094,8 +1092,8 @@ start_au_allocator(ErtsAlcType_t alctr_n,
if (i != 0)
init->init.util.ts = 0;
else {
- if (atype == AFIT)
- atype = GOODFIT;
+ if (astrat == ERTS_ALC_S_AFIT)
+ astrat = ERTS_ALC_S_GOODFIT;
init->init.util.ts = 1;
}
init->init.util.tspec = init->thr_spec + 1;
@@ -1109,25 +1107,26 @@ start_au_allocator(ErtsAlcType_t alctr_n,
(((char *) fix_lists) + fix_list_size));
}
+ init->init.util.alloc_strat = astrat;
init->init.util.ix = i;
- switch (atype) {
- case GOODFIT:
+ switch (astrat) {
+ case ERTS_ALC_S_GOODFIT:
as = erts_gfalc_start((GFAllctr_t *) as0,
&init->init.gf,
&init->init.util);
break;
- case BESTFIT:
+ case ERTS_ALC_S_BESTFIT:
as = erts_bfalc_start((BFAllctr_t *) as0,
&init->init.bf,
&init->init.util);
break;
- case AFIT:
+ case ERTS_ALC_S_AFIT:
as = erts_afalc_start((AFAllctr_t *) as0,
&init->init.af,
&init->init.util);
break;
- case FIRSTFIT:
+ case ERTS_ALC_S_FIRSTFIT:
as = erts_aoffalc_start((AOFFAllctr_t *) as0,
&init->init.aoff,
&init->init.util);
@@ -1363,51 +1362,59 @@ handle_au_arg(struct au_init *auip,
else if(has_prefix("as", sub_param)) {
char *alg = get_value(sub_param + 2, argv, ip);
if (sys_strcmp("bf", alg) == 0) {
- auip->atype = BESTFIT;
+ auip->astrat = ERTS_ALC_S_BESTFIT;
auip->init.bf.ao = 0;
}
else if (sys_strcmp("aobf", alg) == 0) {
- auip->atype = BESTFIT;
+ auip->astrat = ERTS_ALC_S_BESTFIT;
auip->init.bf.ao = 1;
}
else if (sys_strcmp("gf", alg) == 0) {
- auip->atype = GOODFIT;
+ auip->astrat = ERTS_ALC_S_GOODFIT;
}
else if (sys_strcmp("af", alg) == 0) {
- auip->atype = AFIT;
+ auip->astrat = ERTS_ALC_S_AFIT;
}
else if (sys_strcmp("aoff", alg) == 0) {
- auip->atype = FIRSTFIT;
+ auip->astrat = ERTS_ALC_S_FIRSTFIT;
auip->init.aoff.crr_order = FF_AOFF;
auip->init.aoff.blk_order = FF_AOFF;
}
else if (sys_strcmp("aoffcbf", alg) == 0) {
- auip->atype = FIRSTFIT;
+ auip->astrat = ERTS_ALC_S_FIRSTFIT;
auip->init.aoff.crr_order = FF_AOFF;
auip->init.aoff.blk_order = FF_BF;
}
else if (sys_strcmp("aoffcaobf", alg) == 0) {
- auip->atype = FIRSTFIT;
+ auip->astrat = ERTS_ALC_S_FIRSTFIT;
auip->init.aoff.crr_order = FF_AOFF;
auip->init.aoff.blk_order = FF_AOBF;
}
else if (sys_strcmp("ageffcaoff", alg) == 0) {
- auip->atype = FIRSTFIT;
+ auip->astrat = ERTS_ALC_S_FIRSTFIT;
auip->init.aoff.crr_order = FF_AGEFF;
auip->init.aoff.blk_order = FF_AOFF;
}
else if (sys_strcmp("ageffcbf", alg) == 0) {
- auip->atype = FIRSTFIT;
+ auip->astrat = ERTS_ALC_S_FIRSTFIT;
auip->init.aoff.crr_order = FF_AGEFF;
auip->init.aoff.blk_order = FF_BF;
}
else if (sys_strcmp("ageffcaobf", alg) == 0) {
- auip->atype = FIRSTFIT;
+ auip->astrat = ERTS_ALC_S_FIRSTFIT;
auip->init.aoff.crr_order = FF_AGEFF;
auip->init.aoff.blk_order = FF_AOBF;
}
else {
- bad_value(param, sub_param + 1, alg);
+ if (auip->init.util.alloc_no == ERTS_ALC_A_TEST
+ && sys_strcmp("chaosff", alg) == 0) {
+ auip->astrat = ERTS_ALC_S_FIRSTFIT;
+ auip->init.aoff.crr_order = FF_CHAOS;
+ auip->init.aoff.blk_order = FF_CHAOS;
+ }
+ else {
+ bad_value(param, sub_param + 1, alg);
+ }
}
if (!strategy_support_carrier_migration(auip))
auip->init.util.acul = 0;
@@ -2030,33 +2037,55 @@ erts_realloc_n_enomem(ErtsAlcType_t n, void *ptr, Uint size)
}
static ERTS_INLINE UWord
-alcu_size(ErtsAlcType_t ai, ErtsAlcUFixInfo_t *fi, int fisz)
+alcu_size(ErtsAlcType_t alloc_no, ErtsAlcUFixInfo_t *fi, int fisz)
{
- UWord res = 0;
+ UWord res;
+ int ai;
- ASSERT(erts_allctrs_info[ai].enabled);
- ASSERT(erts_allctrs_info[ai].alloc_util);
+ if (!erts_allctrs_info[alloc_no].thr_spec) {
+ AllctrSize_t size;
+ Allctr_t *allctr;
- if (!erts_allctrs_info[ai].thr_spec) {
- Allctr_t *allctr = erts_allctrs_info[ai].extra;
- AllctrSize_t asize;
- erts_alcu_current_size(allctr, &asize, fi, fisz);
- res += asize.blocks;
+ allctr = erts_allctrs_info[alloc_no].extra;
+ erts_alcu_current_size(allctr, &size, fi, fisz);
+
+ return size.blocks;
}
- else {
- ErtsAllocatorThrSpec_t *tspec = &erts_allctr_thr_spec[ai];
- int i;
- ASSERT(tspec->enabled);
+ res = 0;
- for (i = tspec->size - 1; i >= 0; i--) {
- Allctr_t *allctr = tspec->allctr[i];
- AllctrSize_t asize;
- if (allctr) {
- erts_alcu_current_size(allctr, &asize, fi, fisz);
- res += asize.blocks;
- }
- }
+ /* Thread-specific allocators can migrate carriers across types, so we have
+ * to visit every allocator type to gather information on blocks that were
+ * allocated by us. */
+ for (ai = ERTS_ALC_A_MIN; ai < ERTS_ALC_A_MAX; ai++) {
+ ErtsAllocatorThrSpec_t *tspec;
+ Allctr_t *allctr;
+ int i;
+
+ if (!erts_allctrs_info[ai].thr_spec) {
+ continue;
+ }
+
+ tspec = &erts_allctr_thr_spec[ai];
+ ASSERT(tspec->enabled);
+
+ for (i = tspec->size - 1; i >= 0; i--) {
+ allctr = tspec->allctr[i];
+
+ if (allctr) {
+ AllctrSize_t size;
+
+ if (ai == alloc_no) {
+ erts_alcu_current_size(allctr, &size, fi, fisz);
+ } else {
+ erts_alcu_foreign_size(allctr, alloc_no, &size);
+ }
+
+ ASSERT(((SWord)size.blocks) >= 0);
+
+ res += size.blocks;
+ }
+ }
}
return res;
@@ -2400,6 +2429,7 @@ erts_memory(fmtfn_t *print_to_p, void *print_to_arg, void *proc, Eterm earg)
}
if (want_tot_or_sys) {
+ ASSERT(size.total >= size.processes);
size.system = size.total - size.processes;
}
@@ -2821,20 +2851,20 @@ erts_allocator_options(void *proc)
Eterm as[4];
Eterm ts[4];
- as[l] = am_atom_put("e", 1);
+ as[l] = ERTS_MAKE_AM("e");
ts[l++] = am_true;
switch (a) {
case ERTS_ALC_A_SYSTEM:
- as[l] = am_atom_put("m", 1);
- ts[l++] = am_atom_put("libc", 4);
+ as[l] = ERTS_MAKE_AM("m");
+ ts[l++] = ERTS_MAKE_AM("libc");
if(sas.trim_threshold >= 0) {
- as[l] = am_atom_put("tt", 2);
+ as[l] = ERTS_MAKE_AM("tt");
ts[l++] = erts_bld_uint(hpp, szp,
(Uint) sas.trim_threshold);
}
if(sas.top_pad >= 0) {
- as[l] = am_atom_put("tp", 2);
+ as[l] = ERTS_MAKE_AM("tp");
ts[l++] = erts_bld_uint(hpp, szp, (Uint) sas.top_pad);
}
break;
@@ -2848,7 +2878,7 @@ erts_allocator_options(void *proc)
}
else {
- Eterm atom = am_atom_put("e", 1);
+ Eterm atom = ERTS_MAKE_AM("e");
Eterm term = am_false;
tmp = erts_bld_2tup_list(hpp, szp, 1, &atom, &term);
}
@@ -2859,12 +2889,12 @@ erts_allocator_options(void *proc)
#if HAVE_ERTS_MSEG
if (use_mseg) {
- atoms[length] = am_atom_put("mseg_alloc", 10);
+ atoms[length] = ERTS_MAKE_AM("mseg_alloc");
terms[length++] = erts_mseg_info_options(0, NULL, NULL, hpp, szp);
}
#endif
- atoms[length] = am_atom_put("alloc_util", 10);
+ atoms[length] = ERTS_MAKE_AM("alloc_util");
terms[length++] = erts_alcu_au_info_options(NULL, NULL, hpp, szp);
#if HAVE_ERTS_MMAP
@@ -2874,17 +2904,15 @@ erts_allocator_options(void *proc)
#endif
{
Eterm o[1], v[1];
- o[0] = am_atom_put("t", 1);
+ o[0] = ERTS_MAKE_AM("t");
v[0] = erts_mtrace_enabled ? am_true : am_false;
- atoms[length] = am_atom_put("instr", 5);
+ atoms[length] = ERTS_MAKE_AM("instr");
terms[length++] = erts_bld_2tup_list(hpp, szp, 1, o, v);
}
- atoms[length] = am_atom_put("lock_physical_memory", 20);
- terms[length++] = (lock_all_physical_memory
- ? am_atom_put("all", 3)
- : am_atom_put("no", 2));
+ atoms[length] = ERTS_MAKE_AM("lock_physical_memory");
+ terms[length++] = (lock_all_physical_memory ? am_all : am_no);
settings = erts_bld_2tup_list(hpp, szp, length, atoms, terms);
@@ -2899,10 +2927,10 @@ erts_allocator_options(void *proc)
#if HAVE_ERTS_MSEG
if (use_mseg)
- terms[length++] = am_atom_put("mseg_alloc", 10);
+ terms[length++] = ERTS_MAKE_AM("mseg_alloc");
#endif
#if ERTS_HAVE_ERTS_SYS_ALIGNED_ALLOC
- terms[length++] = am_atom_put("sys_aligned_alloc", 17);
+ terms[length++] = ERTS_MAKE_AM("sys_aligned_alloc");
#endif
#if defined(ARCH_64) && defined(ERTS_HAVE_OS_PHYSICAL_MEMORY_RESERVATION)
terms[length++] = ERTS_MAKE_AM("literal_mmap");
@@ -2911,7 +2939,7 @@ erts_allocator_options(void *proc)
#if defined(__GLIBC__)
{
- Eterm AM_glibc = am_atom_put("glibc", 5);
+ Eterm AM_glibc = ERTS_MAKE_AM("glibc");
Eterm version;
version = erts_bld_cons(hpp,
@@ -3461,29 +3489,29 @@ UWord erts_alc_test(UWord op, UWord a1, UWord a2, UWord a3)
switch (op) {
case 0xf00:
if (((Allctr_t *) a1)->thread_safe)
- return (UWord) erts_alcu_alloc_ts(ERTS_ALC_T_UNDEF,
+ return (UWord) erts_alcu_alloc_ts(ERTS_ALC_T_TEST,
(void *) a1,
(Uint) a2);
else
- return (UWord) erts_alcu_alloc(ERTS_ALC_T_UNDEF,
+ return (UWord) erts_alcu_alloc(ERTS_ALC_T_TEST,
(void *) a1,
(Uint) a2);
case 0xf01:
if (((Allctr_t *) a1)->thread_safe)
- return (UWord) erts_alcu_realloc_ts(ERTS_ALC_T_UNDEF,
+ return (UWord) erts_alcu_realloc_ts(ERTS_ALC_T_TEST,
(void *) a1,
(void *) a2,
(Uint) a3);
else
- return (UWord) erts_alcu_realloc(ERTS_ALC_T_UNDEF,
+ return (UWord) erts_alcu_realloc(ERTS_ALC_T_TEST,
(void *) a1,
(void *) a2,
(Uint) a3);
case 0xf02:
if (((Allctr_t *) a1)->thread_safe)
- erts_alcu_free_ts(ERTS_ALC_T_UNDEF, (void *) a1, (void *) a2);
+ erts_alcu_free_ts(ERTS_ALC_T_TEST, (void *) a1, (void *) a2);
else
- erts_alcu_free(ERTS_ALC_T_UNDEF, (void *) a1, (void *) a2);
+ erts_alcu_free(ERTS_ALC_T_TEST, (void *) a1, (void *) a2);
return 0;
case 0xf03: {
Allctr_t *allctr;
@@ -3491,8 +3519,10 @@ UWord erts_alc_test(UWord op, UWord a1, UWord a2, UWord a3)
SET_DEFAULT_ALLOC_OPTS(&init);
init.enable = 1;
- init.atype = GOODFIT;
+ init.astrat = ERTS_ALC_S_GOODFIT;
init.init.util.name_prefix = (char *) a1;
+ init.init.util.alloc_no = ERTS_ALC_A_TEST;
+ init.init.util.alloc_strat = init.astrat;
init.init.util.ts = 1;
if ((char **) a3) {
char **argv = (char **) a3;
@@ -3506,31 +3536,31 @@ UWord erts_alc_test(UWord op, UWord a1, UWord a2, UWord a3)
}
}
- switch (init.atype) {
- case GOODFIT:
+ switch (init.astrat) {
+ case ERTS_ALC_S_GOODFIT:
allctr = erts_gfalc_start((GFAllctr_t *)
- erts_alloc(ERTS_ALC_T_UNDEF,
+ erts_alloc(ERTS_ALC_T_TEST,
sizeof(GFAllctr_t)),
&init.init.gf,
&init.init.util);
break;
- case BESTFIT:
+ case ERTS_ALC_S_BESTFIT:
allctr = erts_bfalc_start((BFAllctr_t *)
- erts_alloc(ERTS_ALC_T_UNDEF,
+ erts_alloc(ERTS_ALC_T_TEST,
sizeof(BFAllctr_t)),
&init.init.bf,
&init.init.util);
break;
- case AFIT:
+ case ERTS_ALC_S_AFIT:
allctr = erts_afalc_start((AFAllctr_t *)
- erts_alloc(ERTS_ALC_T_UNDEF,
+ erts_alloc(ERTS_ALC_T_TEST,
sizeof(AFAllctr_t)),
&init.init.af,
&init.init.util);
break;
- case FIRSTFIT:
+ case ERTS_ALC_S_FIRSTFIT:
allctr = erts_aoffalc_start((AOFFAllctr_t *)
- erts_alloc(ERTS_ALC_T_UNDEF,
+ erts_alloc(ERTS_ALC_T_TEST,
sizeof(AOFFAllctr_t)),
&init.init.aoff,
&init.init.util);
@@ -3546,7 +3576,7 @@ UWord erts_alc_test(UWord op, UWord a1, UWord a2, UWord a3)
}
case 0xf04:
erts_alcu_stop((Allctr_t *) a1);
- erts_free(ERTS_ALC_T_UNDEF, (void *) a1);
+ erts_free(ERTS_ALC_T_TEST, (void *) a1);
break;
case 0xf05: return (UWord) 1;
case 0xf06: return (UWord) ((Allctr_t *) a1)->thread_safe;
@@ -3556,7 +3586,7 @@ UWord erts_alc_test(UWord op, UWord a1, UWord a2, UWord a3)
case 0xf07: return (UWord) ((Allctr_t *) a1)->thread_safe;
#endif
case 0xf08: {
- ethr_mutex *mtx = erts_alloc(ERTS_ALC_T_UNDEF, sizeof(ethr_mutex));
+ ethr_mutex *mtx = erts_alloc(ERTS_ALC_T_TEST, sizeof(ethr_mutex));
if (ethr_mutex_init(mtx) != 0)
ERTS_ALC_TEST_ABORT;
return (UWord) mtx;
@@ -3565,7 +3595,7 @@ UWord erts_alc_test(UWord op, UWord a1, UWord a2, UWord a3)
ethr_mutex *mtx = (ethr_mutex *) a1;
if (ethr_mutex_destroy(mtx) != 0)
ERTS_ALC_TEST_ABORT;
- erts_free(ERTS_ALC_T_UNDEF, (void *) mtx);
+ erts_free(ERTS_ALC_T_TEST, (void *) mtx);
break;
}
case 0xf0a:
@@ -3575,7 +3605,7 @@ UWord erts_alc_test(UWord op, UWord a1, UWord a2, UWord a3)
ethr_mutex_unlock((ethr_mutex *) a1);
break;
case 0xf0c: {
- ethr_cond *cnd = erts_alloc(ERTS_ALC_T_UNDEF, sizeof(ethr_cond));
+ ethr_cond *cnd = erts_alloc(ERTS_ALC_T_TEST, sizeof(ethr_cond));
if (ethr_cond_init(cnd) != 0)
ERTS_ALC_TEST_ABORT;
return (UWord) cnd;
@@ -3584,7 +3614,7 @@ UWord erts_alc_test(UWord op, UWord a1, UWord a2, UWord a3)
ethr_cond *cnd = (ethr_cond *) a1;
if (ethr_cond_destroy(cnd) != 0)
ERTS_ALC_TEST_ABORT;
- erts_free(ERTS_ALC_T_UNDEF, (void *) cnd);
+ erts_free(ERTS_ALC_T_TEST, (void *) cnd);
break;
}
case 0xf0e:
@@ -3598,7 +3628,7 @@ UWord erts_alc_test(UWord op, UWord a1, UWord a2, UWord a3)
break;
}
case 0xf10: {
- ethr_tid *tid = erts_alloc(ERTS_ALC_T_UNDEF, sizeof(ethr_tid));
+ ethr_tid *tid = erts_alloc(ERTS_ALC_T_TEST, sizeof(ethr_tid));
if (ethr_thr_create(tid,
(void * (*)(void *)) a1,
(void *) a2,
@@ -3610,7 +3640,7 @@ UWord erts_alc_test(UWord op, UWord a1, UWord a2, UWord a3)
ethr_tid *tid = (ethr_tid *) a1;
if (ethr_thr_join(*tid, NULL) != 0)
ERTS_ALC_TEST_ABORT;
- erts_free(ERTS_ALC_T_UNDEF, (void *) tid);
+ erts_free(ERTS_ALC_T_TEST, (void *) tid);
break;
}
case 0xf12:
@@ -3962,9 +3992,10 @@ check_memory_fence(void *ptr, Uint *size, ErtsAlcType_t n, int func)
static ErtsAllocatorFunctions_t real_allctrs[ERTS_ALC_A_MAX+1];
static void *
-debug_alloc(ErtsAlcType_t n, void *extra, Uint size)
+debug_alloc(ErtsAlcType_t type, void *extra, Uint size)
{
ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra;
+ ErtsAlcType_t n;
Uint dsize;
void *res;
@@ -3972,9 +4003,11 @@ debug_alloc(ErtsAlcType_t n, void *extra, Uint size)
erts_hdbg_chk_blks();
#endif
+ n = ERTS_ALC_T2N(type);
+
ASSERT(ERTS_ALC_N_MIN <= n && n <= ERTS_ALC_N_MAX);
dsize = size + FENCE_SZ;
- res = (*real_af->alloc)(n, real_af->extra, dsize);
+ res = (*real_af->alloc)(type, real_af->extra, dsize);
res = set_memory_fence(res, size, n);
@@ -3988,14 +4021,17 @@ debug_alloc(ErtsAlcType_t n, void *extra, Uint size)
static void *
-debug_realloc(ErtsAlcType_t n, void *extra, void *ptr, Uint size)
+debug_realloc(ErtsAlcType_t type, void *extra, void *ptr, Uint size)
{
ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra;
+ ErtsAlcType_t n;
Uint dsize;
Uint old_size;
void *dptr;
void *res;
+ n = ERTS_ALC_T2N(type);
+
ASSERT(ERTS_ALC_N_MIN <= n && n <= ERTS_ALC_N_MAX);
dsize = size + FENCE_SZ;
@@ -4010,7 +4046,7 @@ debug_realloc(ErtsAlcType_t n, void *extra, void *ptr, Uint size)
0xf,
sizeof(Uint) + old_size - size);
- res = (*real_af->realloc)(n, real_af->extra, dptr, dsize);
+ res = (*real_af->realloc)(type, real_af->extra, dptr, dsize);
res = set_memory_fence(res, size, n);
@@ -4023,12 +4059,16 @@ debug_realloc(ErtsAlcType_t n, void *extra, void *ptr, Uint size)
}
static void
-debug_free(ErtsAlcType_t n, void *extra, void *ptr)
+debug_free(ErtsAlcType_t type, void *extra, void *ptr)
{
ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra;
+ ErtsAlcType_t n;
void *dptr;
Uint size;
- int free_pattern = n;
+ int free_pattern;
+
+ n = ERTS_ALC_T2N(type);
+ free_pattern = n;
ASSERT(ERTS_ALC_N_MIN <= n && n <= ERTS_ALC_N_MAX);
@@ -4043,7 +4083,7 @@ debug_free(ErtsAlcType_t n, void *extra, void *ptr)
#endif
sys_memset((void *) dptr, free_pattern, size + FENCE_SZ);
- (*real_af->free)(n, real_af->extra, dptr);
+ (*real_af->free)(type, real_af->extra, dptr);
#ifdef PRINT_OPS
fprintf(stderr, "free(%s, 0x%lx)\r\n", ERTS_ALC_N2TD(n), (Uint) ptr);
diff --git a/erts/emulator/beam/erl_alloc.h b/erts/emulator/beam/erl_alloc.h
index 578a3717d9..c13cf3f5b0 100644
--- a/erts/emulator/beam/erl_alloc.h
+++ b/erts/emulator/beam/erl_alloc.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2002-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,10 +26,23 @@
#define ERL_THR_PROGRESS_TSD_TYPE_ONLY
#include "erl_thr_progress.h"
#undef ERL_THR_PROGRESS_TSD_TYPE_ONLY
-#include "erl_alloc_util.h"
#include "erl_threads.h"
#include "erl_mmap.h"
+typedef enum {
+ ERTS_ALC_S_INVALID = 0,
+
+ ERTS_ALC_S_GOODFIT,
+ ERTS_ALC_S_BESTFIT,
+ ERTS_ALC_S_AFIT,
+ ERTS_ALC_S_FIRSTFIT,
+
+ ERTS_ALC_S_MIN = ERTS_ALC_S_GOODFIT,
+ ERTS_ALC_S_MAX = ERTS_ALC_S_FIRSTFIT
+} ErtsAlcStrat_t;
+
+#include "erl_alloc_util.h"
+
#ifdef DEBUG
# undef ERTS_ALC_WANT_INLINE
# define ERTS_ALC_WANT_INLINE 0
@@ -52,6 +65,14 @@
#define ERTS_ALC_NO_FIXED_SIZES \
(ERTS_ALC_N_MAX_A_FIXED_SIZE - ERTS_ALC_N_MIN_A_FIXED_SIZE + 1)
+#define ERTS_ALC_IS_FIX_TYPE(T) \
+ (ERTS_ALC_T2N(T) >= ERTS_ALC_N_MIN_A_FIXED_SIZE && \
+ ERTS_ALC_T2N(T) <= ERTS_ALC_N_MAX_A_FIXED_SIZE)
+
+#define ERTS_ALC_FIX_TYPE_IX(T) \
+ (ASSERT(ERTS_ALC_IS_FIX_TYPE(T)), \
+ ERTS_ALC_T2N((T)) - ERTS_ALC_N_MIN_A_FIXED_SIZE)
+
void erts_sys_alloc_init(void);
void *erts_sys_alloc(ErtsAlcType_t, void *, Uint);
void *erts_sys_realloc(ErtsAlcType_t, void *, void *, Uint);
@@ -228,7 +249,7 @@ 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),
+ type,
erts_allctrs[ERTS_ALC_T2A(type)].extra,
size);
if (!res)
@@ -243,7 +264,7 @@ void *erts_realloc(ErtsAlcType_t type, void *ptr, Uint size)
void *res;
ERTS_MSACC_PUSH_AND_SET_STATE_X(ERTS_MSACC_STATE_ALLOC);
res = (*erts_allctrs[ERTS_ALC_T2A(type)].realloc)(
- ERTS_ALC_T2N(type),
+ type,
erts_allctrs[ERTS_ALC_T2A(type)].extra,
ptr,
size);
@@ -258,7 +279,7 @@ void erts_free(ErtsAlcType_t type, void *ptr)
{
ERTS_MSACC_PUSH_AND_SET_STATE_X(ERTS_MSACC_STATE_ALLOC);
(*erts_allctrs[ERTS_ALC_T2A(type)].free)(
- ERTS_ALC_T2N(type),
+ type,
erts_allctrs[ERTS_ALC_T2A(type)].extra,
ptr);
ERTS_MSACC_POP_STATE_X();
@@ -271,7 +292,7 @@ void *erts_alloc_fnf(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),
+ type,
erts_allctrs[ERTS_ALC_T2A(type)].extra,
size);
ERTS_MSACC_POP_STATE_X();
@@ -285,7 +306,7 @@ void *erts_realloc_fnf(ErtsAlcType_t type, void *ptr, Uint size)
void *res;
ERTS_MSACC_PUSH_AND_SET_STATE_X(ERTS_MSACC_STATE_ALLOC);
res = (*erts_allctrs[ERTS_ALC_T2A(type)].realloc)(
- ERTS_ALC_T2N(type),
+ type,
erts_allctrs[ERTS_ALC_T2A(type)].extra,
ptr,
size);
diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types
index 4a6a19b210..f1e99820af 100644
--- a/erts/emulator/beam/erl_alloc.types
+++ b/erts/emulator/beam/erl_alloc.types
@@ -30,10 +30,10 @@
# name space).
# * Types, allocators, classes, and descriptions have different name
# spaces.
-# * The type, allocator, and class names INVALID are reserved and can
-# not be used.
+# * The type, allocator, and class names INVALID are reserved and
+# cannot be used.
# * The descriptions invalid_allocator, invalid_class, and invalid_type
-# are reserved and can not be used.
+# are reserved and cannot be used.
# * Declarations can be done conditionally by use of a
# +if <boolean_variable>
#
@@ -118,9 +118,6 @@ type PORT DRIVER SYSTEM port
type ATOM LONG_LIVED ATOM atom_entry
type MODULE LONG_LIVED CODE module_entry
type REG_PROC STANDARD PROCESSES reg_proc
-type LINK_LH STANDARD PROCESSES link_lh
-type SUSPEND_MON STANDARD PROCESSES suspend_monitor
-type PEND_SUSPEND SHORT_LIVED PROCESSES pending_suspend
type PROC_LIST SHORT_LIVED PROCESSES proc_list
type SAVED_ESTACK SHORT_LIVED PROCESSES saved_estack
type FUN_ENTRY LONG_LIVED CODE fun_entry
@@ -133,7 +130,6 @@ type TMP_HEAP TEMPORARY PROCESSES tmp_heap
type MSG_REF FIXED_SIZE PROCESSES msg_ref
type MSG EHEAP PROCESSES message
type MSGQ_CHNG SHORT_LIVED PROCESSES messages_queue_change
-type MSG_ROOTS TEMPORARY PROCESSES msg_roots
type ROOTSET TEMPORARY PROCESSES root_set
type LOADER_TMP TEMPORARY CODE loader_tmp
type PREPARED_CODE SHORT_LIVED CODE prepared_code
@@ -178,7 +174,6 @@ type BPD STANDARD SYSTEM bpd
type LINEBUF STANDARD SYSTEM line_buf
type IOQ STANDARD SYSTEM io_queue
type BITS_BUF STANDARD SYSTEM bits_buf
-type TMP_DIST_BUF TEMPORARY SYSTEM tmp_dist_buf
type ASYNC_DATA LONG_LIVED SYSTEM internal_async_data
type ESTACK TEMPORARY SYSTEM estack
type DB_TABLE ETS ETS db_tab
@@ -191,7 +186,6 @@ type DB_MC_STK TEMPORARY ETS db_mc_stack
type DB_MS_RUN_HEAP SHORT_LIVED ETS db_match_spec_run_heap
type DB_MS_CMPL_HEAP TEMPORARY ETS db_match_spec_cmpl_heap
type DB_SEG ETS ETS db_segment
-type DB_SEG_TAB ETS ETS db_segment_tab
type DB_STK ETS ETS db_stack
type DB_TRANS_TAB ETS ETS db_trans_tab
type DB_SEL_LIST ETS ETS db_select_list
@@ -200,7 +194,6 @@ type DB_DMC_ERR_INFO ETS ETS db_dmc_error_info
type DB_TERM ETS ETS db_term
type DB_PROC_CLEANUP SHORT_LIVED ETS db_proc_cleanup_state
type ETS_ALL_REQ SHORT_LIVED ETS ets_all_request
-type INSTR_INFO LONG_LIVED SYSTEM instr_info
type LOGGER_DSBUF TEMPORARY SYSTEM logger_dsbuf
type TMP_DSBUF TEMPORARY SYSTEM tmp_dsbuf
type INFO_DSBUF SYSTEM SYSTEM info_dsbuf
@@ -215,7 +208,6 @@ type PT_HNDL_LIST SHORT_LIVED SYSTEM port_task_handle_list
type MISC_OP_LIST SHORT_LIVED SYSTEM misc_op_list
type PORT_NAMES SHORT_LIVED SYSTEM port_names
type PORT_DATA_LOCK DRIVER SYSTEM port_data_lock
-type NODES_MON STANDARD PROCESSES nodes_monitor
type PTAB_LIST_DEL SHORT_LIVED PROCESSES ptab_list_deleted_el
type PTAB_LIST_CNKI SHORT_LIVED PROCESSES ptab_list_chunk_info
type PTAB_LIST_PIDS SHORT_LIVED PROCESSES ptab_list_pids
@@ -238,10 +230,8 @@ 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 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
type CODE_IX_LOCK_Q SHORT_LIVED SYSTEM code_ix_lock_q
-type PROC_INTERVAL LONG_LIVED SYSTEM process_interval
type BUSY_CALLER_TAB SHORT_LIVED SYSTEM busy_caller_table
type BUSY_CALLER SHORT_LIVED SYSTEM busy_caller
type PROC_SYS_TSK SHORT_LIVED PROCESSES proc_sys_task
@@ -250,8 +240,6 @@ 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
-type DIRTY_START STANDARD PROCESSES dirty_start
type DIRTY_SL SHORT_LIVED SYSTEM dirty_short_lived
type MREF_NSCHED_ENT FIXED_SIZE SYSTEM nsched_magic_ref_entry
type MREF_ENT STANDARD SYSTEM magic_ref_entry
@@ -259,7 +247,6 @@ type MREF_TAB_BKTS STANDARD SYSTEM magic_ref_table_buckets
type MREF_TAB LONG_LIVED SYSTEM magic_ref_table
type MINDIRECTION FIXED_SIZE SYSTEM magic_indirection
type BINARY_FIND SHORT_LIVED PROCESSES binary_find
-type OPEN_PORT_ENV TEMPORARY SYSTEM open_port_env
type CRASH_DUMP STANDARD SYSTEM crash_dump
type DIST_TRANSCODE SHORT_LIVED SYSTEM dist_transcode_context
@@ -273,10 +260,8 @@ type THR_Q_LL LONG_LIVED SYSTEM long_lived_thr_queue
type ASYNC SHORT_LIVED SYSTEM async
type ZLIB STANDARD SYSTEM zlib
-type PORT_LOCK STANDARD SYSTEM port_lock
type DRIVER_LOCK STANDARD SYSTEM driver_lock
type XPORTS_LIST SHORT_LIVED SYSTEM extra_port_list
-type PROC_LCK_WTR LONG_LIVED SYSTEM proc_lock_waiter
type RUNQ_BLNS LONG_LIVED SYSTEM run_queue_balancing
type THR_PRGR_IDATA LONG_LIVED SYSTEM thr_prgr_internal_data
type THR_PRGR_DATA LONG_LIVED SYSTEM thr_prgr_data
@@ -287,6 +272,8 @@ type DIST_DEMONITOR SHORT_LIVED PROCESSES dist_demonitor
type CML_CLEANUP SHORT_LIVED SYSTEM connection_ml_cleanup
type ML_YIELD_STATE SHORT_LIVED SYSTEM monitor_link_yield_state
type ML_DIST STANDARD SYSTEM monitor_link_dist
+type PF3_ARGS SHORT_LIVED PROCESSES process_flag_3_arguments
+type SETUP_CONN_ARG SHORT_LIVED PROCESSES setup_connection_argument
type ENVIRONMENT SYSTEM SYSTEM environment
@@ -315,12 +302,6 @@ type HIPE_EXEC EXEC CODE hipe_code
+endif
-+if heap_frag_elim_test
-
-type SSB SHORT_LIVED PROCESSES ssb
-
-+endif
-
+if lcnt
type LCNT_CARRIER STANDARD SYSTEM lcnt_lock_info_carrier
@@ -340,12 +321,12 @@ type PURGE_DATA SHORT_LIVED CODE purge_data
type DB_HEIR_DATA STANDARD ETS db_heir_data
type DB_MS_PSDO_PROC LONG_LIVED ETS db_match_pseudo_proc
type SCHDLR_DATA LONG_LIVED SYSTEM scheduler_data
-type LL_TEMP_TERM LONG_LIVED SYSTEM ll_temp_term
type NIF_TRAP_EXPORT STANDARD PROCESSES nif_trap_export_entry
type NIF_EXP_TRACE FIXED_SIZE PROCESSES nif_export_trace
type EXPORT LONG_LIVED CODE export_entry
type MONITOR FIXED_SIZE PROCESSES monitor
+type MONITOR_SUSPEND STANDARD PROCESSES monitor_suspend
type LINK FIXED_SIZE PROCESSES link
type AINFO_REQ SHORT_LIVED SYSTEM alloc_info_request
type SCHED_WTIME_REQ SHORT_LIVED SYSTEM sched_wall_time_request
@@ -363,21 +344,17 @@ type DRV_TAB LONG_LIVED SYSTEM drv_tab
type DRV_EV_STATE LONG_LIVED SYSTEM driver_event_state
type DRV_SEL_D_STATE FIXED_SIZE SYSTEM driver_select_data_state
type NIF_SEL_D_STATE FIXED_SIZE SYSTEM enif_select_data_state
-type FD_LIST SHORT_LIVED SYSTEM fd_list
type POLLSET LONG_LIVED SYSTEM pollset
type POLLSET_UPDREQ SHORT_LIVED SYSTEM pollset_update_req
type POLL_FDS LONG_LIVED SYSTEM poll_fds
-type POLL_RES_EVS LONG_LIVED SYSTEM poll_result_events
type FD_STATUS LONG_LIVED SYSTEM fd_status
type SELECT_FDS LONG_LIVED SYSTEM select_fds
+if unix
type SYS_READ_BUF TEMPORARY SYSTEM sys_read_buf
-type FD_TAB LONG_LIVED SYSTEM fd_tab
type FD_ENTRY_BUF STANDARD SYSTEM fd_entry_buf
type CS_PROG_PATH LONG_LIVED SYSTEM cs_prog_path
-type PRT_REP_EXIT STANDARD SYSTEM port_report_exit
type SYS_BLOCKING STANDARD SYSTEM sys_blocking
type SYS_WRITE_BUF TEMPORARY SYSTEM sys_write_buf
@@ -389,7 +366,6 @@ type SYS_WRITE_BUF TEMPORARY SYSTEM sys_write_buf
type DRV_DATA_BUF SYSTEM SYSTEM drv_data_buf
type PRELOADED LONG_LIVED SYSTEM preloaded
type WAITER_OBJ LONG_LIVED SYSTEM waiter_object
-type CON_VPRINTF_BUF TEMPORARY SYSTEM con_vprintf_buf
+endif
diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c
index fdf355d503..b7a8b9c2d0 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2002-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -96,7 +96,6 @@ static int initialized = 0;
#define MBC_REALLOC_ALWAYS_MOVES
#endif
-
/* alloc_util global parameters */
static Uint sys_alloc_carrier_size;
#if HAVE_ERTS_MSEG
@@ -113,32 +112,38 @@ static int allow_sys_alloc_carriers;
#define DEC_CC(CC) ((CC)--)
-/* Multi block carrier (MBC) memory layout in R16:
+/* Multi block carrier (MBC) memory layout in OTP 22:
Empty MBC:
-[Carrier_t|pad|Block_t L0T|fhdr| free... ]
+[Carrier_t|pad|Block_t L0T0|fhdr| free... ]
MBC after allocating first block:
-[Carrier_t|pad|Block_t 000| udata |pad|Block_t L0T|fhdr| free... ]
+[Carrier_t|pad|Block_t 0000| udata |pad|Block_t L0T0|fhdr| free... ]
MBC after allocating second block:
-[Carrier_t|pad|Block_t 000| udata |pad|Block_t 000| udata |pad|Block_t L0T|fhdr| free... ]
+[Carrier_t|pad|Block_t 0000| udata |pad|Block_t 0000| udata |pad|Block_t L0T0|fhdr| free... ]
MBC after deallocating first block:
-[Carrier_t|pad|Block_t 00T|fhdr| free |FreeBlkFtr_t|Block_t 0P0| udata |pad|Block_t L0T|fhdr| free... ]
+[Carrier_t|pad|Block_t 00T0|fhdr| free |FreeBlkFtr_t|Block_t 0P00| udata |pad|Block_t L0T0|fhdr| free... ]
+MBC after allocating first block, with allocation tagging enabled:
+[Carrier_t|pad|Block_t 000A| udata |atag|pad|Block_t L0T0|fhdr| free... ]
udata = Allocated user data
+ atag = A tag with basic metadata about this allocation
pad = Padding to ensure correct alignment for user data
fhdr = Allocator specific header to keep track of free block
free = Unused free memory
T = This block is free (THIS_FREE_BLK_HDR_FLG)
P = Previous block is free (PREV_FREE_BLK_HDR_FLG)
L = Last block in carrier (LAST_BLK_HDR_FLG)
+ A = Block has an allocation tag footer, only valid for allocated blocks
+ (ATAG_BLK_HDR_FLG)
*/
/* Single block carrier (SBC):
-[Carrier_t|pad|Block_t 111| udata... ]
+[Carrier_t|pad|Block_t 1110| udata... ]
+[Carrier_t|pad|Block_t 111A| udata | atag]
*/
/* Allocation tags ...
@@ -154,20 +159,20 @@ MBC after deallocating first block:
typedef UWord alcu_atag_t;
-#define MAKE_ATAG(IdAtom, Type) \
- (ASSERT((Type) >= ERTS_ALC_N_MIN && (Type) <= ERTS_ALC_N_MAX), \
+#define MAKE_ATAG(IdAtom, TypeNum) \
+ (ASSERT((TypeNum) >= ERTS_ALC_N_MIN && (TypeNum) <= ERTS_ALC_N_MAX), \
ASSERT(atom_val(IdAtom) <= MAX_ATAG_ATOM_ID), \
- (atom_val(IdAtom) << ERTS_ALC_N_BITS) | (Type))
+ (atom_val(IdAtom) << ERTS_ALC_N_BITS) | (TypeNum))
#define ATAG_ID(AT) (make_atom((AT) >> ERTS_ALC_N_BITS))
#define ATAG_TYPE(AT) ((AT) & ERTS_ALC_N_MASK)
#define MAX_ATAG_ATOM_ID (ERTS_UWORD_MAX >> ERTS_ALC_N_BITS)
-#define DBG_IS_VALID_ATAG(Allocator, AT) \
+#define DBG_IS_VALID_ATAG(AT) \
(ATAG_TYPE(AT) >= ERTS_ALC_N_MIN && \
ATAG_TYPE(AT) <= ERTS_ALC_N_MAX && \
- (Allocator)->alloc_no == ERTS_ALC_T2A(ERTS_ALC_N2T(ATAG_TYPE(AT))))
+ ATAG_ID(AT) <= MAX_ATAG_ATOM_ID)
/* Blocks ... */
@@ -182,10 +187,15 @@ typedef UWord alcu_atag_t;
#endif
#define FBLK_FTR_SZ (sizeof(FreeBlkFtr_t))
+#define BLK_HAS_ATAG(B) \
+ (!!((B)->bhdr & ATAG_BLK_HDR_FLG))
+
#define GET_BLK_ATAG(B) \
- (((alcu_atag_t *) (((char *) (B)) + (BLK_SZ(B))))[-1])
+ (ASSERT(BLK_HAS_ATAG(B)), \
+ ((alcu_atag_t *) (((char *) (B)) + (BLK_SZ(B))))[-1])
#define SET_BLK_ATAG(B, T) \
- (((alcu_atag_t *) (((char *) (B)) + (BLK_SZ(B))))[-1] = (T))
+ ((B)->bhdr |= ATAG_BLK_HDR_FLG, \
+ ((alcu_atag_t *) (((char *) (B)) + (BLK_SZ(B))))[-1] = (T))
#define BLK_ATAG_SZ(AP) ((AP)->atags ? sizeof(alcu_atag_t) : 0)
@@ -203,13 +213,13 @@ typedef UWord alcu_atag_t;
(((FreeBlkFtr_t *) (((char *) (B)) + (SZ)))[-1] = (SZ))
#define SET_MBC_ABLK_SZ(B, SZ) \
- (ASSERT(((SZ) & FLG_MASK) == 0), \
+ (ASSERT(((SZ) & BLK_FLG_MASK) == 0), \
(B)->bhdr = (((B)->bhdr) & ~MBC_ABLK_SZ_MASK) | (SZ))
#define SET_MBC_FBLK_SZ(B, SZ) \
- (ASSERT(((SZ) & FLG_MASK) == 0), \
+ (ASSERT(((SZ) & BLK_FLG_MASK) == 0), \
(B)->bhdr = (((B)->bhdr) & ~MBC_FBLK_SZ_MASK) | (SZ))
#define SET_SBC_BLK_SZ(B, SZ) \
- (ASSERT(((SZ) & FLG_MASK) == 0), \
+ (ASSERT(((SZ) & BLK_FLG_MASK) == 0), \
(B)->bhdr = (((B)->bhdr) & ~SBC_BLK_SZ_MASK) | (SZ))
#define SET_PREV_BLK_FREE(AP,B) \
(ASSERT(!IS_MBC_FIRST_BLK(AP,B)), \
@@ -235,12 +245,12 @@ typedef UWord alcu_atag_t;
# define SET_MBC_ABLK_HDR(B, Sz, F, C) \
(ASSERT(((Sz) & ~MBC_ABLK_SZ_MASK) == 0), \
- ASSERT(!((UWord)(F) & (~FLG_MASK|THIS_FREE_BLK_HDR_FLG))), \
+ ASSERT(!((UWord)(F) & (~BLK_FLG_MASK|THIS_FREE_BLK_HDR_FLG))), \
(B)->bhdr = ((Sz) | (F) | (BLK_CARRIER_OFFSET(B,C) << MBC_ABLK_OFFSET_SHIFT)))
# define SET_MBC_FBLK_HDR(B, Sz, F, C) \
(ASSERT(((Sz) & ~MBC_FBLK_SZ_MASK) == 0), \
- ASSERT(((UWord)(F) & (~FLG_MASK|THIS_FREE_BLK_HDR_FLG|PREV_FREE_BLK_HDR_FLG)) == THIS_FREE_BLK_HDR_FLG), \
+ ASSERT(((UWord)(F) & (~BLK_FLG_MASK|THIS_FREE_BLK_HDR_FLG|PREV_FREE_BLK_HDR_FLG)) == THIS_FREE_BLK_HDR_FLG), \
(B)->bhdr = ((Sz) | (F)), \
(B)->u.carrier = (C))
@@ -257,8 +267,8 @@ typedef UWord alcu_atag_t;
# define SET_BLK_FREE(B) \
(ASSERT(!IS_PREV_BLK_FREE(B)), \
(B)->u.carrier = ABLK_TO_MBC(B), \
- (B)->bhdr |= THIS_FREE_BLK_HDR_FLG, \
- (B)->bhdr &= (MBC_ABLK_SZ_MASK|FLG_MASK))
+ (B)->bhdr &= (MBC_ABLK_SZ_MASK|LAST_BLK_HDR_FLG), \
+ (B)->bhdr |= THIS_FREE_BLK_HDR_FLG)
# define SET_BLK_ALLOCED(B) \
(ASSERT(((B)->bhdr & (MBC_ABLK_OFFSET_MASK|THIS_FREE_BLK_HDR_FLG)) == THIS_FREE_BLK_HDR_FLG), \
@@ -270,15 +280,16 @@ typedef UWord alcu_atag_t;
# define MBC_SZ_MAX_LIMIT ((UWord)~0)
# define SET_MBC_ABLK_HDR(B, Sz, F, C) \
- (ASSERT(((Sz) & FLG_MASK) == 0), \
- ASSERT(!((UWord)(F) & (~FLG_MASK|THIS_FREE_BLK_HDR_FLG))), \
- ASSERT((UWord)(F) < SBC_BLK_HDR_FLG), \
+ (ASSERT(((Sz) & BLK_FLG_MASK) == 0), \
+ ASSERT(((F) & ~BLK_FLG_MASK) == 0), \
+ ASSERT(!((UWord)(F) & (~BLK_FLG_MASK|THIS_FREE_BLK_HDR_FLG))), \
(B)->bhdr = ((Sz) | (F)), \
(B)->carrier = (C))
# define SET_MBC_FBLK_HDR(B, Sz, F, C) \
- (ASSERT(((Sz) & FLG_MASK) == 0), \
- ASSERT(((UWord)(F) & (~FLG_MASK|THIS_FREE_BLK_HDR_FLG|PREV_FREE_BLK_HDR_FLG)) == THIS_FREE_BLK_HDR_FLG), \
+ (ASSERT(((Sz) & BLK_FLG_MASK) == 0), \
+ ASSERT(((F) & ~BLK_FLG_MASK) == 0), \
+ ASSERT(((UWord)(F) & (~BLK_FLG_MASK|THIS_FREE_BLK_HDR_FLG|PREV_FREE_BLK_HDR_FLG)) == THIS_FREE_BLK_HDR_FLG), \
(B)->bhdr = ((Sz) | (F)), \
(B)->carrier = (C))
@@ -297,7 +308,7 @@ typedef UWord alcu_atag_t;
#endif /* !MBC_ABLK_OFFSET_BITS */
#define SET_SBC_BLK_HDR(B, Sz) \
- (ASSERT(((Sz) & FLG_MASK) == 0), (B)->bhdr = ((Sz) | (SBC_BLK_HDR_FLG)))
+ (ASSERT(((Sz) & BLK_FLG_MASK) == 0), (B)->bhdr = ((Sz) | (SBC_BLK_HDR_FLG)))
#define BLK_UMEM_SZ(B) \
@@ -320,7 +331,7 @@ typedef UWord alcu_atag_t;
#define GET_PREV_FREE_BLK_HDR_FLG(B) \
((B)->bhdr & PREV_FREE_BLK_HDR_FLG)
#define GET_BLK_HDR_FLGS(B) \
- ((B)->bhdr & FLG_MASK)
+ ((B)->bhdr & BLK_FLG_MASK)
#define NXT_BLK(B) \
(ASSERT(IS_MBC_BLK(B)), \
@@ -419,7 +430,7 @@ do { \
#define SCH_SBC SBC_CARRIER_HDR_FLAG
#define SET_CARRIER_HDR(C, Sz, F, AP) \
- (ASSERT(((Sz) & FLG_MASK) == 0), (C)->chdr = ((Sz) | (F)), \
+ (ASSERT(((Sz) & CRR_FLG_MASK) == 0), (C)->chdr = ((Sz) | (F)), \
erts_atomic_init_nob(&(C)->allctr, (erts_aint_t) (AP)))
#define BLK_TO_SBC(B) \
@@ -444,8 +455,8 @@ do { \
(!IS_SB_CARRIER((C)))
#define SET_CARRIER_SZ(C, SZ) \
- (ASSERT(((SZ) & FLG_MASK) == 0), \
- ((C)->chdr = ((C)->chdr & FLG_MASK) | (SZ)))
+ (ASSERT(((SZ) & CRR_FLG_MASK) == 0), \
+ ((C)->chdr = ((C)->chdr & CRR_FLG_MASK) | (SZ)))
#define CFLG_SBC (1 << 0)
#define CFLG_MBC (1 << 1)
@@ -575,10 +586,12 @@ do { \
STAT_MSEG_MBC_ALLOC((AP), csz__); \
else \
STAT_SYS_ALLOC_MBC_ALLOC((AP), csz__); \
- (AP)->mbcs.blocks.curr.no += (CRR)->cpool.blocks; \
+ set_new_allctr_abandon_limit(AP); \
+ (AP)->mbcs.blocks.curr.no += (CRR)->cpool.blocks[(AP)->alloc_no]; \
if ((AP)->mbcs.blocks.max.no < (AP)->mbcs.blocks.curr.no) \
(AP)->mbcs.blocks.max.no = (AP)->mbcs.blocks.curr.no; \
- (AP)->mbcs.blocks.curr.size += (CRR)->cpool.blocks_size; \
+ (AP)->mbcs.blocks.curr.size += \
+ (CRR)->cpool.blocks_size[(AP)->alloc_no]; \
if ((AP)->mbcs.blocks.max.size < (AP)->mbcs.blocks.curr.size) \
(AP)->mbcs.blocks.max.size = (AP)->mbcs.blocks.curr.size; \
} while (0)
@@ -601,25 +614,33 @@ do { \
DEBUG_CHECK_CARRIER_NO_SZ((AP)); \
} while (0)
-#define STAT_MBC_ABANDON(AP, CRR) \
-do { \
- UWord csz__ = CARRIER_SZ((CRR)); \
- if (IS_MSEG_CARRIER((CRR))) \
- STAT_MSEG_MBC_FREE((AP), csz__); \
- else \
- STAT_SYS_ALLOC_MBC_FREE((AP), csz__); \
- ERTS_ALC_CPOOL_ASSERT((AP)->mbcs.blocks.curr.no \
- >= (CRR)->cpool.blocks); \
- (AP)->mbcs.blocks.curr.no -= (CRR)->cpool.blocks; \
- ERTS_ALC_CPOOL_ASSERT((AP)->mbcs.blocks.curr.size \
- >= (CRR)->cpool.blocks_size); \
- (AP)->mbcs.blocks.curr.size -= (CRR)->cpool.blocks_size; \
+#define STAT_MBC_FREE(AP, CRR) \
+do { \
+ UWord csz__ = CARRIER_SZ((CRR)); \
+ if (IS_MSEG_CARRIER((CRR))) { \
+ STAT_MSEG_MBC_FREE((AP), csz__); \
+ } else { \
+ STAT_SYS_ALLOC_MBC_FREE((AP), csz__); \
+ } \
+ set_new_allctr_abandon_limit(AP); \
} while (0)
-#define STAT_MBC_BLK_ALLOC_CRR(CRR, BSZ) \
+#define STAT_MBC_ABANDON(AP, CRR) \
+do { \
+ STAT_MBC_FREE(AP, CRR); \
+ ERTS_ALC_CPOOL_ASSERT((AP)->mbcs.blocks.curr.no \
+ >= (CRR)->cpool.blocks[(AP)->alloc_no]); \
+ (AP)->mbcs.blocks.curr.no -= (CRR)->cpool.blocks[(AP)->alloc_no]; \
+ ERTS_ALC_CPOOL_ASSERT((AP)->mbcs.blocks.curr.size \
+ >= (CRR)->cpool.blocks_size[(AP)->alloc_no]); \
+ (AP)->mbcs.blocks.curr.size -= (CRR)->cpool.blocks_size[(AP)->alloc_no]; \
+} while (0)
+
+#define STAT_MBC_BLK_ALLOC_CRR(AP, CRR, BSZ) \
do { \
- (CRR)->cpool.blocks++; \
- (CRR)->cpool.blocks_size += (BSZ); \
+ (CRR)->cpool.blocks[(AP)->alloc_no]++; \
+ (CRR)->cpool.blocks_size[(AP)->alloc_no] += (BSZ); \
+ (CRR)->cpool.total_blocks_size += (BSZ); \
} while (0)
#define STAT_MBC_BLK_ALLOC(AP, CRR, BSZ, FLGS) \
@@ -631,50 +652,67 @@ do { \
cstats__->blocks.curr.size += (BSZ); \
if (cstats__->blocks.max.size < cstats__->blocks.curr.size) \
cstats__->blocks.max.size = cstats__->blocks.curr.size; \
- STAT_MBC_BLK_ALLOC_CRR((CRR), (BSZ)); \
+ STAT_MBC_BLK_ALLOC_CRR((AP), (CRR), (BSZ)); \
} while (0)
static ERTS_INLINE int
stat_cpool_mbc_blk_free(Allctr_t *allctr,
+ ErtsAlcType_t type,
Carrier_t *crr,
Carrier_t **busy_pcrr_pp,
UWord blksz)
{
+ Allctr_t *orig_allctr;
+ int alloc_no;
- ERTS_ALC_CPOOL_ASSERT(crr->cpool.blocks > 0);
- crr->cpool.blocks--;
- ERTS_ALC_CPOOL_ASSERT(crr->cpool.blocks_size >= blksz);
- crr->cpool.blocks_size -= blksz;
+ alloc_no = ERTS_ALC_T2A(type);
- if (!busy_pcrr_pp || !*busy_pcrr_pp)
- return 0;
+ ERTS_ALC_CPOOL_ASSERT(crr->cpool.blocks[alloc_no] > 0);
+ crr->cpool.blocks[alloc_no]--;
+ ERTS_ALC_CPOOL_ASSERT(crr->cpool.blocks_size[alloc_no] >= blksz);
+ crr->cpool.blocks_size[alloc_no] -= blksz;
+ ERTS_ALC_CPOOL_ASSERT(crr->cpool.total_blocks_size >= blksz);
+ crr->cpool.total_blocks_size -= blksz;
- ERTS_ALC_CPOOL_ASSERT(crr == *busy_pcrr_pp);
+ if (allctr->alloc_no == alloc_no && (!busy_pcrr_pp || !*busy_pcrr_pp)) {
+ /* This is a local block, so we should not update the pool
+ * statistics. */
+ return 0;
+ }
+
+ /* This is either a foreign block that's been fetched from the pool, or any
+ * block that's in the pool. The carrier's owner keeps the statistics for
+ * both pooled and foreign blocks. */
+
+ orig_allctr = crr->cpool.orig_allctr;
+
+ ERTS_ALC_CPOOL_ASSERT(alloc_no != allctr->alloc_no ||
+ (crr == *busy_pcrr_pp && allctr == orig_allctr));
#ifdef ERTS_ALC_CPOOL_DEBUG
ERTS_ALC_CPOOL_ASSERT(
- erts_atomic_dec_read_nob(&allctr->cpool.stat.no_blocks) >= 0);
+ erts_atomic_dec_read_nob(&orig_allctr->cpool.stat.no_blocks[alloc_no]) >= 0);
ERTS_ALC_CPOOL_ASSERT(
- erts_atomic_add_read_nob(&allctr->cpool.stat.blocks_size,
+ erts_atomic_add_read_nob(&orig_allctr->cpool.stat.blocks_size[alloc_no],
-((erts_aint_t) blksz)) >= 0);
#else
- erts_atomic_dec_nob(&allctr->cpool.stat.no_blocks);
- erts_atomic_add_nob(&allctr->cpool.stat.blocks_size,
+ erts_atomic_dec_nob(&orig_allctr->cpool.stat.no_blocks[alloc_no]);
+ erts_atomic_add_nob(&orig_allctr->cpool.stat.blocks_size[alloc_no],
-((erts_aint_t) blksz));
#endif
return 1;
}
-#define STAT_MBC_BLK_FREE(AP, CRR, BPCRRPP, BSZ, FLGS) \
-do { \
- if (!stat_cpool_mbc_blk_free((AP), (CRR), (BPCRRPP), (BSZ))) { \
- CarriersStats_t *cstats__ = &(AP)->mbcs; \
- ASSERT(cstats__->blocks.curr.no > 0); \
- cstats__->blocks.curr.no--; \
- ASSERT(cstats__->blocks.curr.size >= (BSZ)); \
- cstats__->blocks.curr.size -= (BSZ); \
- } \
+#define STAT_MBC_BLK_FREE(AP, TYPE, CRR, BPCRRPP, BSZ, FLGS) \
+do { \
+ if (!stat_cpool_mbc_blk_free((AP), (TYPE), (CRR), (BPCRRPP), (BSZ))) { \
+ CarriersStats_t *cstats__ = &(AP)->mbcs; \
+ ASSERT(cstats__->blocks.curr.no > 0); \
+ cstats__->blocks.curr.no--; \
+ ASSERT(cstats__->blocks.curr.size >= (BSZ)); \
+ cstats__->blocks.curr.size -= (BSZ); \
+ } \
} while (0)
/* Debug stuff... */
@@ -721,8 +759,8 @@ static void make_name_atoms(Allctr_t *allctr);
static Block_t *create_carrier(Allctr_t *, Uint, UWord);
static void destroy_carrier(Allctr_t *, Block_t *, Carrier_t **);
-static void mbc_free(Allctr_t *allctr, void *p, Carrier_t **busy_pcrr_pp);
-static void dealloc_block(Allctr_t *, void *, ErtsAlcFixList_t *, int);
+static void mbc_free(Allctr_t *allctr, ErtsAlcType_t type, void *p, Carrier_t **busy_pcrr_pp);
+static void dealloc_block(Allctr_t *, ErtsAlcType_t, Uint32, void *, ErtsAlcFixList_t *);
static alcu_atag_t determine_alloc_tag(Allctr_t *allocator, ErtsAlcType_t type)
{
@@ -764,14 +802,14 @@ static alcu_atag_t determine_alloc_tag(Allctr_t *allocator, ErtsAlcType_t type)
}
}
- return MAKE_ATAG(id, type);
+ return MAKE_ATAG(id, ERTS_ALC_T2N(type));
}
static void set_alloc_tag(Allctr_t *allocator, void *p, alcu_atag_t tag)
{
Block_t *block;
- ASSERT(DBG_IS_VALID_ATAG(allocator, tag));
+ ASSERT(DBG_IS_VALID_ATAG(tag));
ASSERT(allocator->atags && p);
(void)allocator;
@@ -1308,28 +1346,9 @@ chk_fix_list(Allctr_t *allctr, ErtsAlcFixList_t *fix, int ix, int before)
#define ERTS_DBG_CHK_FIX_LIST(A, FIX, IX, B)
#endif
+static ERTS_INLINE Allctr_t *get_pref_allctr(void *extra);
static void *mbc_alloc(Allctr_t *allctr, Uint size);
-typedef struct {
- ErtsAllctrDDBlock_t ddblock__; /* must be first */
- ErtsAlcType_t fix_type;
-} ErtsAllctrFixDDBlock_t;
-
-#define ERTS_ALC_FIX_NO_UNUSE (((ErtsAlcType_t) 1) << ERTS_ALC_N_BITS)
-
-static ERTS_INLINE void
-dealloc_fix_block(Allctr_t *allctr,
- ErtsAlcType_t type,
- void *ptr,
- ErtsAlcFixList_t *fix,
- int dec_cc_on_redirect)
-{
- /* May be redirected... */
- ASSERT((type & ERTS_ALC_FIX_NO_UNUSE) == 0);
- ((ErtsAllctrFixDDBlock_t *) ptr)->fix_type = type | ERTS_ALC_FIX_NO_UNUSE;
- dealloc_block(allctr, ptr, fix, dec_cc_on_redirect);
-}
-
static ERTS_INLINE void
sched_fix_shrink(Allctr_t *allctr, int on)
{
@@ -1371,7 +1390,7 @@ fix_cpool_check_shrink(Allctr_t *allctr,
if (fix->u.cpool.min_list_size > fix->list_size)
fix->u.cpool.min_list_size = fix->list_size;
- dealloc_fix_block(allctr, type, p, fix, 0);
+ dealloc_block(allctr, type, DEALLOC_FLG_FIX_SHRINK, p, fix);
}
}
}
@@ -1382,11 +1401,9 @@ fix_cpool_alloc(Allctr_t *allctr, ErtsAlcType_t type, Uint size)
void *res;
ErtsAlcFixList_t *fix;
- ASSERT(ERTS_ALC_N_MIN_A_FIXED_SIZE <= type
- && type <= ERTS_ALC_N_MAX_A_FIXED_SIZE);
-
- fix = &allctr->fix[type - ERTS_ALC_N_MIN_A_FIXED_SIZE];
- ASSERT(size == fix->type_size);
+ fix = &allctr->fix[ERTS_ALC_FIX_TYPE_IX(type)];
+ ASSERT(type == fix->type && size == fix->type_size);
+ ASSERT(size >= sizeof(ErtsAllctrDDBlock_t));
res = fix->list;
if (res) {
@@ -1415,21 +1432,39 @@ fix_cpool_alloc(Allctr_t *allctr, ErtsAlcType_t type, Uint size)
static ERTS_INLINE void
fix_cpool_free(Allctr_t *allctr,
ErtsAlcType_t type,
+ Uint32 flags,
void *p,
- Carrier_t **busy_pcrr_pp,
- int unuse)
+ Carrier_t **busy_pcrr_pp)
{
ErtsAlcFixList_t *fix;
+ Allctr_t *fix_allctr;
+
+ /* If this isn't a fix allocator we need to update the fix list of our
+ * neighboring fix_alloc to keep the statistics consistent. */
+ if (!allctr->fix) {
+ ErtsAllocatorThrSpec_t *tspec = &erts_allctr_thr_spec[ERTS_ALC_A_FIXED_SIZE];
+ fix_allctr = get_pref_allctr(tspec);
+ ASSERT(!fix_allctr->thread_safe);
+ ASSERT(allctr != fix_allctr);
+ }
+ else {
+ fix_allctr = allctr;
+ }
- ASSERT(ERTS_ALC_N_MIN_A_FIXED_SIZE <= type
- && type <= ERTS_ALC_N_MAX_A_FIXED_SIZE);
+ ASSERT(ERTS_ALC_IS_CPOOL_ENABLED(fix_allctr));
+ ASSERT(ERTS_ALC_IS_CPOOL_ENABLED(allctr));
- fix = &allctr->fix[type - ERTS_ALC_N_MIN_A_FIXED_SIZE];
+ fix = &fix_allctr->fix[ERTS_ALC_FIX_TYPE_IX(type)];
+ ASSERT(type == fix->type);
- if (unuse)
- fix->u.cpool.used--;
+ if (!(flags & DEALLOC_FLG_FIX_SHRINK)) {
+ fix->u.cpool.used--;
+ }
- if ((!busy_pcrr_pp || !*busy_pcrr_pp)
+ /* We don't want foreign blocks to be long-lived, so we skip recycling if
+ * allctr != fix_allctr. */
+ if (allctr == fix_allctr
+ && (!busy_pcrr_pp || !*busy_pcrr_pp)
&& !fix->u.cpool.shrink_list
&& fix->list_size < ERTS_ALCU_FIX_MAX_LIST_SZ) {
*((void **) p) = fix->list;
@@ -1442,7 +1477,7 @@ fix_cpool_free(Allctr_t *allctr,
if (IS_SBC_BLK(blk))
destroy_carrier(allctr, blk, NULL);
else
- mbc_free(allctr, p, busy_pcrr_pp);
+ mbc_free(allctr, type, p, busy_pcrr_pp);
fix->u.cpool.allocated--;
fix_cpool_check_shrink(allctr, type, fix, busy_pcrr_pp);
}
@@ -1469,7 +1504,7 @@ fix_cpool_alloc_shrink(Allctr_t *allctr, erts_aint32_t flgs)
fix->u.cpool.shrink_list = fix->u.cpool.min_list_size;
fix->u.cpool.min_list_size = fix->list_size;
}
- type = (ErtsAlcType_t) (ix + ERTS_ALC_N_MIN_A_FIXED_SIZE);
+ type = ERTS_ALC_N2T((ErtsAlcType_t) (ix + ERTS_ALC_N_MIN_A_FIXED_SIZE));
for (o = 0; o < ERTS_ALC_FIX_MAX_SHRINK_OPS || flush; o++) {
void *ptr;
@@ -1483,7 +1518,7 @@ fix_cpool_alloc_shrink(Allctr_t *allctr, erts_aint32_t flgs)
fix->list = *((void **) ptr);
fix->list_size--;
fix->u.cpool.shrink_list--;
- dealloc_fix_block(allctr, type, ptr, fix, 0);
+ dealloc_block(allctr, type, DEALLOC_FLG_FIX_SHRINK, ptr, fix);
}
if (fix->u.cpool.min_list_size > fix->list_size)
fix->u.cpool.min_list_size = fix->list_size;
@@ -1509,11 +1544,9 @@ fix_nocpool_alloc(Allctr_t *allctr, ErtsAlcType_t type, Uint size)
ErtsAlcFixList_t *fix;
void *res;
- ASSERT(ERTS_ALC_N_MIN_A_FIXED_SIZE <= type
- && type <= ERTS_ALC_N_MAX_A_FIXED_SIZE);
-
- fix = &allctr->fix[type - ERTS_ALC_N_MIN_A_FIXED_SIZE];
- ASSERT(size == fix->type_size);
+ fix = &allctr->fix[ERTS_ALC_FIX_TYPE_IX(type)];
+ ASSERT(type == fix->type && size == fix->type_size);
+ ASSERT(size >= sizeof(ErtsAllctrDDBlock_t));
ERTS_DBG_CHK_FIX_LIST(allctr, fix, ix, 1);
fix->u.nocpool.used++;
@@ -1530,7 +1563,7 @@ fix_nocpool_alloc(Allctr_t *allctr, ErtsAlcType_t type, Uint size)
if (IS_SBC_BLK(blk))
destroy_carrier(allctr, blk, NULL);
else
- mbc_free(allctr, p, NULL);
+ mbc_free(allctr, type, p, NULL);
fix->u.nocpool.allocated--;
}
ERTS_DBG_CHK_FIX_LIST(allctr, fix, ix, 0);
@@ -1565,10 +1598,8 @@ fix_nocpool_free(Allctr_t *allctr,
Block_t *blk;
ErtsAlcFixList_t *fix;
- ASSERT(ERTS_ALC_N_MIN_A_FIXED_SIZE <= type
- && type <= ERTS_ALC_N_MAX_A_FIXED_SIZE);
-
- fix = &allctr->fix[type - ERTS_ALC_N_MIN_A_FIXED_SIZE];
+ fix = &allctr->fix[ERTS_ALC_T2N(type) - ERTS_ALC_N_MIN_A_FIXED_SIZE];
+ ASSERT(fix->type == type);
ERTS_DBG_CHK_FIX_LIST(allctr, fix, ix, 1);
fix->u.nocpool.used--;
@@ -1587,7 +1618,7 @@ fix_nocpool_free(Allctr_t *allctr,
if (IS_SBC_BLK(blk))
destroy_carrier(allctr, blk, NULL);
else
- mbc_free(allctr, p, NULL);
+ mbc_free(allctr, type, p, NULL);
p = fix->list;
fix->list = *((void **) p);
fix->list_size--;
@@ -1598,7 +1629,7 @@ fix_nocpool_free(Allctr_t *allctr,
if (IS_SBC_BLK(blk))
destroy_carrier(allctr, blk, NULL);
else
- mbc_free(allctr, p, NULL);
+ mbc_free(allctr, type, p, NULL);
ERTS_DBG_CHK_FIX_LIST(allctr, fix, ix, 0);
}
@@ -1639,7 +1670,7 @@ fix_nocpool_alloc_shrink(Allctr_t *allctr, erts_aint32_t flgs)
ptr = fix->list;
fix->list = *((void **) ptr);
fix->list_size--;
- dealloc_block(allctr, ptr, NULL, 0);
+ dealloc_block(allctr, fix->type, 0, ptr, NULL);
fix->u.nocpool.allocated--;
}
if (fix->list_size != 0) {
@@ -1681,6 +1712,7 @@ dealloc_mbc(Allctr_t *allctr, Carrier_t *crr)
}
+static UWord allctr_abandon_limit(Allctr_t *allctr);
static void set_new_allctr_abandon_limit(Allctr_t*);
static void abandon_carrier(Allctr_t*, Carrier_t*);
static void poolify_my_carrier(Allctr_t*, Carrier_t*);
@@ -1802,7 +1834,7 @@ get_used_allctr(Allctr_t *pref_allctr, int pref_lock, void *p, UWord *sizep,
static void
init_dd_queue(ErtsAllctrDDQueue_t *ddq)
{
- erts_atomic_init_nob(&ddq->tail.data.marker.atmc_next, ERTS_AINT_NULL);
+ erts_atomic_init_nob(&ddq->tail.data.marker.u.atmc_next, ERTS_AINT_NULL);
erts_atomic_init_nob(&ddq->tail.data.last,
(erts_aint_t) &ddq->tail.data.marker);
erts_atomic_init_nob(&ddq->tail.data.um_refc[0], 0);
@@ -1823,17 +1855,17 @@ ddq_managed_thread_enqueue(ErtsAllctrDDQueue_t *ddq, void *ptr, int cinit)
erts_aint_t itmp;
ErtsAllctrDDBlock_t *enq, *this = ptr;
- erts_atomic_init_nob(&this->atmc_next, ERTS_AINT_NULL);
+ erts_atomic_init_nob(&this->u.atmc_next, ERTS_AINT_NULL);
/* Enqueue at end of list... */
enq = (ErtsAllctrDDBlock_t *) erts_atomic_read_nob(&ddq->tail.data.last);
- itmp = erts_atomic_cmpxchg_relb(&enq->atmc_next,
+ itmp = erts_atomic_cmpxchg_relb(&enq->u.atmc_next,
(erts_aint_t) this,
ERTS_AINT_NULL);
if (itmp == ERTS_AINT_NULL) {
/* We are required to move last pointer */
#ifdef DEBUG
- ASSERT(ERTS_AINT_NULL == erts_atomic_read_nob(&this->atmc_next));
+ ASSERT(ERTS_AINT_NULL == erts_atomic_read_nob(&this->u.atmc_next));
ASSERT(((erts_aint_t) enq)
== erts_atomic_xchg_relb(&ddq->tail.data.last,
(erts_aint_t) this));
@@ -1851,8 +1883,8 @@ ddq_managed_thread_enqueue(ErtsAllctrDDQueue_t *ddq, void *ptr, int cinit)
while (1) {
erts_aint_t itmp2;
- erts_atomic_set_nob(&this->atmc_next, itmp);
- itmp2 = erts_atomic_cmpxchg_relb(&enq->atmc_next,
+ erts_atomic_set_nob(&this->u.atmc_next, itmp);
+ itmp2 = erts_atomic_cmpxchg_relb(&enq->u.atmc_next,
(erts_aint_t) this,
itmp);
if (itmp == itmp2)
@@ -1861,7 +1893,7 @@ ddq_managed_thread_enqueue(ErtsAllctrDDQueue_t *ddq, void *ptr, int cinit)
itmp = itmp2;
else {
enq = (ErtsAllctrDDBlock_t *) itmp2;
- itmp = erts_atomic_read_acqb(&enq->atmc_next);
+ itmp = erts_atomic_read_acqb(&enq->u.atmc_next);
ASSERT(itmp != ERTS_AINT_NULL);
}
i++;
@@ -1877,8 +1909,8 @@ check_insert_marker(ErtsAllctrDDQueue_t *ddq, erts_aint_t ilast)
erts_aint_t itmp;
ErtsAllctrDDBlock_t *last = (ErtsAllctrDDBlock_t *) ilast;
- erts_atomic_init_nob(&ddq->tail.data.marker.atmc_next, ERTS_AINT_NULL);
- itmp = erts_atomic_cmpxchg_relb(&last->atmc_next,
+ erts_atomic_init_nob(&ddq->tail.data.marker.u.atmc_next, ERTS_AINT_NULL);
+ itmp = erts_atomic_cmpxchg_relb(&last->u.atmc_next,
(erts_aint_t) &ddq->tail.data.marker,
ERTS_AINT_NULL);
if (itmp == ERTS_AINT_NULL) {
@@ -1929,7 +1961,7 @@ ddq_dequeue(ErtsAllctrDDQueue_t *ddq)
ASSERT(ddq->head.used_marker);
ddq->head.used_marker = 0;
blk = ((ErtsAllctrDDBlock_t *)
- erts_atomic_read_nob(&blk->atmc_next));
+ erts_atomic_read_nob(&blk->u.atmc_next));
if (blk == ddq->head.unref_end) {
ddq->head.first = blk;
return NULL;
@@ -1937,7 +1969,7 @@ ddq_dequeue(ErtsAllctrDDQueue_t *ddq)
}
ddq->head.first = ((ErtsAllctrDDBlock_t *)
- erts_atomic_read_nob(&blk->atmc_next));
+ erts_atomic_read_nob(&blk->u.atmc_next));
ASSERT(ddq->head.first);
@@ -1999,19 +2031,13 @@ check_pending_dealloc_carrier(Allctr_t *allctr,
int *need_more_work);
static void
-handle_delayed_fix_dealloc(Allctr_t *allctr, void *ptr)
+handle_delayed_fix_dealloc(Allctr_t *allctr, ErtsAlcType_t type, Uint32 flags,
+ void *ptr)
{
- ErtsAlcType_t type;
-
- type = ((ErtsAllctrFixDDBlock_t *) ptr)->fix_type;
-
- ASSERT(ERTS_ALC_N_MIN_A_FIXED_SIZE
- <= (type & ~ERTS_ALC_FIX_NO_UNUSE));
- ASSERT((type & ~ERTS_ALC_FIX_NO_UNUSE)
- <= ERTS_ALC_N_MAX_A_FIXED_SIZE);
+ ASSERT(ERTS_ALC_IS_FIX_TYPE(type));
if (!ERTS_ALC_IS_CPOOL_ENABLED(allctr))
- fix_nocpool_free(allctr, (type & ~ERTS_ALC_FIX_NO_UNUSE), ptr);
+ fix_nocpool_free(allctr, type, ptr);
else {
Block_t *blk = UMEM2BLK(ptr);
Carrier_t *busy_pcrr_p;
@@ -2026,20 +2052,24 @@ handle_delayed_fix_dealloc(Allctr_t *allctr, void *ptr)
NULL, &busy_pcrr_p);
if (used_allctr == allctr) {
doit:
- fix_cpool_free(allctr, (type & ~ERTS_ALC_FIX_NO_UNUSE),
- ptr, &busy_pcrr_p,
- !(type & ERTS_ALC_FIX_NO_UNUSE));
+ fix_cpool_free(allctr, type, flags, ptr, &busy_pcrr_p);
clear_busy_pool_carrier(allctr, busy_pcrr_p);
}
else {
/* Carrier migrated; need to redirect block to new owner... */
- int cinit = used_allctr->dd.ix - allctr->dd.ix;
+ ErtsAllctrDDBlock_t *dd_block;
+ int cinit;
+
+ dd_block = (ErtsAllctrDDBlock_t*)ptr;
+ dd_block->flags = flags;
+ dd_block->type = type;
ERTS_ALC_CPOOL_ASSERT(!busy_pcrr_p);
DEC_CC(allctr->calls.this_free);
- ((ErtsAllctrFixDDBlock_t *) ptr)->fix_type = type;
+ cinit = used_allctr->dd.ix - allctr->dd.ix;
+
if (ddq_enqueue(&used_allctr->dd.q, ptr, cinit))
erts_alloc_notify_delayed_dealloc(used_allctr->ix);
}
@@ -2063,7 +2093,6 @@ handle_delayed_dealloc(Allctr_t *allctr,
int need_mr_wrk = 0;
int have_checked_incoming = 0;
int ops = 0;
- ErtsAlcFixList_t *fix;
int res;
ErtsAllctrDDQueue_t *ddq;
@@ -2072,8 +2101,6 @@ handle_delayed_dealloc(Allctr_t *allctr,
ERTS_ALCU_DBG_CHK_THR_ACCESS(allctr);
- fix = allctr->fix;
-
ddq = &allctr->dd.q;
res = 0;
@@ -2162,16 +2189,27 @@ handle_delayed_dealloc(Allctr_t *allctr,
}
}
else {
+ ErtsAllctrDDBlock_t *dd_block;
+ ErtsAlcType_t type;
+ Uint32 flags;
+
+ dd_block = (ErtsAllctrDDBlock_t*)ptr;
+ flags = dd_block->flags;
+ type = dd_block->type;
+
+ flags |= DEALLOC_FLG_REDIRECTED;
+
ASSERT(IS_SBC_BLK(blk) || (ABLK_TO_MBC(blk) !=
ErtsContainerStruct(blk, Carrier_t,
cpool.homecoming_dd.blk)));
INC_CC(allctr->calls.this_free);
- if (fix)
- handle_delayed_fix_dealloc(allctr, ptr);
- else
- dealloc_block(allctr, ptr, NULL, 1);
+ if (ERTS_ALC_IS_FIX_TYPE(type)) {
+ handle_delayed_fix_dealloc(allctr, type, flags, ptr);
+ } else {
+ dealloc_block(allctr, type, flags, ptr, NULL);
+ }
}
}
@@ -2199,8 +2237,10 @@ enqueue_dealloc_other_instance(ErtsAlcType_t type,
void *ptr,
int cinit)
{
- if (allctr->fix)
- ((ErtsAllctrFixDDBlock_t*) ptr)->fix_type = type;
+ ErtsAllctrDDBlock_t *dd_block = ((ErtsAllctrDDBlock_t*)ptr);
+
+ dd_block->type = type;
+ dd_block->flags = 0;
if (ddq_enqueue(&allctr->dd.q, ptr, cinit))
erts_alloc_notify_delayed_dealloc(allctr->ix);
@@ -2230,10 +2270,7 @@ check_abandon_carrier(Allctr_t *allctr, Block_t *fblk, Carrier_t **busy_pcrr_pp)
if (!ERTS_ALC_IS_CPOOL_ENABLED(allctr))
return;
- allctr->cpool.check_limit_count--;
- if (--allctr->cpool.check_limit_count <= 0)
- set_new_allctr_abandon_limit(allctr);
-
+ ASSERT(allctr->cpool.abandon_limit == allctr_abandon_limit(allctr));
ASSERT(erts_thr_progress_is_managed_thread());
if (allctr->cpool.disable_abandon)
@@ -2251,7 +2288,7 @@ check_abandon_carrier(Allctr_t *allctr, Block_t *fblk, Carrier_t **busy_pcrr_pp)
if (allctr->main_carrier == crr)
return;
- if (crr->cpool.blocks_size > crr->cpool.abandon_limit)
+ if (crr->cpool.total_blocks_size > crr->cpool.abandon_limit)
return;
if (crr->cpool.thr_prgr != ERTS_THR_PRGR_INVALID
@@ -2287,24 +2324,26 @@ erts_alcu_check_delayed_dealloc(Allctr_t *allctr,
ERTS_ALCU_DD_OPS_LIM_LOW, NULL, NULL, NULL)
static void
-dealloc_block(Allctr_t *allctr, void *ptr, ErtsAlcFixList_t *fix, int dec_cc_on_redirect)
+dealloc_block(Allctr_t *allctr, ErtsAlcType_t type, Uint32 flags, void *ptr,
+ ErtsAlcFixList_t *fix)
{
Block_t *blk = UMEM2BLK(ptr);
+ ASSERT(!fix || type == fix->type);
+
ERTS_LC_ASSERT(!allctr->thread_safe
|| erts_lc_mtx_is_locked(&allctr->mutex));
if (IS_SBC_BLK(blk)) {
destroy_carrier(allctr, blk, NULL);
if (fix && ERTS_ALC_IS_CPOOL_ENABLED(allctr)) {
- ErtsAlcType_t type = ((ErtsAllctrFixDDBlock_t *) ptr)->fix_type;
- if (!(type & ERTS_ALC_FIX_NO_UNUSE))
+ if (!(flags & DEALLOC_FLG_FIX_SHRINK))
fix->u.cpool.used--;
fix->u.cpool.allocated--;
}
}
else if (!ERTS_ALC_IS_CPOOL_ENABLED(allctr))
- mbc_free(allctr, ptr, NULL);
+ mbc_free(allctr, type, ptr, NULL);
else {
Carrier_t *busy_pcrr_p;
Allctr_t *used_allctr;
@@ -2313,22 +2352,29 @@ dealloc_block(Allctr_t *allctr, void *ptr, ErtsAlcFixList_t *fix, int dec_cc_on_
NULL, &busy_pcrr_p);
if (used_allctr == allctr) {
if (fix) {
- ErtsAlcType_t type = ((ErtsAllctrFixDDBlock_t *) ptr)->fix_type;
- if (!(type & ERTS_ALC_FIX_NO_UNUSE))
+ if (!(flags & DEALLOC_FLG_FIX_SHRINK))
fix->u.cpool.used--;
fix->u.cpool.allocated--;
}
- mbc_free(allctr, ptr, &busy_pcrr_p);
+ mbc_free(allctr, type, ptr, &busy_pcrr_p);
clear_busy_pool_carrier(allctr, busy_pcrr_p);
}
else {
/* Carrier migrated; need to redirect block to new owner... */
- int cinit = used_allctr->dd.ix - allctr->dd.ix;
+ ErtsAllctrDDBlock_t *dd_block;
+ int cinit;
+
+ dd_block = (ErtsAllctrDDBlock_t*)ptr;
+ dd_block->flags = flags;
+ dd_block->type = type;
ERTS_ALC_CPOOL_ASSERT(!busy_pcrr_p);
- if (dec_cc_on_redirect)
+ if (flags & DEALLOC_FLG_REDIRECTED)
DEC_CC(allctr->calls.this_free);
+
+ cinit = used_allctr->dd.ix - allctr->dd.ix;
+
if (ddq_enqueue(&used_allctr->dd.q, ptr, cinit))
erts_alloc_notify_delayed_dealloc(used_allctr->ix);
}
@@ -2495,7 +2541,7 @@ mbc_alloc(Allctr_t *allctr, Uint size)
}
static void
-mbc_free(Allctr_t *allctr, void *p, Carrier_t **busy_pcrr_pp)
+mbc_free(Allctr_t *allctr, ErtsAlcType_t type, void *p, Carrier_t **busy_pcrr_pp)
{
Uint is_first_blk;
Uint is_last_blk;
@@ -2517,7 +2563,8 @@ mbc_free(Allctr_t *allctr, void *p, Carrier_t **busy_pcrr_pp)
crr = ABLK_TO_MBC(blk);
ERTS_ALC_CPOOL_FREE_OP(allctr);
- STAT_MBC_BLK_FREE(allctr, crr, busy_pcrr_pp, blk_sz, alcu_flgs);
+
+ STAT_MBC_BLK_FREE(allctr, type, crr, busy_pcrr_pp, blk_sz, alcu_flgs);
is_first_blk = IS_MBC_FIRST_ABLK(allctr, blk);
is_last_blk = IS_LAST_BLK(blk);
@@ -2586,8 +2633,8 @@ mbc_free(Allctr_t *allctr, void *p, Carrier_t **busy_pcrr_pp)
}
static void *
-mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs,
- Carrier_t **busy_pcrr_pp)
+mbc_realloc(Allctr_t *allctr, ErtsAlcType_t type, void *p, Uint size,
+ Uint32 alcu_flgs, Carrier_t **busy_pcrr_pp)
{
void *new_p;
Uint old_blk_sz;
@@ -2625,7 +2672,7 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs,
new_blk = UMEM2BLK(new_p);
ASSERT(!(IS_MBC_BLK(new_blk) && ABLK_TO_MBC(new_blk) == *busy_pcrr_pp));
sys_memcpy(new_p, p, MIN(size, old_blk_sz - ABLK_HDR_SZ));
- mbc_free(allctr, p, busy_pcrr_pp);
+ mbc_free(allctr, type, p, busy_pcrr_pp);
return new_p;
}
@@ -2702,7 +2749,7 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs,
crr = ABLK_TO_MBC(blk);
ERTS_ALC_CPOOL_REALLOC_OP(allctr);
- STAT_MBC_BLK_FREE(allctr, crr, NULL, old_blk_sz, alcu_flgs);
+ STAT_MBC_BLK_FREE(allctr, type, crr, NULL, old_blk_sz, alcu_flgs);
STAT_MBC_BLK_ALLOC(allctr, crr, blk_sz, alcu_flgs);
ASSERT(MBC_BLK_SZ(blk) >= allctr->min_block_size);
@@ -2806,7 +2853,7 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs,
}
ERTS_ALC_CPOOL_REALLOC_OP(allctr);
- STAT_MBC_BLK_FREE(allctr, crr, NULL, old_blk_sz, alcu_flgs);
+ STAT_MBC_BLK_FREE(allctr, type, crr, NULL, old_blk_sz, alcu_flgs);
STAT_MBC_BLK_ALLOC(allctr, crr, blk_sz, alcu_flgs);
ASSERT(IS_ALLOCED_BLK(blk));
@@ -2867,7 +2914,7 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs,
if (!new_p)
return NULL;
sys_memcpy(new_p, p, MIN(size, old_blk_sz - ABLK_HDR_SZ));
- mbc_free(allctr, p, busy_pcrr_pp);
+ mbc_free(allctr, type, p, busy_pcrr_pp);
return new_p;
@@ -2897,7 +2944,7 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs,
1);
new_p = BLK2UMEM(new_blk);
sys_memcpy(new_p, p, MIN(size, old_blk_sz - ABLK_HDR_SZ));
- mbc_free(allctr, p, NULL);
+ mbc_free(allctr, type, p, NULL);
return new_p;
}
else {
@@ -2954,7 +3001,7 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs,
0);
ERTS_ALC_CPOOL_FREE_OP(allctr);
- STAT_MBC_BLK_FREE(allctr, crr, NULL, old_blk_sz, alcu_flgs);
+ STAT_MBC_BLK_FREE(allctr, type, crr, NULL, old_blk_sz, alcu_flgs);
return new_p;
}
@@ -2965,7 +3012,6 @@ mbc_realloc(Allctr_t *allctr, void *p, Uint size, Uint32 alcu_flgs,
#define ERTS_ALC_MAX_DEALLOC_CARRIER 10
#define ERTS_ALC_CPOOL_MAX_FETCH_INSPECT 100
-#define ERTS_ALC_CPOOL_CHECK_LIMIT_COUNT 100
#define ERTS_ALC_CPOOL_MAX_FAILED_STAT_READS 3
#define ERTS_ALC_CPOOL_PTR_MOD_MRK (((erts_aint_t) 1) << 0)
@@ -2992,14 +3038,11 @@ typedef union {
# error "Carrier pool implementation assumes ERTS_ALC_A_MIN > ERTS_ALC_A_INVALID"
#endif
-/*
- * The pool is only allowed to be manipulated by managed
- * threads except in the alloc_SUITE:cpool case. In this
- * test case carrier_pool[ERTS_ALC_A_INVALID] will be
- * used.
- */
+/* The pools are only allowed to be manipulated by managed threads except in
+ * the alloc_SUITE:cpool test, where only test_carrier_pool is used. */
-static ErtsAlcCrrPool_t carrier_pool[ERTS_ALC_A_MAX+1] erts_align_attribute(ERTS_CACHE_LINE_SIZE);
+static ErtsAlcCrrPool_t firstfit_carrier_pool;
+static ErtsAlcCrrPool_t test_carrier_pool;
#define ERTS_ALC_CPOOL_MAX_BACKOFF (1 << 8)
@@ -3020,12 +3063,12 @@ backoff(int n)
static int
cpool_dbg_is_in_pool(Allctr_t *allctr, Carrier_t *crr)
{
- ErtsAlcCPoolData_t *sentinel = &carrier_pool[allctr->alloc_no].sentinel;
+ ErtsAlcCPoolData_t *sentinel = allctr->cpool.sentinel;
ErtsAlcCPoolData_t *cpdp = sentinel;
Carrier_t *tmp_crr;
while (1) {
- cpdp = (ErtsAlcCPoolData_t *) (erts_atomic_read_ddrb(&cpdp->next) & ~FLG_MASK);
+ cpdp = (ErtsAlcCPoolData_t *) (erts_atomic_read_ddrb(&cpdp->next) & ~CRR_FLG_MASK);
if (cpdp == sentinel)
return 0;
tmp_crr = (Carrier_t *) (((char *) cpdp) - offsetof(Carrier_t, cpool));
@@ -3037,7 +3080,7 @@ cpool_dbg_is_in_pool(Allctr_t *allctr, Carrier_t *crr)
static int
cpool_is_empty(Allctr_t *allctr)
{
- ErtsAlcCPoolData_t *sentinel = &carrier_pool[allctr->alloc_no].sentinel;
+ ErtsAlcCPoolData_t *sentinel = allctr->cpool.sentinel;
return ((erts_atomic_read_rb(&sentinel->next) == (erts_aint_t) sentinel)
&& (erts_atomic_read_rb(&sentinel->prev) == (erts_aint_t) sentinel));
}
@@ -3127,16 +3170,31 @@ cpool_insert(Allctr_t *allctr, Carrier_t *crr)
{
ErtsAlcCPoolData_t *cpd1p, *cpd2p;
erts_aint_t val;
- ErtsAlcCPoolData_t *sentinel = &carrier_pool[allctr->alloc_no].sentinel;
+ ErtsAlcCPoolData_t *sentinel = allctr->cpool.sentinel;
Allctr_t *orig_allctr = crr->cpool.orig_allctr;
- ERTS_ALC_CPOOL_ASSERT(allctr->alloc_no == ERTS_ALC_A_INVALID /* testcase */
+ ERTS_ALC_CPOOL_ASSERT(allctr->alloc_no == ERTS_ALC_A_TEST /* testcase */
|| erts_thr_progress_is_managed_thread());
- erts_atomic_add_nob(&orig_allctr->cpool.stat.blocks_size,
- (erts_aint_t) crr->cpool.blocks_size);
- erts_atomic_add_nob(&orig_allctr->cpool.stat.no_blocks,
- (erts_aint_t) crr->cpool.blocks);
+ {
+ int alloc_no = allctr->alloc_no;
+
+ ERTS_ALC_CPOOL_ASSERT(
+ erts_atomic_read_nob(&orig_allctr->cpool.stat.blocks_size[alloc_no]) >= 0 &&
+ crr->cpool.blocks_size[alloc_no] >= 0);
+
+ ERTS_ALC_CPOOL_ASSERT(
+ erts_atomic_read_nob(&orig_allctr->cpool.stat.no_blocks[alloc_no]) >= 0 &&
+ crr->cpool.blocks[alloc_no] >= 0);
+
+ /* We only modify the counter for our current type since the others are
+ * conceptually still in the pool. */
+ erts_atomic_add_nob(&orig_allctr->cpool.stat.blocks_size[alloc_no],
+ ((erts_aint_t) crr->cpool.blocks_size[alloc_no]));
+ erts_atomic_add_nob(&orig_allctr->cpool.stat.no_blocks[alloc_no],
+ ((erts_aint_t) crr->cpool.blocks[alloc_no]));
+ }
+
erts_atomic_add_nob(&orig_allctr->cpool.stat.carriers_size,
(erts_aint_t) CARRIER_SZ(crr));
erts_atomic_inc_nob(&orig_allctr->cpool.stat.no_carriers);
@@ -3209,10 +3267,10 @@ cpool_delete(Allctr_t *allctr, Allctr_t *prev_allctr, Carrier_t *crr)
ErtsAlcCPoolData_t *cpd1p, *cpd2p;
erts_aint_t val;
#ifdef ERTS_ALC_CPOOL_DEBUG
- ErtsAlcCPoolData_t *sentinel = &carrier_pool[allctr->alloc_no].sentinel;
+ ErtsAlcCPoolData_t *sentinel = allctr->cpool.sentinel;
#endif
- ERTS_ALC_CPOOL_ASSERT(allctr->alloc_no == ERTS_ALC_A_INVALID /* testcase */
+ ERTS_ALC_CPOOL_ASSERT(allctr->alloc_no == ERTS_ALC_A_TEST /* testcase */
|| erts_thr_progress_is_managed_thread());
ERTS_ALC_CPOOL_ASSERT(sentinel != &crr->cpool);
@@ -3288,28 +3346,43 @@ cpool_delete(Allctr_t *allctr, Allctr_t *prev_allctr, Carrier_t *crr)
crr->cpool.thr_prgr = erts_thr_progress_later(NULL);
- erts_atomic_add_nob(&prev_allctr->cpool.stat.blocks_size,
- -((erts_aint_t) crr->cpool.blocks_size));
- erts_atomic_add_nob(&prev_allctr->cpool.stat.no_blocks,
- -((erts_aint_t) crr->cpool.blocks));
- erts_atomic_add_nob(&prev_allctr->cpool.stat.carriers_size,
+ {
+ Allctr_t *orig_allctr = crr->cpool.orig_allctr;
+ int alloc_no = allctr->alloc_no;
+
+ ERTS_ALC_CPOOL_ASSERT(orig_allctr == prev_allctr);
+
+ ERTS_ALC_CPOOL_ASSERT(crr->cpool.blocks_size[alloc_no] <=
+ erts_atomic_read_nob(&orig_allctr->cpool.stat.blocks_size[alloc_no]));
+
+ ERTS_ALC_CPOOL_ASSERT(crr->cpool.blocks[alloc_no] <=
+ erts_atomic_read_nob(&orig_allctr->cpool.stat.no_blocks[alloc_no]));
+
+ /* We only modify the counters for our current type since the others
+ * were, conceptually, never taken out of the pool. */
+ erts_atomic_add_nob(&orig_allctr->cpool.stat.blocks_size[alloc_no],
+ -((erts_aint_t) crr->cpool.blocks_size[alloc_no]));
+ erts_atomic_add_nob(&orig_allctr->cpool.stat.no_blocks[alloc_no],
+ -((erts_aint_t) crr->cpool.blocks[alloc_no]));
+
+ erts_atomic_add_nob(&orig_allctr->cpool.stat.carriers_size,
-((erts_aint_t) CARRIER_SZ(crr)));
- erts_atomic_dec_wb(&prev_allctr->cpool.stat.no_carriers);
+ erts_atomic_dec_wb(&orig_allctr->cpool.stat.no_carriers);
+ }
}
static Carrier_t *
cpool_fetch(Allctr_t *allctr, UWord size)
{
- enum { IGNORANT, HAS_SEEN_SENTINEL, THE_LAST_ONE } loop_state;
- int i;
+ int i, seen_sentinel;
Carrier_t *crr;
Carrier_t *reinsert_crr = NULL;
ErtsAlcCPoolData_t *cpdp;
ErtsAlcCPoolData_t *cpool_entrance = NULL;
ErtsAlcCPoolData_t *sentinel;
- ERTS_ALC_CPOOL_ASSERT(allctr->alloc_no == ERTS_ALC_A_INVALID /* testcase */
+ ERTS_ALC_CPOOL_ASSERT(allctr->alloc_no == ERTS_ALC_A_TEST /* testcase */
|| erts_thr_progress_is_managed_thread());
i = ERTS_ALC_CPOOL_MAX_FETCH_INSPECT;
@@ -3411,48 +3484,39 @@ cpool_fetch(Allctr_t *allctr, UWord size)
/*
* Finally search the shared pool and try employ foreign carriers
*/
- sentinel = &carrier_pool[allctr->alloc_no].sentinel;
+ sentinel = allctr->cpool.sentinel;
if (cpool_entrance) {
/*
* We saw a pooled carried above, use it as entrance into the pool
*/
- cpdp = cpool_entrance;
}
else {
/*
- * No pooled carried seen above. Start search at cpool sentinel,
+ * No pooled carrier seen above. Start search at cpool sentinel,
* but begin by passing one element before trying to fetch.
* This in order to avoid contention with threads inserting elements.
*/
- cpool_entrance = sentinel;
- cpdp = cpool_aint2cpd(cpool_read(&cpool_entrance->prev));
- if (cpdp == sentinel)
+ cpool_entrance = cpool_aint2cpd(cpool_read(&sentinel->prev));
+ if (cpool_entrance == sentinel)
goto check_dc_list;
}
- loop_state = IGNORANT;
+ cpdp = cpool_entrance;
+ seen_sentinel = 0;
do {
erts_aint_t exp;
cpdp = cpool_aint2cpd(cpool_read(&cpdp->prev));
- if (cpdp == cpool_entrance) {
- if (cpool_entrance == sentinel) {
- cpdp = cpool_aint2cpd(cpool_read(&cpdp->prev));
- if (cpdp == sentinel)
- break;
- }
- loop_state = THE_LAST_ONE;
- }
- else if (cpdp == sentinel) {
- if (loop_state == HAS_SEEN_SENTINEL) {
+ if (cpdp == sentinel) {
+ if (seen_sentinel) {
/* We been here before. cpool_entrance must have been removed */
INC_CC(allctr->cpool.stat.entrance_removed);
break;
}
- cpdp = cpool_aint2cpd(cpool_read(&cpdp->prev));
- if (cpdp == sentinel)
- break;
- loop_state = HAS_SEEN_SENTINEL;
+ seen_sentinel = 1;
+ continue;
}
+ ASSERT(cpdp != cpool_entrance || seen_sentinel);
+
crr = ErtsContainerStruct(cpdp, Carrier_t, cpool);
exp = erts_atomic_read_rb(&crr->allctr);
@@ -3485,7 +3549,7 @@ cpool_fetch(Allctr_t *allctr, UWord size)
INC_CC(allctr->cpool.stat.fail_shared);
return NULL;
}
- }while (loop_state != THE_LAST_ONE);
+ }while (cpdp != cpool_entrance);
check_dc_list:
/* Last; check our own pending dealloc carrier list... */
@@ -3664,8 +3728,9 @@ cpool_init_carrier_data(Allctr_t *allctr, Carrier_t *crr)
crr->cpool.orig_allctr = allctr;
crr->cpool.thr_prgr = ERTS_THR_PRGR_INVALID;
erts_atomic_init_nob(&crr->cpool.max_size, 0);
- crr->cpool.blocks = 0;
- crr->cpool.blocks_size = 0;
+ sys_memset(&crr->cpool.blocks_size, 0, sizeof(crr->cpool.blocks_size));
+ sys_memset(&crr->cpool.blocks, 0, sizeof(crr->cpool.blocks));
+ crr->cpool.total_blocks_size = 0;
if (!ERTS_ALC_IS_CPOOL_ENABLED(allctr))
crr->cpool.abandon_limit = 0;
else {
@@ -3680,14 +3745,14 @@ cpool_init_carrier_data(Allctr_t *allctr, Carrier_t *crr)
crr->cpool.state = ERTS_MBC_IS_HOME;
}
-static void
-set_new_allctr_abandon_limit(Allctr_t *allctr)
+
+
+static UWord
+allctr_abandon_limit(Allctr_t *allctr)
{
UWord limit;
UWord csz;
- allctr->cpool.check_limit_count = ERTS_ALC_CPOOL_CHECK_LIMIT_COUNT;
-
csz = allctr->mbcs.curr.norm.mseg.size;
csz += allctr->mbcs.curr.norm.sys_alloc.size;
@@ -3697,7 +3762,13 @@ set_new_allctr_abandon_limit(Allctr_t *allctr)
else
limit = (csz/100)*allctr->cpool.util_limit;
- allctr->cpool.abandon_limit = limit;
+ return limit;
+}
+
+static void ERTS_INLINE
+set_new_allctr_abandon_limit(Allctr_t *allctr)
+{
+ allctr->cpool.abandon_limit = allctr_abandon_limit(allctr);
}
static void
@@ -3709,7 +3780,6 @@ abandon_carrier(Allctr_t *allctr, Carrier_t *crr)
unlink_carrier(&allctr->mbc_list, crr);
allctr->remove_mbc(allctr, crr);
- set_new_allctr_abandon_limit(allctr);
cpool_insert(allctr, crr);
@@ -3762,7 +3832,8 @@ poolify_my_carrier(Allctr_t *allctr, Carrier_t *crr)
}
static void
-cpool_read_stat(Allctr_t *allctr, UWord *nocp, UWord *cszp, UWord *nobp, UWord *bszp)
+cpool_read_stat(Allctr_t *allctr, int alloc_no,
+ UWord *nocp, UWord *cszp, UWord *nobp, UWord *bszp)
{
int i;
UWord noc = 0, csz = 0, nob = 0, bsz = 0;
@@ -3782,10 +3853,10 @@ cpool_read_stat(Allctr_t *allctr, UWord *nocp, UWord *cszp, UWord *nobp, UWord *
? erts_atomic_read_nob(&allctr->cpool.stat.carriers_size)
: 0);
tnob = (UWord) (nobp
- ? erts_atomic_read_nob(&allctr->cpool.stat.no_blocks)
+ ? erts_atomic_read_nob(&allctr->cpool.stat.no_blocks[alloc_no])
: 0);
tbsz = (UWord) (bszp
- ? erts_atomic_read_nob(&allctr->cpool.stat.blocks_size)
+ ? erts_atomic_read_nob(&allctr->cpool.stat.blocks_size[alloc_no])
: 0);
if (tnoc == noc && tcsz == csz && tnob == nob && tbsz == bsz)
break;
@@ -4040,6 +4111,7 @@ create_carrier(Allctr_t *allctr, Uint umem_sz, UWord flags)
#if HAVE_ERTS_MSEG
mbc_final_touch:
#endif
+ set_new_allctr_abandon_limit(allctr);
blk = MBC_TO_FIRST_BLK(allctr, crr);
@@ -4258,7 +4330,6 @@ destroy_carrier(Allctr_t *allctr, Block_t *blk, Carrier_t **busy_pcrr_pp)
else {
ASSERT(IS_MBC_FIRST_FBLK(allctr, blk));
crr = FIRST_BLK_TO_MBC(allctr, blk);
- crr_sz = CARRIER_SZ(crr);
#ifdef DEBUG
if (!allctr->stopped) {
@@ -4290,15 +4361,7 @@ destroy_carrier(Allctr_t *allctr, Block_t *blk, Carrier_t **busy_pcrr_pp)
else
{
unlink_carrier(&allctr->mbc_list, crr);
-#if HAVE_ERTS_MSEG
- if (IS_MSEG_CARRIER(crr)) {
- ASSERT(crr_sz % ERTS_SACRR_UNIT_SZ == 0);
- STAT_MSEG_MBC_FREE(allctr, crr_sz);
- }
- else
-#endif
- STAT_SYS_ALLOC_MBC_FREE(allctr, crr_sz);
-
+ STAT_MBC_FREE(allctr, crr);
if (allctr->remove_mbc)
allctr->remove_mbc(allctr, crr);
}
@@ -4312,7 +4375,7 @@ destroy_carrier(Allctr_t *allctr, Block_t *blk, Carrier_t **busy_pcrr_pp)
LTTNG5(carrier_destroy,
ERTS_ALC_A2AD(allctr->alloc_no),
allctr->ix,
- crr_sz,
+ CARRIER_SZ(crr),
mbc_stats,
sbc_stats);
}
@@ -4390,6 +4453,8 @@ static struct {
Eterm blocks_size;
Eterm blocks;
+ Eterm foreign_blocks;
+
Eterm calls;
Eterm sys_alloc;
Eterm sys_free;
@@ -4490,6 +4555,7 @@ init_atoms(Allctr_t *allctr)
AM_INIT(carriers);
AM_INIT(blocks_size);
AM_INIT(blocks);
+ AM_INIT(foreign_blocks);
AM_INIT(calls);
AM_INIT(sys_alloc);
@@ -4625,7 +4691,6 @@ sz_info_fix(Allctr_t *allctr,
ErtsAlcFixList_t *fix = &allctr->fix[ix];
UWord alloced = fix->type_size * fix->u.cpool.allocated;
UWord used = fix->type_size * fix->u.cpool.used;
- ErtsAlcType_t n = ERTS_ALC_N_MIN_A_FIXED_SIZE + ix;
if (print_to_p) {
fmtfn_t to = *print_to_p;
@@ -4633,14 +4698,14 @@ sz_info_fix(Allctr_t *allctr,
erts_print(to,
arg,
"fix type internal: %s %bpu %bpu\n",
- (char *) ERTS_ALC_N2TD(n),
+ (char *) ERTS_ALC_T2TD(fix->type),
alloced,
used);
}
if (hpp || szp) {
add_3tup(hpp, szp, &res,
- alloc_type_atoms[n],
+ alloc_type_atoms[ERTS_ALC_T2N(fix->type)],
bld_unstable_uint(hpp, szp, alloced),
bld_unstable_uint(hpp, szp, used));
}
@@ -4653,7 +4718,6 @@ sz_info_fix(Allctr_t *allctr,
ErtsAlcFixList_t *fix = &allctr->fix[ix];
UWord alloced = fix->type_size * fix->u.nocpool.allocated;
UWord used = fix->type_size*fix->u.nocpool.used;
- ErtsAlcType_t n = ERTS_ALC_N_MIN_A_FIXED_SIZE + ix;
if (print_to_p) {
fmtfn_t to = *print_to_p;
@@ -4661,14 +4725,14 @@ sz_info_fix(Allctr_t *allctr,
erts_print(to,
arg,
"fix type: %s %bpu %bpu\n",
- (char *) ERTS_ALC_N2TD(n),
+ (char *) ERTS_ALC_T2TD(fix->type),
alloced,
used);
}
if (hpp || szp) {
add_3tup(hpp, szp, &res,
- alloc_type_atoms[n],
+ alloc_type_atoms[ERTS_ALC_T2N(fix->type)],
bld_unstable_uint(hpp, szp, alloced),
bld_unstable_uint(hpp, szp, used));
}
@@ -4741,9 +4805,9 @@ info_cpool(Allctr_t *allctr,
noc = csz = nob = bsz = ~0;
if (print_to_p || hpp) {
if (sz_only)
- cpool_read_stat(allctr, NULL, &csz, NULL, &bsz);
+ cpool_read_stat(allctr, allctr->alloc_no, NULL, &csz, NULL, &bsz);
else
- cpool_read_stat(allctr, &noc, &csz, &nob, &bsz);
+ cpool_read_stat(allctr, allctr->alloc_no, &noc, &csz, &nob, &bsz);
}
if (print_to_p) {
@@ -4758,6 +4822,10 @@ info_cpool(Allctr_t *allctr,
}
if (hpp || szp) {
+ Eterm foreign_blocks;
+ int i;
+
+ foreign_blocks = NIL;
res = NIL;
if (!sz_only) {
@@ -4804,22 +4872,61 @@ info_cpool(Allctr_t *allctr,
add_3tup(hpp, szp, &res, am.entrance_removed,
bld_unstable_uint(hpp, szp, ERTS_ALC_CC_GIGA_VAL(allctr->cpool.stat.entrance_removed)),
bld_unstable_uint(hpp, szp, ERTS_ALC_CC_VAL(allctr->cpool.stat.entrance_removed)));
+ }
add_2tup(hpp, szp, &res,
am.carriers_size,
bld_unstable_uint(hpp, szp, csz));
- }
- if (!sz_only)
- add_2tup(hpp, szp, &res,
- am.carriers,
- bld_unstable_uint(hpp, szp, noc));
+
+ if (!sz_only) {
+ add_2tup(hpp, szp, &res,
+ am.carriers,
+ bld_unstable_uint(hpp, szp, noc));
+ }
+
add_2tup(hpp, szp, &res,
am.blocks_size,
bld_unstable_uint(hpp, szp, bsz));
- if (!sz_only)
+
+ if (!sz_only) {
add_2tup(hpp, szp, &res,
am.blocks,
bld_unstable_uint(hpp, szp, nob));
+ }
+
+ for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) {
+ const char *name_str;
+ Eterm name, info;
+
+ if (i == allctr->alloc_no) {
+ continue;
+ }
+
+ cpool_read_stat(allctr, i, NULL, NULL, &nob, &bsz);
+
+ if (bsz == 0 && (nob == 0 || sz_only)) {
+ continue;
+ }
+
+ name_str = ERTS_ALC_A2AD(i);
+ info = NIL;
+
+ add_2tup(hpp, szp, &info,
+ am.blocks_size,
+ bld_unstable_uint(hpp, szp, bsz));
+
+ if (!sz_only) {
+ add_2tup(hpp, szp, &info,
+ am.blocks,
+ bld_unstable_uint(hpp, szp, nob));
+ }
+
+ name = am_atom_put(name_str, sys_strlen(name_str));
+
+ add_2tup(hpp, szp, &foreign_blocks, name, info);
+ }
+
+ add_2tup(hpp, szp, &res, am.foreign_blocks, foreign_blocks);
}
return res;
@@ -5455,6 +5562,19 @@ erts_alcu_info(Allctr_t *allctr,
return res;
}
+void
+erts_alcu_foreign_size(Allctr_t *allctr, ErtsAlcType_t alloc_no, AllctrSize_t *size)
+{
+ if (ERTS_ALC_IS_CPOOL_ENABLED(allctr)) {
+ UWord csz, bsz;
+ cpool_read_stat(allctr, alloc_no, NULL, &csz, NULL, &bsz);
+ size->carriers = csz;
+ size->blocks = bsz;
+ } else {
+ size->carriers = 0;
+ size->blocks = 0;
+ }
+}
void
erts_alcu_current_size(Allctr_t *allctr, AllctrSize_t *size, ErtsAlcUFixInfo_t *fi, int fisz)
@@ -5473,7 +5593,7 @@ erts_alcu_current_size(Allctr_t *allctr, AllctrSize_t *size, ErtsAlcUFixInfo_t *
if (ERTS_ALC_IS_CPOOL_ENABLED(allctr)) {
UWord csz, bsz;
- cpool_read_stat(allctr, NULL, &csz, NULL, &bsz);
+ cpool_read_stat(allctr, allctr->alloc_no, NULL, &csz, NULL, &bsz);
size->blocks += bsz;
size->carriers += csz;
}
@@ -5518,6 +5638,11 @@ do_erts_alcu_alloc(ErtsAlcType_t type, Allctr_t *allctr, Uint size)
ERTS_ALCU_DBG_CHK_THR_ACCESS(allctr);
+ /* Reject sizes that can't fit into the header word. */
+ if (size > ~BLK_FLG_MASK) {
+ return NULL;
+ }
+
#if ALLOC_ZERO_EQ_NULL
if (!size)
return NULL;
@@ -5684,12 +5809,11 @@ do_erts_alcu_free(ErtsAlcType_t type, Allctr_t *allctr, void *p,
ERTS_ALCU_DBG_CHK_THR_ACCESS(allctr);
if (p) {
-
INC_CC(allctr->calls.this_free);
- if (allctr->fix) {
+ if (ERTS_ALC_IS_FIX_TYPE(type)) {
if (ERTS_ALC_IS_CPOOL_ENABLED(allctr))
- fix_cpool_free(allctr, type, p, busy_pcrr_pp, 1);
+ fix_cpool_free(allctr, type, 0, p, busy_pcrr_pp);
else
fix_nocpool_free(allctr, type, p);
}
@@ -5698,7 +5822,7 @@ do_erts_alcu_free(ErtsAlcType_t type, Allctr_t *allctr, void *p,
if (IS_SBC_BLK(blk))
destroy_carrier(allctr, blk, NULL);
else
- mbc_free(allctr, p, busy_pcrr_pp);
+ mbc_free(allctr, type, p, busy_pcrr_pp);
}
}
}
@@ -5800,6 +5924,11 @@ do_erts_alcu_realloc(ErtsAlcType_t type,
return res;
}
+ /* Reject sizes that can't fit into the header word. */
+ if (size > ~BLK_FLG_MASK) {
+ return NULL;
+ }
+
#if ALLOC_ZERO_EQ_NULL
if (!size) {
ASSERT(p);
@@ -5816,7 +5945,7 @@ do_erts_alcu_realloc(ErtsAlcType_t type,
if (size < allctr->sbc_threshold) {
if (IS_MBC_BLK(blk))
- res = mbc_realloc(allctr, p, size, alcu_flgs, busy_pcrr_pp);
+ res = mbc_realloc(allctr, type, p, size, alcu_flgs, busy_pcrr_pp);
else {
Uint used_sz = SBC_HEADER_SIZE + ABLK_HDR_SZ + size;
Uint crr_sz;
@@ -5875,7 +6004,7 @@ do_erts_alcu_realloc(ErtsAlcType_t type,
sys_memcpy((void *) res,
(void *) p,
MIN(MBC_ABLK_SZ(blk) - ABLK_HDR_SZ, size));
- mbc_free(allctr, p, busy_pcrr_pp);
+ mbc_free(allctr, type, p, busy_pcrr_pp);
}
else
res = NULL;
@@ -6243,6 +6372,7 @@ int
erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
{
/* erts_alcu_start assumes that allctr has been zeroed */
+ int i;
if (((UWord)allctr & ERTS_CRR_ALCTR_FLG_MASK) != 0) {
erts_exit(ERTS_ABORT_EXIT, "%s:%d:erts_alcu_start: Alignment error\n",
@@ -6266,6 +6396,11 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
allctr->ix = init->ix;
allctr->alloc_no = init->alloc_no;
+ allctr->alloc_strat = init->alloc_strat;
+
+ ASSERT(allctr->alloc_no >= ERTS_ALC_A_MIN &&
+ allctr->alloc_no <= ERTS_ALC_A_MAX);
+
if (allctr->alloc_no < ERTS_ALC_A_MIN
|| ERTS_ALC_A_MAX < allctr->alloc_no)
allctr->alloc_no = ERTS_ALC_A_INVALID;
@@ -6318,8 +6453,7 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
+ sizeof(FreeBlkFtr_t));
if (init->tpref) {
Uint sz = ABLK_HDR_SZ;
- sz += (init->fix ?
- sizeof(ErtsAllctrFixDDBlock_t) : sizeof(ErtsAllctrDDBlock_t));
+ sz += sizeof(ErtsAllctrDDBlock_t);
sz = UNIT_CEILING(sz);
if (sz > allctr->min_block_size)
allctr->min_block_size = sz;
@@ -6330,15 +6464,23 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
allctr->cpool.dc_list.last = NULL;
allctr->cpool.abandon_limit = 0;
allctr->cpool.disable_abandon = 0;
- erts_atomic_init_nob(&allctr->cpool.stat.blocks_size, 0);
- erts_atomic_init_nob(&allctr->cpool.stat.no_blocks, 0);
+ for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) {
+ erts_atomic_init_nob(&allctr->cpool.stat.blocks_size[i], 0);
+ erts_atomic_init_nob(&allctr->cpool.stat.no_blocks[i], 0);
+ }
erts_atomic_init_nob(&allctr->cpool.stat.carriers_size, 0);
erts_atomic_init_nob(&allctr->cpool.stat.no_carriers, 0);
- allctr->cpool.check_limit_count = ERTS_ALC_CPOOL_CHECK_LIMIT_COUNT;
if (!init->ts && init->acul && init->acnl) {
allctr->cpool.util_limit = init->acul;
allctr->cpool.in_pool_limit = init->acnl;
allctr->cpool.fblk_min_limit = init->acfml;
+
+ if (allctr->alloc_strat == ERTS_ALC_S_FIRSTFIT) {
+ allctr->cpool.sentinel = &firstfit_carrier_pool.sentinel;
+ }
+ else if (allctr->alloc_no != ERTS_ALC_A_TEST) {
+ ERTS_INTERNAL_ERROR("Impossible carrier migration config.");
+ }
}
else {
allctr->cpool.util_limit = 0;
@@ -6346,6 +6488,12 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
allctr->cpool.fblk_min_limit = 0;
}
+ /* The invasive tests don't really care whether the pool is enabled or not,
+ * so we need to set this unconditionally for this allocator type. */
+ if (allctr->alloc_no == ERTS_ALC_A_TEST) {
+ allctr->cpool.sentinel = &test_carrier_pool.sentinel;
+ }
+
allctr->sbc_threshold = adjust_sbct(allctr, init->sbct);
#if HAVE_ERTS_MSEG
@@ -6457,9 +6605,9 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init)
allctr->fix_shrink_scheduled = 0;
for (i = 0; i < ERTS_ALC_NO_FIXED_SIZES; i++) {
allctr->fix[i].type_size = init->fix_type_size[i];
+ allctr->fix[i].type = ERTS_ALC_N2T(i + ERTS_ALC_N_MIN_A_FIXED_SIZE);
allctr->fix[i].list_size = 0;
allctr->fix[i].list = NULL;
- ASSERT(allctr->fix[i].type_size >= sizeof(ErtsAllctrFixDDBlock_t));
if (ERTS_ALC_IS_CPOOL_ENABLED(allctr)) {
allctr->fix[i].u.cpool.min_list_size = 0;
allctr->fix[i].u.cpool.shrink_list = 0;
@@ -6508,12 +6656,16 @@ erts_alcu_stop(Allctr_t *allctr)
void
erts_alcu_init(AlcUInit_t *init)
{
- int i;
- for (i = 0; i <= ERTS_ALC_A_MAX; i++) {
- ErtsAlcCPoolData_t *sentinel = &carrier_pool[i].sentinel;
- erts_atomic_init_nob(&sentinel->next, (erts_aint_t) sentinel);
- erts_atomic_init_nob(&sentinel->prev, (erts_aint_t) sentinel);
- }
+ ErtsAlcCPoolData_t *sentinel;
+
+ sentinel = &firstfit_carrier_pool.sentinel;
+ erts_atomic_init_nob(&sentinel->next, (erts_aint_t) sentinel);
+ erts_atomic_init_nob(&sentinel->prev, (erts_aint_t) sentinel);
+
+ sentinel = &test_carrier_pool.sentinel;
+ erts_atomic_init_nob(&sentinel->next, (erts_aint_t) sentinel);
+ erts_atomic_init_nob(&sentinel->prev, (erts_aint_t) sentinel);
+
ERTS_CT_ASSERT(SBC_BLK_SZ_MASK == MBC_FBLK_SZ_MASK); /* see BLK_SZ */
#if HAVE_ERTS_MSEG
ASSERT(erts_mseg_unit_size() == ERTS_SACRR_UNIT_SZ);
@@ -6695,7 +6847,7 @@ static int blockscan_cpool_yielding(blockscan_t *state)
{
ErtsAlcCPoolData_t *sentinel, *cursor;
- sentinel = &carrier_pool[(state->allocator)->alloc_no].sentinel;
+ sentinel = (state->allocator)->cpool.sentinel;
cursor = blockscan_restore_cpool_cursor(state);
if (ERTS_PROC_IS_EXITING(state->process)) {
@@ -6827,11 +6979,8 @@ static int blockscan_sweep_mbcs(blockscan_t *state)
static int blockscan_sweep_cpool(blockscan_t *state)
{
if (state->current_op != blockscan_sweep_cpool) {
- ErtsAlcCPoolData_t *sentinel;
-
SET_CARRIER_HDR(&state->dummy_carrier, 0, SCH_MBC, state->allocator);
- sentinel = &carrier_pool[(state->allocator)->alloc_no].sentinel;
- state->cpool_cursor = sentinel;
+ state->cpool_cursor = (state->allocator)->cpool.sentinel;
}
state->current_op = blockscan_sweep_cpool;
@@ -7115,11 +7264,14 @@ static int gather_ahist_scan(Allctr_t *allocator,
alcu_atag_t tag;
block = SBC2BLK(allocator, carrier);
- tag = GET_BLK_ATAG(block);
- ASSERT(DBG_IS_VALID_ATAG(allocator, tag));
+ if (BLK_HAS_ATAG(block)) {
+ tag = GET_BLK_ATAG(block);
- gather_ahist_update(state, tag, SBC_BLK_SZ(block));
+ ASSERT(DBG_IS_VALID_ATAG(tag));
+
+ gather_ahist_update(state, tag, SBC_BLK_SZ(block));
+ }
} else {
UWord scanned_bytes = MBC_HEADER_SIZE(allocator);
@@ -7130,10 +7282,10 @@ static int gather_ahist_scan(Allctr_t *allocator,
while (1) {
UWord block_size = MBC_BLK_SZ(block);
- if (IS_ALLOCED_BLK(block)) {
+ if (IS_ALLOCED_BLK(block) && BLK_HAS_ATAG(block)) {
alcu_atag_t tag = GET_BLK_ATAG(block);
- ASSERT(DBG_IS_VALID_ATAG(allocator, tag));
+ ASSERT(DBG_IS_VALID_ATAG(tag));
gather_ahist_update(state, tag, block_size);
}
@@ -7293,8 +7445,6 @@ int erts_alcu_gather_alloc_histograms(Process *p, int allocator_num,
sched_id,
&allocator)) {
return 0;
- } else if (!allocator->atags) {
- return 0;
}
ensure_atoms_initialized(allocator);
diff --git a/erts/emulator/beam/erl_alloc_util.h b/erts/emulator/beam/erl_alloc_util.h
index ff4d10b206..9ab8589bf3 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2002-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
#define ERTS_ALCU_VSN_STR "3.0"
#include "erl_alloc_types.h"
+#include "erl_alloc.h"
#define ERL_THREADS_EMU_INTERNAL__
#include "erl_threads.h"
@@ -44,6 +45,7 @@ typedef struct {
typedef struct {
char *name_prefix;
ErtsAlcType_t alloc_no;
+ ErtsAlcStrat_t alloc_strat;
int force;
int ix;
int ts;
@@ -101,6 +103,7 @@ typedef struct {
#define ERTS_DEFAULT_ALLCTR_INIT { \
NULL, \
ERTS_ALC_A_INVALID, /* (number) alloc_no: allocator number */\
+ ERTS_ALC_S_INVALID, /* (number) alloc_strat: allocator strategy */\
0, /* (bool) force: force enabled */\
0, /* (number) ix: instance index */\
1, /* (bool) ts: thread safe */\
@@ -138,6 +141,7 @@ typedef struct {
#define ERTS_DEFAULT_ALLCTR_INIT { \
NULL, \
ERTS_ALC_A_INVALID, /* (number) alloc_no: allocator number */\
+ ERTS_ALC_S_INVALID, /* (number) alloc_strat: allocator strategy */\
0, /* (bool) force: force enabled */\
0, /* (number) ix: instance index */\
1, /* (bool) ts: thread safe */\
@@ -188,6 +192,7 @@ Eterm erts_alcu_info(Allctr_t *, int, int, fmtfn_t *, void *, Uint **, Uint *);
void erts_alcu_init(AlcUInit_t *);
void erts_alcu_current_size(Allctr_t *, AllctrSize_t *,
ErtsAlcUFixInfo_t *, int);
+void erts_alcu_foreign_size(Allctr_t *, ErtsAlcType_t, AllctrSize_t *);
void erts_alcu_check_delayed_dealloc(Allctr_t *, int, int *, ErtsThrPrgrVal *, int *);
erts_aint32_t erts_alcu_fix_alloc_shrink(Allctr_t *, erts_aint32_t);
@@ -286,10 +291,18 @@ void erts_alcu_sched_spec_data_init(struct ErtsSchedulerData_ *esdp);
#define UNIT_FLOOR(X) ((X) & UNIT_MASK)
#define UNIT_CEILING(X) UNIT_FLOOR((X) + INV_UNIT_MASK)
-#define FLG_MASK INV_UNIT_MASK
-#define SBC_BLK_SZ_MASK UNIT_MASK
-#define MBC_FBLK_SZ_MASK UNIT_MASK
-#define CARRIER_SZ_MASK UNIT_MASK
+/* We store flags in the bits that no one will ever use. Generally these are
+ * the bits below the alignment size, but for blocks we also steal the highest
+ * bit since the header's a size and no one can expect to be able to allocate
+ * objects that large. */
+#define HIGHEST_WORD_BIT (((UWord) 1) << (sizeof(UWord) * CHAR_BIT - 1))
+
+#define BLK_FLG_MASK (INV_UNIT_MASK | HIGHEST_WORD_BIT)
+#define SBC_BLK_SZ_MASK (~BLK_FLG_MASK)
+#define MBC_FBLK_SZ_MASK (~BLK_FLG_MASK)
+
+#define CRR_FLG_MASK INV_UNIT_MASK
+#define CRR_SZ_MASK UNIT_MASK
#if ERTS_HAVE_MSEG_SUPER_ALIGNED \
|| (!HAVE_ERTS_MSEG && ERTS_HAVE_ERTS_SYS_ALIGNED_ALLOC)
@@ -299,9 +312,9 @@ void erts_alcu_sched_spec_data_init(struct ErtsSchedulerData_ *esdp);
# define ERTS_SUPER_ALIGN_BITS 18
# endif
# ifdef ARCH_64
-# define MBC_ABLK_OFFSET_BITS 24
+# define MBC_ABLK_OFFSET_BITS 23
# else
-# define MBC_ABLK_OFFSET_BITS 9
+# define MBC_ABLK_OFFSET_BITS 8
/* Affects hard limits for sbct and lmbcs documented in erts_alloc.xml */
# endif
# define ERTS_SACRR_UNIT_SHIFT ERTS_SUPER_ALIGN_BITS
@@ -322,18 +335,17 @@ void erts_alcu_sched_spec_data_init(struct ErtsSchedulerData_ *esdp);
#if MBC_ABLK_OFFSET_BITS
# define MBC_ABLK_OFFSET_SHIFT (sizeof(UWord)*8 - MBC_ABLK_OFFSET_BITS)
-# define MBC_ABLK_OFFSET_MASK (~((UWord)0) << MBC_ABLK_OFFSET_SHIFT)
-# define MBC_ABLK_SZ_MASK (~MBC_ABLK_OFFSET_MASK & ~FLG_MASK)
+# define MBC_ABLK_OFFSET_MASK ((~((UWord)0) << MBC_ABLK_OFFSET_SHIFT) & ~BLK_FLG_MASK)
+# define MBC_ABLK_SZ_MASK (~MBC_ABLK_OFFSET_MASK & ~BLK_FLG_MASK)
#else
-# define MBC_ABLK_SZ_MASK (~FLG_MASK)
+# define MBC_ABLK_SZ_MASK (~BLK_FLG_MASK)
#endif
#define MBC_ABLK_SZ(B) (ASSERT(!is_sbc_blk(B)), (B)->bhdr & MBC_ABLK_SZ_MASK)
#define MBC_FBLK_SZ(B) (ASSERT(!is_sbc_blk(B)), (B)->bhdr & MBC_FBLK_SZ_MASK)
#define SBC_BLK_SZ(B) (ASSERT(is_sbc_blk(B)), (B)->bhdr & SBC_BLK_SZ_MASK)
-#define CARRIER_SZ(C) \
- ((C)->chdr & CARRIER_SZ_MASK)
+#define CARRIER_SZ(C) ((C)->chdr & CRR_SZ_MASK)
typedef union {char c[ERTS_ALLOC_ALIGN_BYTES]; long l; double d;} Unit_t;
@@ -351,12 +363,20 @@ typedef struct {
#endif
} Block_t;
-typedef union ErtsAllctrDDBlock_t_ ErtsAllctrDDBlock_t;
+typedef struct ErtsAllctrDDBlock__ {
+ union {
+ struct ErtsAllctrDDBlock__ *ptr_next;
+ erts_atomic_t atmc_next;
+ } u;
+ ErtsAlcType_t type;
+ Uint32 flags;
+} ErtsAllctrDDBlock_t;
-union ErtsAllctrDDBlock_t_ {
- erts_atomic_t atmc_next;
- ErtsAllctrDDBlock_t *ptr_next;
-};
+/* Deallocation was caused by shrinking a fix-list, so usage statistics has
+ * already been updated. */
+#define DEALLOC_FLG_FIX_SHRINK (1 << 0)
+/* Deallocation was redirected to another instance. */
+#define DEALLOC_FLG_REDIRECTED (1 << 1)
typedef struct {
Block_t blk;
@@ -365,11 +385,10 @@ typedef struct {
#endif
} ErtsFakeDDBlock_t;
-
-
#define THIS_FREE_BLK_HDR_FLG (((UWord) 1) << 0)
#define PREV_FREE_BLK_HDR_FLG (((UWord) 1) << 1)
#define LAST_BLK_HDR_FLG (((UWord) 1) << 2)
+#define ATAG_BLK_HDR_FLG HIGHEST_WORD_BIT
#define SBC_BLK_HDR_FLG /* Special flag combo for (allocated) SBC blocks */\
(THIS_FREE_BLK_HDR_FLG | PREV_FREE_BLK_HDR_FLG | LAST_BLK_HDR_FLG)
@@ -381,9 +400,9 @@ typedef struct {
#define HOMECOMING_MBC_BLK_HDR (THIS_FREE_BLK_HDR_FLG | LAST_BLK_HDR_FLG)
#define IS_FREE_LAST_MBC_BLK(B) \
- (((B)->bhdr & FLG_MASK) == (THIS_FREE_BLK_HDR_FLG | LAST_BLK_HDR_FLG))
+ (((B)->bhdr & BLK_FLG_MASK) == (THIS_FREE_BLK_HDR_FLG | LAST_BLK_HDR_FLG))
-#define IS_SBC_BLK(B) (((B)->bhdr & FLG_MASK) == SBC_BLK_HDR_FLG)
+#define IS_SBC_BLK(B) (((B)->bhdr & SBC_BLK_HDR_FLG) == SBC_BLK_HDR_FLG)
#define IS_MBC_BLK(B) (!IS_SBC_BLK((B)))
#define IS_FREE_BLK(B) (ASSERT(IS_MBC_BLK(B)), \
(B)->bhdr & THIS_FREE_BLK_HDR_FLG)
@@ -394,7 +413,8 @@ typedef struct {
# define ABLK_TO_MBC(B) \
(ASSERT(IS_MBC_BLK(B) && !IS_FREE_BLK(B)), \
(Carrier_t*)((ERTS_SACRR_UNIT_FLOOR((UWord)(B)) - \
- (((B)->bhdr >> MBC_ABLK_OFFSET_SHIFT) << ERTS_SACRR_UNIT_SHIFT))))
+ ((((B)->bhdr & ~BLK_FLG_MASK) >> MBC_ABLK_OFFSET_SHIFT) \
+ << ERTS_SACRR_UNIT_SHIFT))))
# define BLK_TO_MBC(B) (IS_FREE_BLK(B) ? FBLK_TO_MBC(B) : ABLK_TO_MBC(B))
#else
# define FBLK_TO_MBC(B) ((B)->carrier)
@@ -414,6 +434,10 @@ struct AOFF_RBTree_t_ {
AOFF_RBTree_t *right;
Uint32 flags;
Uint32 max_sz; /* of all blocks in this sub-tree */
+ union {
+ AOFF_RBTree_t* next; /* for best fit */
+ Sint64 birth_time; /* for age first fit */
+ } u;
};
void aoff_add_pooled_mbc(Allctr_t*, Carrier_t*);
@@ -429,8 +453,9 @@ typedef struct {
ErtsThrPrgrVal thr_prgr;
erts_atomic_t max_size;
UWord abandon_limit;
- UWord blocks;
- UWord blocks_size;
+ UWord blocks[ERTS_ALC_A_MAX + 1];
+ UWord blocks_size[ERTS_ALC_A_MAX + 1];
+ UWord total_blocks_size;
enum {
ERTS_MBC_IS_HOME,
ERTS_MBC_WAS_POOLED,
@@ -448,7 +473,7 @@ struct Carrier_t_ {
};
#define ERTS_ALC_CARRIER_TO_ALLCTR(C) \
- ((Allctr_t *) (erts_atomic_read_nob(&(C)->allctr) & ~FLG_MASK))
+ ((Allctr_t *) (erts_atomic_read_nob(&(C)->allctr) & ~CRR_FLG_MASK))
typedef struct {
Carrier_t *first;
@@ -526,7 +551,6 @@ typedef struct {
} head;
} ErtsAllctrDDQueue_t;
-
typedef struct {
size_t type_size;
SWord list_size;
@@ -545,6 +569,7 @@ typedef struct {
UWord used;
} cpool;
} u;
+ ErtsAlcType_t type;
} ErtsAlcFixList_t;
struct Allctr_t_ {
@@ -565,6 +590,9 @@ struct Allctr_t_ {
/* Allocator number */
ErtsAlcType_t alloc_no;
+ /* Allocator strategy */
+ ErtsAlcStrat_t alloc_strat;
+
/* Instance index */
int ix;
@@ -613,6 +641,9 @@ struct Allctr_t_ {
AOFF_RBTree_t* pooled_tree;
CarrierList_t dc_list;
+ /* the sentinel of the cpool we're attached to */
+ ErtsAlcCPoolData_t *sentinel;
+
UWord abandon_limit;
int disable_abandon;
int check_limit_count;
@@ -620,8 +651,8 @@ struct Allctr_t_ {
UWord in_pool_limit; /* acnl */
UWord fblk_min_limit; /* acmfl */
struct {
- erts_atomic_t blocks_size;
- erts_atomic_t no_blocks;
+ erts_atomic_t blocks_size[ERTS_ALC_A_MAX + 1];
+ erts_atomic_t no_blocks[ERTS_ALC_A_MAX + 1];
erts_atomic_t carriers_size;
erts_atomic_t no_carriers;
CallCounter_t fail_pooled;
diff --git a/erts/emulator/beam/erl_ao_firstfit_alloc.c b/erts/emulator/beam/erl_ao_firstfit_alloc.c
index 0c5545401a..0e3e4c890a 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2003-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -100,24 +100,18 @@
#define AOFF_BLK_SZ(B) MBC_FBLK_SZ(&(B)->hdr)
-/* BF block nodes keeps list of all with equal size
- */
-typedef struct {
- AOFF_RBTree_t t;
- AOFF_RBTree_t *next;
-}AOFF_RBTreeList_t;
-
-#define LIST_NEXT(N) (((AOFF_RBTreeList_t*) (N))->next)
-#define LIST_PREV(N) (((AOFF_RBTreeList_t*) (N))->t.parent)
+#define LIST_NEXT(N) (((AOFF_RBTree_t*)(N))->u.next)
+#define LIST_PREV(N) (((AOFF_RBTree_t*)(N))->parent)
typedef struct AOFF_Carrier_t_ AOFF_Carrier_t;
struct AOFF_Carrier_t_ {
Carrier_t crr;
- AOFF_RBTree_t rbt_node; /* My node in the carrier tree */
- Sint64 birth_time;
- AOFF_RBTree_t* root; /* Root of my block tree */
+ AOFF_RBTree_t rbt_node; /* My node in the carrier tree */
+ AOFF_RBTree_t* root; /* Root of my block tree */
+ enum AOFFSortOrder blk_order;
};
+
#define RBT_NODE_TO_MBC(PTR) ErtsContainerStruct((PTR), AOFF_Carrier_t, rbt_node)
/*
@@ -199,9 +193,7 @@ static ERTS_INLINE SWord cmp_blocks(enum AOFFSortOrder order,
{
ASSERT(lhs != rhs);
if (order == FF_AGEFF) {
- AOFF_Carrier_t* lc = RBT_NODE_TO_MBC(lhs);
- AOFF_Carrier_t* rc = RBT_NODE_TO_MBC(rhs);
- Sint64 diff = lc->birth_time - rc->birth_time;
+ Sint64 diff = lhs->u.birth_time - rhs->u.birth_time;
#ifdef ARCH_64
if (diff)
return diff;
@@ -291,13 +283,28 @@ erts_aoffalc_start(AOFFAllctr_t *alc,
sys_memcpy((void *) alc, (void *) &zero.allctr, sizeof(AOFFAllctr_t));
+ if (aoffinit->blk_order == FF_CHAOS) {
+ const enum AOFFSortOrder orders[3] = {FF_AOFF, FF_AOBF, FF_BF};
+ int index = init->ix % (sizeof(orders) / sizeof(orders[0]));
+
+ ASSERT(init->alloc_no == ERTS_ALC_A_TEST);
+ aoffinit->blk_order = orders[index];
+ }
+
+ if (aoffinit->crr_order == FF_CHAOS) {
+ const enum AOFFSortOrder orders[2] = {FF_AGEFF, FF_AOFF};
+ int index = init->ix % (sizeof(orders) / sizeof(orders[0]));
+
+ ASSERT(init->alloc_no == ERTS_ALC_A_TEST);
+ aoffinit->crr_order = orders[index];
+ }
+
alc->blk_order = aoffinit->blk_order;
alc->crr_order = aoffinit->crr_order;
allctr->mbc_header_size = sizeof(AOFF_Carrier_t);
allctr->min_mbc_size = MIN_MBC_SZ;
allctr->min_mbc_first_free_size = MIN_MBC_FIRST_FREE_SZ;
- allctr->min_block_size = (aoffinit->blk_order == FF_BF ?
- sizeof(AOFF_RBTreeList_t):sizeof(AOFF_RBTree_t));
+ allctr->min_block_size = sizeof(AOFF_RBTree_t);
allctr->vsn_str = ERTS_ALC_AOFF_ALLOC_VSN_STR;
@@ -520,14 +527,15 @@ tree_insert_fixup(AOFF_RBTree_t** root, AOFF_RBTree_t *blk)
static void
aoff_unlink_free_block(Allctr_t *allctr, Block_t *blk)
{
- AOFFAllctr_t* alc = (AOFFAllctr_t*)allctr;
AOFF_RBTree_t* del = (AOFF_RBTree_t*)blk;
AOFF_Carrier_t *crr = (AOFF_Carrier_t*) FBLK_TO_MBC(&del->hdr);
+ (void)allctr;
+
ASSERT(crr->rbt_node.hdr.bhdr == crr->root->max_sz);
- HARD_CHECK_TREE(&crr->crr, alc->blk_order, crr->root, 0);
+ HARD_CHECK_TREE(&crr->crr, crr->blk_order, crr->root, 0);
- if (alc->blk_order == FF_BF) {
+ if (crr->blk_order == FF_BF) {
ASSERT(del->flags & IS_BF_FLG);
if (IS_LIST_ELEM(del)) {
/* Remove from list */
@@ -548,14 +556,14 @@ aoff_unlink_free_block(Allctr_t *allctr, Block_t *blk)
replace(&crr->root, (AOFF_RBTree_t*)del, LIST_NEXT(del));
- HARD_CHECK_TREE(&crr->crr, alc->blk_order, crr->root, 0);
+ HARD_CHECK_TREE(&crr->crr, crr->blk_order, crr->root, 0);
return;
}
}
rbt_delete(&crr->root, (AOFF_RBTree_t*)del);
- HARD_CHECK_TREE(&crr->crr, alc->blk_order, crr->root, 0);
+ HARD_CHECK_TREE(&crr->crr, crr->blk_order, crr->root, 0);
/* Update the carrier tree with a potentially new (lower) max_sz
*/
@@ -745,17 +753,18 @@ rbt_delete(AOFF_RBTree_t** root, AOFF_RBTree_t* del)
static void
aoff_link_free_block(Allctr_t *allctr, Block_t *block)
{
- AOFFAllctr_t* alc = (AOFFAllctr_t*) allctr;
AOFF_RBTree_t *blk = (AOFF_RBTree_t *) block;
AOFF_RBTree_t *crr_node;
AOFF_Carrier_t *blk_crr = (AOFF_Carrier_t*) FBLK_TO_MBC(block);
Uint blk_sz = AOFF_BLK_SZ(blk);
+ (void)allctr;
+
ASSERT(allctr == ERTS_ALC_CARRIER_TO_ALLCTR(&blk_crr->crr));
ASSERT(blk_crr->rbt_node.hdr.bhdr == (blk_crr->root ? blk_crr->root->max_sz : 0));
- HARD_CHECK_TREE(&blk_crr->crr, alc->blk_order, blk_crr->root, 0);
+ HARD_CHECK_TREE(&blk_crr->crr, blk_crr->blk_order, blk_crr->root, 0);
- rbt_insert(alc->blk_order, &blk_crr->root, blk);
+ rbt_insert(blk_crr->blk_order, &blk_crr->root, blk);
/*
* Update carrier tree with a potentially new (larger) max_sz
@@ -899,7 +908,7 @@ aoff_get_free_block(Allctr_t *allctr, Uint size,
/* Get block within carrier tree
*/
#ifdef HARD_DEBUG
- dbg_blk = HARD_CHECK_TREE(&crr->crr, alc->blk_order, crr->root, size);
+ dbg_blk = HARD_CHECK_TREE(&crr->crr, crr->blk_order, crr->root, size);
#endif
blk = rbt_search(crr->root, size);
@@ -912,7 +921,7 @@ aoff_get_free_block(Allctr_t *allctr, Uint size,
if (!blk)
return NULL;
- if (cand_blk && cmp_cand_blk(alc->blk_order, cand_blk, blk) < 0) {
+ if (cand_blk && cmp_cand_blk(crr->blk_order, cand_blk, blk) < 0) {
return NULL; /* cand_blk was better */
}
@@ -935,18 +944,28 @@ static void aoff_creating_mbc(Allctr_t *allctr, Carrier_t *carrier)
AOFFAllctr_t *alc = (AOFFAllctr_t *) allctr;
AOFF_Carrier_t *crr = (AOFF_Carrier_t*) carrier;
AOFF_RBTree_t **root = &alc->mbc_root;
+ Sint64 bt = get_birth_time();
HARD_CHECK_TREE(NULL, alc->crr_order, *root, 0);
crr->rbt_node.hdr.bhdr = 0;
- if (alc->crr_order == FF_AGEFF || IS_DEBUG)
- crr->birth_time = get_birth_time();
+
+ /* While birth time is only used for FF_AGEFF, we have to set it for all
+ * types as we can be migrated to an instance that uses it and we don't
+ * want to mess its order up. */
+ crr->rbt_node.u.birth_time = bt;
+ crr->crr.cpool.pooled.u.birth_time = bt;
+
rbt_insert(alc->crr_order, root, &crr->rbt_node);
/* aoff_link_free_block will add free block later */
crr->root = NULL;
HARD_CHECK_TREE(NULL, alc->crr_order, *root, 0);
+
+ /* When a carrier has been migrated, its block order may differ from that
+ * of the allocator it's been migrated to. */
+ crr->blk_order = alc->blk_order;
}
#define IS_CRR_IN_TREE(CRR,ROOT) \
@@ -978,6 +997,7 @@ static void aoff_add_mbc(Allctr_t *allctr, Carrier_t *carrier)
void aoff_add_pooled_mbc(Allctr_t *allctr, Carrier_t *crr)
{
+ AOFFAllctr_t *alc = (AOFFAllctr_t *) allctr;
AOFF_RBTree_t **root = &allctr->cpool.pooled_tree;
ASSERT(allctr == crr->cpool.orig_allctr);
@@ -985,7 +1005,7 @@ void aoff_add_pooled_mbc(Allctr_t *allctr, Carrier_t *crr)
/* Link carrier in address order tree
*/
- rbt_insert(FF_AOFF, root, &crr->cpool.pooled);
+ rbt_insert(alc->crr_order, root, &crr->cpool.pooled);
HARD_CHECK_TREE(NULL, 0, *root, 0);
}
diff --git a/erts/emulator/beam/erl_ao_firstfit_alloc.h b/erts/emulator/beam/erl_ao_firstfit_alloc.h
index 9cf4fc81a8..9c9b98da86 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2003-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -29,10 +29,15 @@
typedef struct AOFFAllctr_t_ AOFFAllctr_t;
enum AOFFSortOrder {
- FF_AGEFF = 0,
+ FF_AGEFF = 0, /* carrier trees only */
FF_AOFF = 1,
- FF_AOBF = 2,
- FF_BF = 3
+ FF_AOBF = 2, /* block trees only */
+ FF_BF = 3, /* block trees only */
+
+ FF_CHAOS = -1 /* A test-specific sort order that picks any of the above
+ * after instance id. Used to test that carriers created
+ * under one order will work fine after being migrated
+ * to another. */
};
typedef struct {
diff --git a/erts/emulator/beam/erl_arith.c b/erts/emulator/beam/erl_arith.c
index b6625db0d3..144fb56ea5 100644
--- a/erts/emulator/beam/erl_arith.c
+++ b/erts/emulator/beam/erl_arith.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1999-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_async.c b/erts/emulator/beam/erl_async.c
index 3ceb2fd368..605a2b3461 100644
--- a/erts/emulator/beam/erl_async.c
+++ b/erts/emulator/beam/erl_async.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2000-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2000-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_bestfit_alloc.c b/erts/emulator/beam/erl_bestfit_alloc.c
index 85fc4c3a85..9cb1199c2a 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2003-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_bif_binary.c b/erts/emulator/beam/erl_bif_binary.c
index 469f6a1ea8..ede317aca3 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -796,6 +796,7 @@ static void compute_goodshifts(BMData *bmd)
}
#define BM_LOOP_FACTOR 10 /* Should we have a higher value? */
+#define MC_LOOP_FACTOR 8
static void bm_init_find_first_match(BinaryFindContext *ctx)
{
@@ -819,13 +820,38 @@ static BFReturn bm_find_first_match(BinaryFindContext *ctx, byte *haystack)
Sint i;
Sint j = state->pos;
register Uint reds = *reductions;
+ byte *pos_pointer;
+ Sint needle_last = blen - 1;
+ Sint mem_read = len - needle_last - j;
- while (j <= len - blen) {
+ if (mem_read <= 0) {
+ return BF_NOT_FOUND;
+ }
+ mem_read = MIN(mem_read, reds * MC_LOOP_FACTOR);
+ ASSERT(mem_read > 0);
+
+ pos_pointer = memchr(&haystack[j + needle_last], needle[needle_last], mem_read);
+ if (pos_pointer == NULL) {
+ reds -= mem_read / MC_LOOP_FACTOR;
+ j += mem_read;
+ } else {
+ reds -= (pos_pointer - &haystack[j]) / MC_LOOP_FACTOR;
+ j = pos_pointer - haystack - needle_last;
+ }
+
+ // Ensure we have at least one reduction before entering the loop
+ ++reds;
+
+ for(;;) {
+ if (j > len - blen) {
+ *reductions = reds;
+ return BF_NOT_FOUND;
+ }
if (--reds == 0) {
state->pos = j;
return BF_RESTART;
}
- for (i = blen - 1; i >= 0 && needle[i] == haystack[i + j]; --i)
+ for (i = needle_last; i >= 0 && needle[i] == haystack[i + j]; --i)
;
if (i < 0) { /* found */
*reductions = reds;
@@ -835,8 +861,6 @@ static BFReturn bm_find_first_match(BinaryFindContext *ctx, byte *haystack)
}
j += MAX(gs[i],bs[haystack[i+j]] - blen + 1 + i);
}
- *reductions = reds;
- return BF_NOT_FOUND;
}
static void bm_init_find_all(BinaryFindContext *ctx)
@@ -875,14 +899,38 @@ static BFReturn bm_find_all_non_overlapping(BinaryFindContext *ctx, byte *haysta
Sint *gs = bmd->goodshift;
Sint *bs = bmd->badshift;
byte *needle = bmd->x;
- Sint i;
+ Sint i = -1; /* Use memchr on start and on every match */
Sint j = state->pos;
Uint m = state->m;
Uint allocated = state->allocated;
FindallData *out = state->out;
register Uint reds = *reductions;
+ byte *pos_pointer;
+ Sint needle_last = blen - 1;
+ Sint mem_read;
- while (j <= len - blen) {
+ for(;;) {
+ if (i < 0) {
+ mem_read = len - needle_last - j;
+ if(mem_read <= 0) {
+ goto done;
+ }
+ mem_read = MIN(mem_read, reds * MC_LOOP_FACTOR);
+ ASSERT(mem_read > 0);
+ pos_pointer = memchr(&haystack[j + needle_last], needle[needle_last], mem_read);
+ if (pos_pointer == NULL) {
+ reds -= mem_read / MC_LOOP_FACTOR;
+ j += mem_read;
+ } else {
+ reds -= (pos_pointer - &haystack[j]) / MC_LOOP_FACTOR;
+ j = pos_pointer - haystack - needle_last;
+ }
+ // Ensure we have at least one reduction when resuming the loop
+ ++reds;
+ }
+ if (j > len - blen) {
+ goto done;
+ }
if (--reds == 0) {
state->pos = j;
state->m = m;
@@ -890,7 +938,7 @@ static BFReturn bm_find_all_non_overlapping(BinaryFindContext *ctx, byte *haysta
state->out = out;
return BF_RESTART;
}
- for (i = blen - 1; i >= 0 && needle[i] == haystack[i + j]; --i)
+ for (i = needle_last; i >= 0 && needle[i] == haystack[i + j]; --i)
;
if (i < 0) { /* found */
if (m >= allocated) {
@@ -912,6 +960,7 @@ static BFReturn bm_find_all_non_overlapping(BinaryFindContext *ctx, byte *haysta
j += MAX(gs[i],bs[haystack[i+j]] - blen + 1 + i);
}
}
+ done:
state->m = m;
state->out = out;
*reductions = reds;
@@ -931,6 +980,7 @@ static int do_binary_match_compile(Eterm argument, Eterm *tag, Binary **binp)
Eterm t, b, comp_term = NIL;
Uint characters;
Uint words;
+ Uint size;
characters = 0;
words = 0;
@@ -946,11 +996,12 @@ static int do_binary_match_compile(Eterm argument, Eterm *tag, Binary **binp)
if (binary_bitsize(b) != 0) {
goto badarg;
}
- if (binary_size(b) == 0) {
+ size = binary_size(b);
+ if (size == 0) {
goto badarg;
}
++words;
- characters += binary_size(b);
+ characters += size;
}
if (is_not_nil(t)) {
goto badarg;
diff --git a/erts/emulator/beam/erl_bif_chksum.c b/erts/emulator/beam/erl_bif_chksum.c
index 9095bcd380..cce8472ccb 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -44,7 +44,7 @@ void erts_init_bif_chksum(void)
{
/* Non visual BIF to trap to. */
erts_init_trap_export(&chksum_md5_2_exp,
- am_erlang, am_atom_put("md5_trap",8), 2,
+ am_erlang, ERTS_MAKE_AM("md5_trap"), 2,
&md5_2);
}
diff --git a/erts/emulator/beam/erl_bif_ddll.c b/erts/emulator/beam/erl_bif_ddll.c
index 294bce115f..639aee29dc 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2006-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -829,7 +829,7 @@ BIF_RETTYPE erl_ddll_format_error_int_1(BIF_ALIST_1)
"cannot be loaded/unloaded";
break;
case am_permanent:
- errstring = "DDLL driver is permanent an can not be unloaded/loaded";
+ errstring = "DDLL driver is permanent an cannot be unloaded/loaded";
break;
case am_not_loaded:
errstring = "DDLL driver is not loaded";
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 6f9e507228..7fada0d548 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -617,17 +617,13 @@ static void collect_one_target_monitor(ErtsMonitor *mon, void *vmicp)
}
typedef struct {
- Process *c_p;
- ErtsProcLocks c_p_locks;
ErtsMonitorSuspend **smi;
Uint smi_i;
Uint smi_max;
- int sz;
+ Uint sz;
} ErtsSuspendMonitorInfoCollection;
-#define ERTS_INIT_SUSPEND_MONITOR_INFOS(SMIC, CP, CPL) do { \
- (SMIC).c_p = (CP); \
- (SMIC).c_p_locks = (CPL); \
+#define ERTS_INIT_SUSPEND_MONITOR_INFOS(SMIC) do { \
(SMIC).smi = NULL; \
(SMIC).smi_i = (SMIC).smi_max = 0; \
(SMIC).sz = 0; \
@@ -660,34 +656,26 @@ do { \
static void
collect_one_suspend_monitor(ErtsMonitor *mon, void *vsmicp)
{
- ErtsMonitorSuspend *smon = erts_monitor_suspend(mon);
- ErtsSuspendMonitorInfoCollection *smicp = vsmicp;
- Process *suspendee = erts_pid2proc(smicp->c_p,
- smicp->c_p_locks,
- mon->other.item,
- 0);
- if (suspendee) { /* suspendee is alive */
- Sint a, p;
- if (smon->active) {
- smon->active += smon->pending;
- smon->pending = 0;
- }
+ if (mon->type == ERTS_MON_TYPE_SUSPEND) {
+ Sint count;
+ erts_aint_t mstate;
+ ErtsMonitorSuspend *msp;
+ ErtsSuspendMonitorInfoCollection *smicp;
- ASSERT((smon->active && !smon->pending)
- || (smon->pending && !smon->active));
+ msp = (ErtsMonitorSuspend *) erts_monitor_to_data(mon);
+ smicp = vsmicp;
ERTS_EXTEND_SUSPEND_MONITOR_INFOS(smicp);
- smicp->smi[smicp->smi_i] = smon;
+ smicp->smi[smicp->smi_i] = msp;
smicp->sz += 2 /* cons */ + 4 /* 3-tuple */;
- a = (Sint) smon->active; /* quiet compiler warnings */
- p = (Sint) smon->pending; /* on 64-bit machines */
+ mstate = erts_atomic_read_nob(&msp->state);
- if (!IS_SSMALL(a))
- smicp->sz += BIG_UINT_HEAP_SIZE;
- if (!IS_SSMALL(p))
+ count = (Sint) (mstate & ERTS_MSUSPEND_STATE_COUNTER_MASK);
+ if (!IS_SSMALL(count))
smicp->sz += BIG_UINT_HEAP_SIZE;
+
smicp->smi_i++;
}
}
@@ -1075,8 +1063,10 @@ process_info_bif(Process *c_p, Eterm pid, Eterm opt, int always_wrap, int pi2)
if (c_p->common.id == pid) {
int local_only = c_p->flags & F_LOCAL_SIGS_ONLY;
- int sreds = ERTS_BIF_REDS_LEFT(c_p);
- int sres;
+ int sres, sreds, reds_left;
+
+ reds_left = ERTS_BIF_REDS_LEFT(c_p);
+ sreds = reds_left;
if (!local_only) {
erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ);
@@ -1085,15 +1075,19 @@ process_info_bif(Process *c_p, Eterm pid, Eterm opt, int always_wrap, int pi2)
}
sres = erts_proc_sig_handle_incoming(c_p, &state, &sreds, sreds, !0);
+
+ BUMP_REDS(c_p, (int) sreds);
+ reds_left -= sreds;
+
if (state & ERTS_PSFLG_EXITING) {
c_p->flags &= ~F_LOCAL_SIGS_ONLY;
goto exited;
}
- if (!sres) {
+ if (!sres | (reds_left <= 0)) {
/*
- * More signals to handle; need to yield and continue.
- * Prevent fetching of more signals by setting
- * local-sigs-only flag.
+ * More signals to handle or out of reds; need
+ * to yield and continue. Prevent fetching of
+ * more signals by setting local-sigs-only flag.
*/
c_p->flags |= F_LOCAL_SIGS_ONLY;
goto yield;
@@ -1166,6 +1160,7 @@ process_info_bif(Process *c_p, Eterm pid, Eterm opt, int always_wrap, int pi2)
else {
if (flags & ERTS_PI_FLAG_FORCE_SIG_SEND)
goto send_signal;
+ state = ERTS_PSFLG_RUNNING; /* fail state... */
rp = erts_try_lock_sig_free_proc(pid, locks, &state);
if (!rp)
goto undefined;
@@ -1627,56 +1622,56 @@ process_info_aux(Process *c_p,
case ERTS_PI_IX_SUSPENDING: {
ErtsSuspendMonitorInfoCollection smic;
int i;
- Eterm item;
-
- erts_proc_lock(rp, ERTS_PROC_LOCK_STATUS);
- ERTS_INIT_SUSPEND_MONITOR_INFOS(smic,
- c_p,
- (c_p == rp
- ? ERTS_PROC_LOCK_MAIN
- : 0) | ERTS_PROC_LOCK_STATUS);
+ ERTS_INIT_SUSPEND_MONITOR_INFOS(smic);
- erts_monitor_tree_foreach(rp->suspend_monitors,
- &collect_one_suspend_monitor,
- &smic);
+ erts_monitor_tree_foreach(ERTS_P_MONITORS(rp),
+ collect_one_suspend_monitor,
+ (void *) &smic);
reserve_size += smic.sz;
res = NIL;
for (i = 0; i < smic.smi_i; i++) {
- Sint a = (Sint) smic.smi[i]->active; /* quiet compiler warnings */
- Sint p = (Sint) smic.smi[i]->pending; /* on 64-bit machines... */
- Eterm active;
- Eterm pending;
+ ErtsMonitorSuspend *msp;
+ erts_aint_t mstate;
+ Sint ci;
+ Eterm ct, active, pending, item;
Uint sz = 4 + 2;
- if (!IS_SSMALL(a))
- sz += BIG_UINT_HEAP_SIZE;
- if (!IS_SSMALL(p))
- sz += BIG_UINT_HEAP_SIZE;
+
+ msp = smic.smi[i];
+ mstate = erts_atomic_read_nob(&msp->state);
+
+ ci = (Sint) (mstate & ERTS_MSUSPEND_STATE_COUNTER_MASK);
+ if (!IS_SSMALL(ci))
+ sz += BIG_UINT_HEAP_SIZE;
ERTS_PI_UNRESERVE(reserve_size, sz);
hp = erts_produce_heap(hfact, sz, reserve_size);
- if (IS_SSMALL(a))
- active = make_small(a);
- else {
- active = small_to_big(a, hp);
- hp += BIG_UINT_HEAP_SIZE;
- }
- if (IS_SSMALL(p))
- pending = make_small(p);
- else {
- pending = small_to_big(p, hp);
- hp += BIG_UINT_HEAP_SIZE;
- }
- item = TUPLE3(hp, smic.smi[i]->mon.other.item, active, pending);
+ if (IS_SSMALL(ci))
+ ct = make_small(ci);
+ else {
+ ct = small_to_big(ci, hp);
+ hp += BIG_UINT_HEAP_SIZE;
+ }
+
+ if (mstate & ERTS_MSUSPEND_STATE_FLG_ACTIVE) {
+ active = ct;
+ pending = make_small(0);
+ }
+ else {
+ active = make_small(0);
+ pending = ct;
+ }
+
+ ASSERT(is_internal_pid(msp->md.origin.other.item));
+
+ item = TUPLE3(hp, msp->md.origin.other.item, active, pending);
hp += 4;
res = CONS(hp, item, res);
}
- erts_proc_unlock(rp, ERTS_PROC_LOCK_STATUS);
-
*reds += (Uint) smic.smi_i / 4;
ERTS_DESTROY_SUSPEND_MONITOR_INFOS(smic);
@@ -2098,17 +2093,6 @@ current_stacktrace(ErtsHeapFactory *hfact, Process* rp,
return res;
}
-#if defined(VALGRIND)
-static int check_if_xml(void)
-{
- char buf[1];
- size_t bufsz = sizeof(buf);
- return erts_sys_explicit_8bit_getenv("VALGRIND_LOG_XML", buf, &bufsz) >= 0;
-}
-#else
-#define check_if_xml() 0
-#endif
-
/*
* This function takes care of calls to erlang:system_info/1 when the argument
* is a tuple.
@@ -2205,15 +2189,9 @@ info_1_tuple(Process* BIF_P, /* Pointer to current process. */
#endif
} else if (is_list(*tp)) {
#if defined(PURIFY)
-#define ERTS_ERROR_CHECKER_PRINTF purify_printf
-#define ERTS_ERROR_CHECKER_PRINTF_XML purify_printf
+# define ERTS_ERROR_CHECKER_PRINTF purify_printf
#elif defined(VALGRIND)
-#define ERTS_ERROR_CHECKER_PRINTF VALGRIND_PRINTF
-# ifndef HAVE_VALGRIND_PRINTF_XML
-# define ERTS_ERROR_CHECKER_PRINTF_XML VALGRIND_PRINTF
-# else
-# define ERTS_ERROR_CHECKER_PRINTF_XML VALGRIND_PRINTF_XML
-# endif
+# define ERTS_ERROR_CHECKER_PRINTF VALGRIND_PRINTF
#endif
ErlDrvSizeT buf_size = 8*1024; /* Try with 8KB first */
char *buf = erts_alloc(ERTS_ALC_T_TMP, buf_size);
@@ -2229,12 +2207,7 @@ info_1_tuple(Process* BIF_P, /* Pointer to current process. */
ASSERT(r == buf_size - 1);
}
buf[buf_size - 1 - r] = '\0';
- if (check_if_xml()) {
- ERTS_ERROR_CHECKER_PRINTF_XML("<erlang_info_log>"
- "%s</erlang_info_log>\n", buf);
- } else {
- ERTS_ERROR_CHECKER_PRINTF("%s\n", buf);
- }
+ ERTS_ERROR_CHECKER_PRINTF("%s\n", buf);
erts_free(ERTS_ALC_T_TMP, (void *) buf);
BIF_RET(am_true);
#undef ERTS_ERROR_CHECKER_PRINTF
@@ -3134,6 +3107,9 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
else if (ERTS_IS_ATOM_STR("ets_limit",BIF_ARG_1)) {
BIF_RET(make_small(erts_db_get_max_tabs()));
}
+ else if (ERTS_IS_ATOM_STR("ets_count",BIF_ARG_1)) {
+ BIF_RET(make_small(erts_ets_table_count()));
+ }
else if (ERTS_IS_ATOM_STR("atom_limit",BIF_ARG_1)) {
BIF_RET(make_small(erts_get_atom_limit()));
}
@@ -3637,26 +3613,46 @@ BIF_RETTYPE is_process_alive_1(BIF_ALIST_1)
BIF_ERROR(BIF_P, BADARG);
}
-BIF_RETTYPE process_display_2(BIF_ALIST_2)
+static Eterm
+process_display(Process *c_p, void *arg, int *redsp, ErlHeapFragment **bpp)
{
- Process *rp;
+ if (redsp)
+ *redsp = 1;
- if (BIF_ARG_2 != am_backtrace)
- BIF_ERROR(BIF_P, BADARG);
+ if (ERTS_PROC_IS_EXITING(c_p))
+ return am_badarg;
- rp = erts_pid2proc_nropt(BIF_P, ERTS_PROC_LOCK_MAIN,
- BIF_ARG_1, ERTS_PROC_LOCKS_ALL);
- if(!rp) {
- BIF_ERROR(BIF_P, BADARG);
- }
- if (rp == ERTS_PROC_LOCK_BUSY)
- ERTS_BIF_YIELD2(bif_export[BIF_process_display_2], BIF_P,
- BIF_ARG_1, BIF_ARG_2);
- erts_stack_dump(ERTS_PRINT_STDERR, NULL, rp);
- erts_proc_unlock(rp, (BIF_P == rp
- ? ERTS_PROC_LOCKS_ALL_MINOR
- : ERTS_PROC_LOCKS_ALL));
- BIF_RET(am_true);
+ erts_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
+ erts_stack_dump(ERTS_PRINT_STDERR, NULL, c_p);
+ erts_proc_unlock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
+
+ return am_true;
+}
+
+
+BIF_RETTYPE erts_internal_process_display_2(BIF_ALIST_2)
+{
+ Eterm res;
+
+ if (BIF_ARG_2 != am_backtrace)
+ BIF_RET(am_badarg);
+
+ if (BIF_P->common.id == BIF_ARG_1) {
+ res = process_display(BIF_P, NULL, NULL, NULL);
+ BIF_RET(res);
+ }
+
+ if (is_not_internal_pid(BIF_ARG_1))
+ BIF_RET(am_badarg);
+
+ res = erts_proc_sig_send_rpc_request(BIF_P, BIF_ARG_1,
+ !0,
+ process_display,
+ NULL);
+ if (is_non_value(res))
+ BIF_RET(am_badarg);
+
+ BIF_RET(res);
}
/* this is a general call which return some possibly useful information */
@@ -4597,27 +4593,6 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2)
BIF_RET(am_true);
}
}
- else if (ERTS_IS_ATOM_STR("not_running_optimization", BIF_ARG_1)) {
- int old_use_opt, use_opt;
- switch (BIF_ARG_2) {
- case am_true:
- use_opt = 1;
- break;
- case am_false:
- use_opt = 0;
- break;
- default:
- BIF_ERROR(BIF_P, BADARG);
- }
-
- erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
- erts_thr_progress_block();
- old_use_opt = !erts_disable_proc_not_running_opt;
- erts_disable_proc_not_running_opt = !use_opt;
- erts_thr_progress_unblock();
- erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
- BIF_RET(old_use_opt ? am_true : am_false);
- }
else if (ERTS_IS_ATOM_STR("wait", BIF_ARG_1)) {
if (ERTS_IS_ATOM_STR("deallocations", BIF_ARG_2)) {
int flag = ERTS_DEBUG_WAIT_COMPLETED_DEALLOCATIONS;
@@ -4688,7 +4663,14 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2)
refbin));
}
}
-
+ else if (ERTS_IS_ATOM_STR("ets_force_trap", BIF_ARG_1)) {
+#ifdef ETS_DBG_FORCE_TRAP
+ erts_ets_dbg_force_trap = (BIF_ARG_2 == am_true) ? 1 : 0;
+ BIF_RET(am_ok);
+#else
+ BIF_RET(am_notsup);
+#endif
+ }
}
BIF_ERROR(BIF_P, BADARG);
diff --git a/erts/emulator/beam/erl_bif_re.c b/erts/emulator/beam/erl_bif_re.c
index 4d769c2d46..bbc64eb9aa 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c
index 1953f79d79..711e62c795 100644
--- a/erts/emulator/beam/erl_bif_trace.c
+++ b/erts/emulator/beam/erl_bif_trace.c
@@ -643,12 +643,12 @@ Eterm erts_internal_trace_3(BIF_ALIST_3)
SysTimespec tp;
int i;
- if (sys_get_proc_cputime(start, tp) < 0)
+ if (sys_get_cputime(start, tp) < 0)
goto error;
start = ((SysCpuTime)tp.tv_sec * 1000000000LL) +
(SysCpuTime)tp.tv_nsec;
for (i = 0; i < 100; i++)
- sys_get_proc_cputime(stop, tp);
+ sys_get_cputime(stop, tp);
stop = ((SysCpuTime)tp.tv_sec * 1000000000LL) +
(SysCpuTime)tp.tv_nsec;
if (start == 0) goto error;
@@ -809,10 +809,129 @@ Eterm trace_info_2(BIF_ALIST_2)
BIF_ERROR(p, BADARG);
}
erts_release_code_write_permission();
+
+ if (is_value(res) && is_internal_ref(res))
+ BIF_TRAP1(erts_await_result, BIF_P, res);
+
BIF_RET(res);
}
static Eterm
+build_trace_flags_term(Eterm **hpp, Uint *szp, Uint trace_flags)
+{
+
+#define ERTS_TFLAG__(F, FN) \
+ if (trace_flags & F) { \
+ if (szp) \
+ sz += 2; \
+ if (hp) { \
+ res = CONS(hp, FN, res); \
+ hp += 2; \
+ } \
+ }
+
+ Eterm res;
+ Uint sz = 0;
+ Eterm *hp;
+
+ if (hpp) {
+ hp = *hpp;
+ res = NIL;
+ }
+ else {
+ hp = NULL;
+ res = THE_NON_VALUE;
+ }
+
+ ERTS_TFLAG__(F_NOW_TS, am_timestamp);
+ ERTS_TFLAG__(F_STRICT_MON_TS, am_strict_monotonic_timestamp);
+ ERTS_TFLAG__(F_MON_TS, am_monotonic_timestamp);
+ ERTS_TFLAG__(F_TRACE_SEND, am_send);
+ ERTS_TFLAG__(F_TRACE_RECEIVE, am_receive);
+ ERTS_TFLAG__(F_TRACE_SOS, am_set_on_spawn);
+ ERTS_TFLAG__(F_TRACE_CALLS, am_call);
+ ERTS_TFLAG__(F_TRACE_PROCS, am_procs);
+ ERTS_TFLAG__(F_TRACE_SOS1, am_set_on_first_spawn);
+ ERTS_TFLAG__(F_TRACE_SOL, am_set_on_link);
+ ERTS_TFLAG__(F_TRACE_SOL1, am_set_on_first_link);
+ ERTS_TFLAG__(F_TRACE_SCHED, am_running);
+ ERTS_TFLAG__(F_TRACE_SCHED_EXIT, am_exiting);
+ ERTS_TFLAG__(F_TRACE_GC, am_garbage_collection);
+ ERTS_TFLAG__(F_TRACE_ARITY_ONLY, am_arity);
+ ERTS_TFLAG__(F_TRACE_RETURN_TO, am_return_to);
+ ERTS_TFLAG__(F_TRACE_SILENT, am_silent);
+ ERTS_TFLAG__(F_TRACE_SCHED_NO, am_scheduler_id);
+ ERTS_TFLAG__(F_TRACE_PORTS, am_ports);
+ ERTS_TFLAG__(F_TRACE_SCHED_PORTS, am_running_ports);
+ ERTS_TFLAG__(F_TRACE_SCHED_PROCS, am_running_procs);
+
+ if (szp)
+ *szp += sz;
+
+ if (hpp)
+ *hpp = hp;
+
+ return res;
+
+#undef ERTS_TFLAG__
+}
+
+static Eterm
+trace_info_tracee(Process *c_p, void *arg, int *redsp, ErlHeapFragment **bpp)
+{
+ ErlHeapFragment *bp;
+ Eterm *hp, res, key;
+ Uint sz;
+
+ *redsp = 1;
+
+ if (ERTS_PROC_IS_EXITING(c_p))
+ return am_undefined;
+
+ key = (Eterm) arg;
+ sz = 3;
+
+ if (!ERTS_TRACER_IS_NIL(ERTS_TRACER(c_p)))
+ erts_is_tracer_proc_enabled(c_p, ERTS_PROC_LOCK_MAIN,
+ &c_p->common);
+
+ switch (key) {
+ case am_tracer:
+
+ erts_build_tracer_to_term(NULL, NULL, &sz, ERTS_TRACER(c_p));
+ bp = new_message_buffer(sz);
+ hp = bp->mem;
+ res = erts_build_tracer_to_term(&hp, &bp->off_heap,
+ NULL, ERTS_TRACER(c_p));
+ if (res == am_false)
+ res = NIL;
+ break;
+
+ case am_flags:
+
+ build_trace_flags_term(NULL, &sz, ERTS_TRACE_FLAGS(c_p));
+ bp = new_message_buffer(sz);
+ hp = bp->mem;
+ res = build_trace_flags_term(&hp, NULL, ERTS_TRACE_FLAGS(c_p));
+ break;
+
+ default:
+
+ ERTS_INTERNAL_ERROR("Key not supported");
+ res = NIL;
+ bp = NULL;
+ hp = NULL;
+ break;
+ }
+
+ *redsp += 2;
+
+ res = TUPLE2(hp, key, res);
+ *bpp = bp;
+ return res;
+}
+
+static Eterm
trace_info_pid(Process* p, Eterm pid_spec, Eterm key)
{
Eterm tracer;
@@ -846,24 +965,19 @@ trace_info_pid(Process* p, Eterm pid_spec, Eterm key)
erts_port_release(tracee);
} else if (is_internal_pid(pid_spec)) {
- Process *tracee = erts_pid2proc_not_running(p, ERTS_PROC_LOCK_MAIN,
- pid_spec, ERTS_PROC_LOCK_MAIN);
-
- if (tracee == ERTS_PROC_LOCK_BUSY)
- ERTS_BIF_YIELD2(bif_export[BIF_trace_info_2], p, pid_spec, key);
+ Eterm ref;
- if (!tracee)
- return am_undefined;
+ if (key != am_flags && key != am_tracer)
+ goto error;
- if (!ERTS_TRACER_IS_NIL(ERTS_TRACER(tracee)))
- erts_is_tracer_proc_enabled(tracee, ERTS_PROC_LOCK_MAIN,
- &tracee->common);
+ ref = erts_proc_sig_send_rpc_request(p, pid_spec, !0,
+ trace_info_tracee,
+ (void *) key);
- tracer = erts_tracer_to_term(p, ERTS_TRACER(tracee));
- trace_flags = ERTS_TRACE_FLAGS(tracee);
+ if (is_non_value(ref))
+ return am_undefined;
- if (tracee != p)
- erts_proc_unlock(tracee, ERTS_PROC_LOCK_MAIN);
+ return ref;
} else if (is_external_pid(pid_spec)
&& external_pid_dist_entry(pid_spec) == erts_this_dist_entry) {
return am_undefined;
@@ -873,48 +987,16 @@ trace_info_pid(Process* p, Eterm pid_spec, Eterm key)
}
if (key == am_flags) {
- int num_flags = 21; /* MAXIMUM number of flags. */
- Uint needed = 3+2*num_flags;
- Eterm flag_list = NIL;
- Eterm* limit;
+ Eterm flag_list;
+ Uint sz = 3;
+ Eterm *hp;
-#define FLAG0(flag_mask,flag) \
- if (trace_flags & (flag_mask)) { flag_list = CONS(hp, flag, flag_list); hp += 2; } else {}
+ build_trace_flags_term(NULL, &sz, trace_flags);
+
+ hp = HAlloc(p, sz);
+
+ flag_list = build_trace_flags_term(&hp, NULL, trace_flags);
-#if defined(DEBUG)
- /*
- * Check num_flags if this assertion fires.
- */
-# define FLAG ASSERT(num_flags-- > 0); FLAG0
-#else
-# define FLAG FLAG0
-#endif
- hp = HAlloc(p, needed);
- limit = hp+needed;
- FLAG(F_NOW_TS, am_timestamp);
- FLAG(F_STRICT_MON_TS, am_strict_monotonic_timestamp);
- FLAG(F_MON_TS, am_monotonic_timestamp);
- FLAG(F_TRACE_SEND, am_send);
- FLAG(F_TRACE_RECEIVE, am_receive);
- FLAG(F_TRACE_SOS, am_set_on_spawn);
- FLAG(F_TRACE_CALLS, am_call);
- FLAG(F_TRACE_PROCS, am_procs);
- FLAG(F_TRACE_SOS1, am_set_on_first_spawn);
- FLAG(F_TRACE_SOL, am_set_on_link);
- FLAG(F_TRACE_SOL1, am_set_on_first_link);
- FLAG(F_TRACE_SCHED, am_running);
- FLAG(F_TRACE_SCHED_EXIT, am_exiting);
- FLAG(F_TRACE_GC, am_garbage_collection);
- FLAG(F_TRACE_ARITY_ONLY, am_arity);
- FLAG(F_TRACE_RETURN_TO, am_return_to);
- FLAG(F_TRACE_SILENT, am_silent);
- FLAG(F_TRACE_SCHED_NO, am_scheduler_id);
- FLAG(F_TRACE_PORTS, am_ports);
- FLAG(F_TRACE_SCHED_PORTS, am_running_ports);
- FLAG(F_TRACE_SCHED_PROCS, am_running_procs);
-#undef FLAG0
-#undef FLAG
- HRelease(p,limit,hp+3);
return TUPLE2(hp, key, flag_list);
} else if (key == am_tracer) {
if (tracer == am_false)
diff --git a/erts/emulator/beam/erl_bif_unique.h b/erts/emulator/beam/erl_bif_unique.h
index 6af9d4ac8c..40b70667c0 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2014-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_binary.h b/erts/emulator/beam/erl_binary.h
index 46653a8580..08edb43c49 100644
--- a/erts/emulator/beam/erl_binary.h
+++ b/erts/emulator/beam/erl_binary.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2000-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2000-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -146,9 +146,7 @@ typedef union {
/* A "magic" binary flag */
#define BIN_FLAG_MAGIC 1
-#define BIN_FLAG_USR1 2 /* Reserved for use by different modules too mark */
-#define BIN_FLAG_USR2 4 /* certain binaries as special (used by ets) */
-#define BIN_FLAG_DRV 8
+#define BIN_FLAG_DRV 2
#endif /* ERL_BINARY_H__TYPES__ */
diff --git a/erts/emulator/beam/erl_bits.h b/erts/emulator/beam/erl_bits.h
index a3816fa820..7beef5cfda 100644
--- a/erts/emulator/beam/erl_bits.h
+++ b/erts/emulator/beam/erl_bits.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1999-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c
index ca2ebb7c27..c009a3bde8 100644
--- a/erts/emulator/beam/erl_db.c
+++ b/erts/emulator/beam/erl_db.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -50,6 +50,34 @@ erts_atomic_t erts_ets_misc_mem_size;
** Utility macros
*/
+#define DB_BIF_GET_TABLE(TB, WHAT, KIND, BIF_IX) \
+ DB_GET_TABLE(TB, BIF_ARG_1, WHAT, KIND, BIF_IX, NULL, BIF_P)
+
+#define DB_TRAP_GET_TABLE(TB, TID, WHAT, KIND, BIF_EXP) \
+ DB_GET_TABLE(TB, TID, WHAT, KIND, 0, BIF_EXP, BIF_P)
+
+#define DB_GET_TABLE(TB, TID, WHAT, KIND, BIF_IX, BIF_EXP, PROC) \
+do { \
+ Uint freason__; \
+ if (!(TB = db_get_table(PROC, TID, WHAT, KIND, &freason__))) { \
+ return db_bif_fail(PROC, freason__, BIF_IX, BIF_EXP); \
+ } \
+}while(0)
+
+static BIF_RETTYPE db_bif_fail(Process* p, Uint freason,
+ Uint bif_ix, Export* bif_exp)
+{
+ if (freason == TRAP) {
+ if (!bif_exp)
+ bif_exp = bif_export[bif_ix];
+ p->arity = bif_exp->info.mfa.arity;
+ p->i = (BeamInstr*) bif_exp->addressv[erts_active_code_ix()];
+ }
+ p->freason = freason;
+ return THE_NON_VALUE;
+}
+
+
/* Get a key from any table structure and a tagged object */
#define TERM_GETKEY(tb, obj) db_getkey((tb)->common.keypos, (obj))
@@ -294,10 +322,10 @@ erts_db_make_tid(Process *c_p, DbTableCommon *tb)
/*
** The meta hash table of all NAMED ets tables
*/
-# define META_NAME_TAB_LOCK_CNT 16
+# define META_NAME_TAB_LOCK_CNT 256
union {
erts_rwmtx_t lck;
- byte _cache_line_alignment[64];
+ byte align[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(erts_rwmtx_t))];
}meta_name_tab_rwlocks[META_NAME_TAB_LOCK_CNT];
static struct meta_name_tab_entry {
union {
@@ -326,8 +354,7 @@ struct meta_name_tab_entry* meta_name_tab_bucket(Eterm name,
typedef enum {
LCK_READ=1, /* read only access */
LCK_WRITE=2, /* exclusive table write access */
- LCK_WRITE_REC=3, /* record write access */
- LCK_NONE=4
+ LCK_WRITE_REC=3 /* record write access */
} db_lock_kind_t;
extern DbTableMethod db_hash;
@@ -337,9 +364,6 @@ int user_requested_db_max_tabs;
int erts_ets_realloc_always_moves;
int erts_ets_always_compress;
static int db_max_tabs;
-static Eterm ms_delete_all;
-static Eterm ms_delete_all_buff[8]; /* To compare with for deletion
- of all objects */
/*
** Forward decls, static functions
@@ -351,18 +375,19 @@ static void set_heir(Process* me, DbTable* tb, Eterm heir, UWord heir_data);
static void free_heir_data(DbTable*);
static SWord free_fixations_locked(Process* p, DbTable *tb);
+static void delete_all_objects_continue(Process* p, DbTable* tb);
static SWord free_table_continue(Process *p, DbTable *tb, SWord reds);
static void print_table(fmtfn_t to, void *to_arg, int show, DbTable* tb);
-static BIF_RETTYPE ets_select_delete_1(BIF_ALIST_1);
+static BIF_RETTYPE ets_select_delete_trap_1(BIF_ALIST_1);
static BIF_RETTYPE ets_select_count_1(BIF_ALIST_1);
static BIF_RETTYPE ets_select_replace_1(BIF_ALIST_1);
static BIF_RETTYPE ets_select_trap_1(BIF_ALIST_1);
static BIF_RETTYPE ets_delete_trap(BIF_ALIST_1);
static Eterm table_info(Process* p, DbTable* tb, Eterm What);
-static BIF_RETTYPE ets_select1(Process* p, Eterm arg1);
-static BIF_RETTYPE ets_select2(Process* p, Eterm arg1, Eterm arg2);
-static BIF_RETTYPE ets_select3(Process* p, Eterm arg1, Eterm arg2, Eterm arg3);
+static BIF_RETTYPE ets_select1(Process* p, int bif_ix, Eterm arg1);
+static BIF_RETTYPE ets_select2(Process* p, DbTable*, Eterm tid, Eterm ms);
+static BIF_RETTYPE ets_select3(Process* p, DbTable*, Eterm tid, Eterm ms, Sint chunk_size);
/*
@@ -425,7 +450,7 @@ save_sched_table(Process *c_p, DbTable *tb)
DbTable *first;
ASSERT(esdp);
- esdp->ets_tables.count++;
+ erts_atomic_inc_nob(&esdp->ets_tables.count);
erts_refc_inc(&tb->common.refc, 1);
first = esdp->ets_tables.clist;
@@ -449,8 +474,8 @@ remove_sched_table(ErtsSchedulerData *esdp, DbTable *tb)
ASSERT(erts_get_ref_numbers_thr_id(ERTS_MAGIC_BIN_REFN(tb->common.btid))
== (Uint32) esdp->no);
- ASSERT(esdp->ets_tables.count > 0);
- esdp->ets_tables.count--;
+ ASSERT(erts_atomic_read_nob(&esdp->ets_tables.count) > 0);
+ erts_atomic_dec_nob(&esdp->ets_tables.count);
eaydp = ERTS_SCHED_AUX_YIELD_DATA(esdp, ets_all);
if (eaydp->ongoing) {
@@ -636,15 +661,42 @@ static ERTS_INLINE void db_unlock(DbTable* tb, db_lock_kind_t kind)
}
}
+static ERTS_INLINE int db_is_exclusive(DbTable* tb, db_lock_kind_t kind)
+{
+ return kind != LCK_READ && tb->common.is_thread_safe;
+}
+
+static DbTable* handle_lacking_permission(Process* p, DbTable* tb,
+ db_lock_kind_t kind,
+ Uint* freason_p)
+{
+ if (tb->common.status & DB_BUSY) {
+ if (!db_is_exclusive(tb, kind)) {
+ db_unlock(tb, kind);
+ db_lock(tb, LCK_WRITE);
+ }
+ delete_all_objects_continue(p, tb);
+ db_unlock(tb, LCK_WRITE);
+ tb = NULL;
+ *freason_p = TRAP;
+ }
+ else if (p->common.id != tb->common.owner) {
+ db_unlock(tb, kind);
+ tb = NULL;
+ *freason_p = BADARG;
+ }
+ return tb;
+}
+
static ERTS_INLINE
DbTable* db_get_table_aux(Process *p,
Eterm id,
int what,
db_lock_kind_t kind,
- int meta_already_locked)
+ int meta_already_locked,
+ Uint* freason_p)
{
DbTable *tb;
- erts_rwmtx_t *mtl = NULL;
/*
* IMPORTANT: Only scheduler threads are allowed
@@ -654,13 +706,13 @@ DbTable* db_get_table_aux(Process *p,
ASSERT(erts_get_scheduler_data());
if (is_atom(id)) {
+ erts_rwmtx_t *mtl;
struct meta_name_tab_entry* bucket = meta_name_tab_bucket(id,&mtl);
if (!meta_already_locked)
erts_rwmtx_rlock(mtl);
else{
ERTS_LC_ASSERT(erts_lc_rwmtx_is_rlocked(mtl)
|| erts_lc_rwmtx_is_rwlocked(mtl));
- mtl = NULL;
}
tb = NULL;
if (bucket->pu.tb != NULL) {
@@ -679,20 +731,29 @@ DbTable* db_get_table_aux(Process *p,
}
}
}
+ if (!meta_already_locked)
+ erts_rwmtx_runlock(mtl);
}
else
tb = tid2tab(id);
if (tb) {
db_lock(tb, kind);
- if ((tb->common.status & what) == 0
- && p->common.id != tb->common.owner) {
- db_unlock(tb, kind);
- tb = NULL;
- }
+#ifdef ETS_DBG_FORCE_TRAP
+ if (erts_atomic_read_nob(&tb->common.dbg_force_trap) &&
+ erts_atomic_add_read_nob(&tb->common.dbg_force_trap, 2) & 2) {
+ db_unlock(tb, kind);
+ tb = NULL;
+ *freason_p = TRAP;
+ }
+ else
+#endif
+ if (ERTS_UNLIKELY(!(tb->common.status & what)))
+ tb = handle_lacking_permission(p, tb, kind, freason_p);
}
- if (mtl)
- erts_rwmtx_runlock(mtl);
+ else
+ *freason_p = BADARG;
+
return tb;
}
@@ -700,9 +761,10 @@ static ERTS_INLINE
DbTable* db_get_table(Process *p,
Eterm id,
int what,
- db_lock_kind_t kind)
+ db_lock_kind_t kind,
+ Uint* freason_p)
{
- return db_get_table_aux(p, id, what, kind, 0);
+ return db_get_table_aux(p, id, what, kind, 0, freason_p);
}
static int insert_named_tab(Eterm name_atom, DbTable* tb, int have_lock)
@@ -868,9 +930,7 @@ BIF_RETTYPE ets_safe_fixtable_2(BIF_ALIST_2)
#endif
kind = (BIF_ARG_2 == am_true) ? LCK_READ : LCK_WRITE_REC;
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, kind)) == NULL) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ DB_BIF_GET_TABLE(tb, DB_READ, kind, BIF_ets_safe_fixtable_2);
if (BIF_ARG_2 == am_true) {
fix_table_locked(BIF_P, tb);
@@ -900,11 +960,7 @@ BIF_RETTYPE ets_first_1(BIF_ALIST_1)
CHECK_TABLES();
- tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_READ);
-
- if (!tb) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ DB_BIF_GET_TABLE(tb, DB_READ, LCK_READ, BIF_ets_first_1);
cret = tb->common.meth->db_first(BIF_P, tb, &ret);
@@ -927,11 +983,7 @@ BIF_RETTYPE ets_next_2(BIF_ALIST_2)
CHECK_TABLES();
- tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_READ);
-
- if (!tb) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ DB_BIF_GET_TABLE(tb, DB_READ, LCK_READ, BIF_ets_next_2);
cret = tb->common.meth->db_next(BIF_P, tb, BIF_ARG_2, &ret);
@@ -954,11 +1006,7 @@ BIF_RETTYPE ets_last_1(BIF_ALIST_1)
CHECK_TABLES();
- tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_READ);
-
- if (!tb) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ DB_BIF_GET_TABLE(tb, DB_READ, LCK_READ, BIF_ets_last_1);
cret = tb->common.meth->db_last(BIF_P, tb, &ret);
@@ -981,11 +1029,7 @@ BIF_RETTYPE ets_prev_2(BIF_ALIST_2)
CHECK_TABLES();
- tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_READ);
-
- if (!tb) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ DB_BIF_GET_TABLE(tb, DB_READ, LCK_READ, BIF_ets_prev_2);
cret = tb->common.meth->db_prev(BIF_P,tb,BIF_ARG_2,&ret);
@@ -1003,21 +1047,15 @@ BIF_RETTYPE ets_prev_2(BIF_ALIST_2)
BIF_RETTYPE ets_take_2(BIF_ALIST_2)
{
DbTable* tb;
-#ifdef DEBUG
int cret;
-#endif
Eterm ret;
CHECK_TABLES();
- tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE_REC);
- if (!tb) {
- BIF_ERROR(BIF_P, BADARG);
- }
-#ifdef DEBUG
- cret =
-#endif
- tb->common.meth->db_take(BIF_P, tb, BIF_ARG_2, &ret);
- ASSERT(cret == DB_ERROR_NONE);
+ DB_BIF_GET_TABLE(tb, DB_WRITE, LCK_WRITE_REC, BIF_ets_take_2);
+
+ cret = tb->common.meth->db_take(BIF_P, tb, BIF_ARG_2, &ret);
+
+ ASSERT(cret == DB_ERROR_NONE); (void)cret;
db_unlock(tb, LCK_WRITE_REC);
BIF_RET(ret);
}
@@ -1035,9 +1073,8 @@ BIF_RETTYPE ets_update_element_3(BIF_ALIST_3)
DeclareTmpHeap(cell,2,BIF_P);
DbUpdateHandle handle;
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE_REC)) == NULL) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ DB_BIF_GET_TABLE(tb, DB_WRITE, LCK_WRITE_REC, BIF_ets_update_element_3);
+
UseTmpHeap(2,BIF_P);
if (!(tb->common.status & (DB_SET | DB_ORDERED_SET))) {
goto bail_out;
@@ -1108,9 +1145,9 @@ bail_out:
}
static BIF_RETTYPE
-do_update_counter(Process *p, Eterm arg1, Eterm arg2, Eterm arg3, Eterm arg4)
+do_update_counter(Process *p, DbTable* tb,
+ Eterm arg2, Eterm arg3, Eterm arg4)
{
- DbTable* tb;
int cret = DB_ERROR_BADITEM;
Eterm upop_list;
int list_size;
@@ -1126,10 +1163,6 @@ do_update_counter(Process *p, Eterm arg1, Eterm arg2, Eterm arg3, Eterm arg4)
Eterm* hstart;
Eterm* hend;
- if ((tb = db_get_table(p, arg1, DB_WRITE, LCK_WRITE_REC)) == NULL) {
- BIF_ERROR(p, BADARG);
- }
-
UseTmpHeap(5, p);
if (!(tb->common.status & (DB_SET | DB_ORDERED_SET))) {
@@ -1303,7 +1336,11 @@ bail_out:
*/
BIF_RETTYPE ets_update_counter_3(BIF_ALIST_3)
{
- return do_update_counter(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3, THE_NON_VALUE);
+ DbTable* tb;
+
+ DB_BIF_GET_TABLE(tb, DB_WRITE, LCK_WRITE_REC, BIF_ets_update_counter_3);
+
+ return do_update_counter(BIF_P, tb, BIF_ARG_2, BIF_ARG_3, THE_NON_VALUE);
}
/*
@@ -1315,10 +1352,14 @@ BIF_RETTYPE ets_update_counter_3(BIF_ALIST_3)
*/
BIF_RETTYPE ets_update_counter_4(BIF_ALIST_4)
{
+ DbTable* tb;
+
if (is_not_tuple(BIF_ARG_4)) {
BIF_ERROR(BIF_P, BADARG);
}
- return do_update_counter(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3, BIF_ARG_4);
+ DB_BIF_GET_TABLE(tb, DB_WRITE, LCK_WRITE_REC, BIF_ets_update_counter_4);
+
+ return do_update_counter(BIF_P, tb, BIF_ARG_2, BIF_ARG_3, BIF_ARG_4);
}
@@ -1339,9 +1380,8 @@ BIF_RETTYPE ets_insert_2(BIF_ALIST_2)
kind = ((is_list(BIF_ARG_2) && CDR(list_val(BIF_ARG_2)) != NIL)
? LCK_WRITE : LCK_WRITE_REC);
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, kind)) == NULL) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ DB_BIF_GET_TABLE(tb, DB_WRITE, kind, BIF_ets_insert_2);
+
if (BIF_ARG_2 == NIL) {
db_unlock(tb, kind);
BIF_RET(am_true);
@@ -1407,11 +1447,9 @@ BIF_RETTYPE ets_insert_new_2(BIF_ALIST_2)
/* More than one object, use LCK_WRITE to keep atomicity */
kind = LCK_WRITE;
- tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, kind);
- if (tb == NULL) {
- BIF_ERROR(BIF_P, BADARG);
- }
- meth = tb->common.meth;
+ DB_BIF_GET_TABLE(tb, DB_WRITE, kind, BIF_ets_insert_new_2);
+
+ meth = tb->common.meth;
for (lst = BIF_ARG_2; is_list(lst); lst = CDR(list_val(lst))) {
if (is_not_tuple(CAR(list_val(lst)))
|| (arityval(*tuple_val(CAR(list_val(lst))))
@@ -1446,9 +1484,8 @@ BIF_RETTYPE ets_insert_new_2(BIF_ALIST_2)
/* Only one object (or NIL)
*/
kind = LCK_WRITE_REC;
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, kind)) == NULL) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ DB_BIF_GET_TABLE(tb, DB_WRITE, kind, BIF_ets_insert_new_2);
+
if (BIF_ARG_2 == NIL) {
db_unlock(tb, kind);
BIF_RET(am_true);
@@ -1487,6 +1524,7 @@ BIF_RETTYPE ets_rename_2(BIF_ALIST_2)
Eterm ret;
Eterm old_name;
erts_rwmtx_t *lck1, *lck2;
+ Uint freason;
#ifdef HARDDEBUG
erts_fprintf(stderr,
@@ -1531,9 +1569,9 @@ BIF_RETTYPE ets_rename_2(BIF_ALIST_2)
if (lck2)
erts_rwmtx_rwlock(lck2);
- tb = db_get_table_aux(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE, 1);
+ tb = db_get_table_aux(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE, 1, &freason);
if (!tb)
- goto badarg;
+ goto fail;
if (is_table_named(tb)) {
if (!insert_named_tab(BIF_ARG_2, tb, 1))
@@ -1553,13 +1591,18 @@ BIF_RETTYPE ets_rename_2(BIF_ALIST_2)
if (lck2)
erts_rwmtx_rwunlock(lck2);
BIF_RET(ret);
- badarg:
+
+badarg:
+ freason = BADARG;
+
+fail:
if (tb)
db_unlock(tb, LCK_WRITE);
erts_rwmtx_rwunlock(lck1);
if (lck2)
erts_rwmtx_rwunlock(lck2);
- BIF_ERROR(BIF_P, BADARG);
+
+ return db_bif_fail(BIF_P, freason, BIF_ets_rename_2, NULL);
}
@@ -1580,9 +1623,7 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
Sint keypos;
int is_named, is_compressed;
int is_fine_locked, frequent_read;
-#ifdef DEBUG
int cret;
-#endif
DbTableMethod* meth;
if (is_not_atom(BIF_ARG_1)) {
@@ -1708,7 +1749,7 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
tb->common.meth = meth;
tb->common.the_name = BIF_ARG_1;
tb->common.status = status;
- tb->common.type = status & ERTS_ETS_TABLE_TYPES;
+ tb->common.type = status;
/* Note, 'type' is *read only* from now on... */
erts_refc_init(&tb->common.fix_count, 0);
db_init_lock(tb, status & (DB_FINE_LOCKED|DB_FREQ_READ));
@@ -1720,12 +1761,12 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
tb->common.fixing_procs = NULL;
tb->common.compress = is_compressed;
-
-#ifdef DEBUG
- cret =
+#ifdef ETS_DBG_FORCE_TRAP
+ erts_atomic_init_nob(&tb->common.dbg_force_trap, erts_ets_dbg_force_trap);
#endif
- meth->db_create(BIF_P, tb);
- ASSERT(cret == DB_ERROR_NONE);
+
+ cret = meth->db_create(BIF_P, tb);
+ ASSERT(cret == DB_ERROR_NONE); (void)cret;
make_btid(tb);
@@ -1735,20 +1776,21 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
ret = make_tid(BIF_P, tb);
save_sched_table(BIF_P, tb);
+ save_owned_table(BIF_P, tb);
if (is_named && !insert_named_tab(BIF_ARG_1, tb, 0)) {
tid_clear(BIF_P, tb);
+ delete_owned_table(BIF_P, tb);
db_lock(tb,LCK_WRITE);
free_heir_data(tb);
- tb->common.meth->db_free_table(tb);
+ tb->common.meth->db_free_empty_table(tb);
db_unlock(tb,LCK_WRITE);
table_dec_refc(tb, 0);
BIF_ERROR(BIF_P, BADARG);
}
BIF_P->flags |= F_USING_DB; /* So we can remove tb if p dies */
- save_owned_table(BIF_P, tb);
#ifdef HARDDEBUG
erts_fprintf(stderr,
@@ -1767,13 +1809,19 @@ BIF_RETTYPE ets_whereis_1(BIF_ALIST_1)
{
DbTable* tb;
Eterm res;
+ Uint freason;
if (is_not_atom(BIF_ARG_1)) {
BIF_ERROR(BIF_P, BADARG);
}
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_INFO, LCK_READ)) == NULL) {
- BIF_RET(am_undefined);
+ if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_INFO, LCK_READ, &freason)) == NULL) {
+ if (freason == BADARG)
+ BIF_RET(am_undefined);
+ else {
+ //ToDo: Could we avoid this
+ return db_bif_fail(BIF_P, freason, BIF_ets_whereis_1, NULL);
+ }
}
res = make_tid(BIF_P, tb);
@@ -1793,9 +1841,7 @@ BIF_RETTYPE ets_lookup_2(BIF_ALIST_2)
CHECK_TABLES();
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_READ)) == NULL) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ DB_BIF_GET_TABLE(tb, DB_READ, LCK_READ, BIF_ets_lookup_2);
cret = tb->common.meth->db_get(BIF_P, tb, BIF_ARG_2, &ret);
@@ -1823,9 +1869,7 @@ BIF_RETTYPE ets_member_2(BIF_ALIST_2)
CHECK_TABLES();
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_READ)) == NULL) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ DB_BIF_GET_TABLE(tb, DB_READ, LCK_READ, BIF_ets_member_2);
cret = tb->common.meth->db_member(tb, BIF_ARG_2, &ret);
@@ -1856,9 +1900,7 @@ BIF_RETTYPE ets_lookup_element_3(BIF_ALIST_3)
CHECK_TABLES();
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_READ)) == NULL) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ DB_BIF_GET_TABLE(tb, DB_READ, LCK_READ, BIF_ets_lookup_element_3);
if (is_not_small(BIF_ARG_3) || ((index = signed_val(BIF_ARG_3)) < 1)) {
db_unlock(tb, LCK_READ);
@@ -1896,9 +1938,7 @@ BIF_RETTYPE ets_delete_1(BIF_ALIST_1)
CHECK_TABLES();
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE)) == NULL) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ DB_BIF_GET_TABLE(tb, DB_WRITE, LCK_WRITE, BIF_ets_delete_1);
/*
* Clear all access bits to prevent any ets operation to access the
@@ -1929,8 +1969,6 @@ BIF_RETTYPE ets_delete_1(BIF_ALIST_1)
save_owned_table(BIF_P, tb);
}
- tid_clear(BIF_P, tb);
-
if (is_table_named(tb))
remove_named_tab(tb, 0);
@@ -1939,9 +1977,11 @@ BIF_RETTYPE ets_delete_1(BIF_ALIST_1)
tb->common.heir = am_none;
reds -= free_fixations_locked(BIF_P, tb);
+ tid_clear(BIF_P, tb);
db_unlock(tb, LCK_WRITE);
- if (free_table_continue(BIF_P, tb, reds) < 0) {
+ reds = free_table_continue(BIF_P, tb, reds);
+ if (reds < 0) {
/*
* Package the DbTable* pointer into a bignum so that it can be safely
* passed through a trap. We used to pass the DbTable* pointer directly
@@ -1970,6 +2010,7 @@ BIF_RETTYPE ets_give_away_3(BIF_ALIST_3)
Eterm to_pid = BIF_ARG_2;
Eterm from_pid;
DbTable* tb = NULL;
+ Uint freason;
if (!is_internal_pid(to_pid)) {
goto badarg;
@@ -1979,10 +2020,11 @@ BIF_RETTYPE ets_give_away_3(BIF_ALIST_3)
goto badarg;
}
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE)) == NULL
- || tb->common.owner != BIF_P->common.id) {
- goto badarg;
- }
+ if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE, &freason)) == NULL)
+ goto fail;
+ if (tb->common.owner != BIF_P->common.id)
+ goto badarg;
+
from_pid = tb->common.owner;
if (to_pid == from_pid) {
goto badarg; /* or should we be idempotent? return false maybe */
@@ -2001,9 +2043,12 @@ BIF_RETTYPE ets_give_away_3(BIF_ALIST_3)
BIF_RET(am_true);
badarg:
+ freason = BADARG;
+fail:
if (to_proc != NULL && to_proc != BIF_P) erts_proc_unlock(to_proc, to_locks);
if (tb != NULL) db_unlock(tb, LCK_WRITE);
- BIF_ERROR(BIF_P, BADARG);
+
+ return db_bif_fail(BIF_P, freason, BIF_ets_give_away_3, NULL);
}
BIF_RETTYPE ets_setopts_2(BIF_ALIST_2)
@@ -2054,11 +2099,13 @@ BIF_RETTYPE ets_setopts_2(BIF_ALIST_2)
}
}
- if (tail != NIL
- || (tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE)) == NULL
- || tb->common.owner != BIF_P->common.id) {
+ if (tail != NIL)
+ goto badarg;
+
+ DB_BIF_GET_TABLE(tb, DB_WRITE, LCK_WRITE, BIF_ets_setopts_2);
+
+ if (tb->common.owner != BIF_P->common.id)
goto badarg;
- }
if (heir_data != THE_NON_VALUE) {
free_heir_data(tb);
@@ -2082,23 +2129,84 @@ badarg:
}
/*
-** BIF to erase a whole table and release all memory it holds
-*/
-BIF_RETTYPE ets_delete_all_objects_1(BIF_ALIST_1)
+ * Common for delete_all_objects and select_delete(DeleteAll).
+ */
+BIF_RETTYPE ets_internal_delete_all_2(BIF_ALIST_2)
{
+ SWord initial_reds = ERTS_BIF_REDS_LEFT(BIF_P);
+ SWord reds = initial_reds;
+ Eterm nitems;
DbTable* tb;
CHECK_TABLES();
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE)) == NULL) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ DB_BIF_GET_TABLE(tb, DB_WRITE, LCK_WRITE, BIF_ets_internal_delete_all_2);
+
+ if (BIF_ARG_2 == am_undefined) {
+ nitems = erts_make_integer(erts_atomic_read_nob(&tb->common.nitems),
+ BIF_P);
+
+ reds = tb->common.meth->db_delete_all_objects(BIF_P, tb, reds);
- tb->common.meth->db_delete_all_objects(BIF_P, tb);
+ ASSERT(!(tb->common.status & DB_BUSY));
+
+ if (reds < 0) {
+ /*
+ * Oboy, need to trap AND need to be atomic.
+ * Solved by cooperative trapping where every process trying to
+ * access this table (including this process) will "fail" to lookup
+ * the table and instead pitch in deleting objects
+ * (in delete_all_objects_continue) and then trap to self.
+ */
+ ASSERT((tb->common.status & (DB_PRIVATE|DB_PROTECTED|DB_PUBLIC))
+ ==
+ (tb->common.type & (DB_PRIVATE|DB_PROTECTED|DB_PUBLIC)));
+ tb->common.status &= ~(DB_PRIVATE|DB_PROTECTED|DB_PUBLIC);
+ tb->common.status |= DB_BUSY;
+ db_unlock(tb, LCK_WRITE);
+ BUMP_ALL_REDS(BIF_P);
+ BIF_TRAP2(bif_export[BIF_ets_internal_delete_all_2], BIF_P,
+ BIF_ARG_1, nitems);
+ }
+ else {
+ /* Done, no trapping needed */
+ BUMP_REDS(BIF_P, (initial_reds - reds));
+ }
+
+ }
+ else {
+ /*
+ * The table lookup succeeded and second argument is nitems
+ * and not 'undefined', which means we have trapped at least once
+ * and are now done.
+ */
+ nitems = BIF_ARG_2;
+ }
db_unlock(tb, LCK_WRITE);
+ BIF_RET(nitems);
+}
- BIF_RET(am_true);
+static void delete_all_objects_continue(Process* p, DbTable* tb)
+{
+ SWord initial_reds = ERTS_BIF_REDS_LEFT(p);
+ SWord reds = initial_reds;
+
+ ERTS_LC_ASSERT(erts_lc_rwmtx_is_rwlocked(&tb->common.rwlock));
+
+ if ((tb->common.status & (DB_DELETE|DB_BUSY)) != DB_BUSY)
+ return;
+
+ reds = tb->common.meth->db_delete_all_objects(p, tb, reds);
+
+ if (reds < 0) {
+ BUMP_ALL_REDS(p);
+ }
+ else {
+ tb->common.status |= tb->common.type & (DB_PRIVATE|DB_PROTECTED|DB_PUBLIC);
+ tb->common.status &= ~DB_BUSY;
+ BUMP_REDS(p, (initial_reds - reds));
+ }
}
/*
@@ -2114,9 +2222,7 @@ BIF_RETTYPE ets_delete_2(BIF_ALIST_2)
CHECK_TABLES();
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE_REC)) == NULL) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ DB_BIF_GET_TABLE(tb, DB_WRITE, LCK_WRITE_REC, BIF_ets_delete_2);
cret = tb->common.meth->db_erase(tb,BIF_ARG_2,&ret);
@@ -2143,9 +2249,8 @@ BIF_RETTYPE ets_delete_object_2(BIF_ALIST_2)
CHECK_TABLES();
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE_REC)) == NULL) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ DB_BIF_GET_TABLE(tb, DB_WRITE, LCK_WRITE_REC, BIF_ets_delete_object_2);
+
if (is_not_tuple(BIF_ARG_2) ||
(arityval(*tuple_val(BIF_ARG_2)) < tb->common.keypos)) {
db_unlock(tb, LCK_WRITE_REC);
@@ -2168,7 +2273,7 @@ BIF_RETTYPE ets_delete_object_2(BIF_ALIST_2)
/*
** This is for trapping, cannot be called directly.
*/
-static BIF_RETTYPE ets_select_delete_1(BIF_ALIST_1)
+static BIF_RETTYPE ets_select_delete_trap_1(BIF_ALIST_1)
{
Process *p = BIF_P;
Eterm a1 = BIF_ARG_1;
@@ -2178,15 +2283,14 @@ static BIF_RETTYPE ets_select_delete_1(BIF_ALIST_1)
Eterm ret;
Eterm *tptr;
db_lock_kind_t kind = LCK_WRITE_REC;
-
+
CHECK_TABLES();
ASSERT(is_tuple(a1));
tptr = tuple_val(a1);
ASSERT(arityval(*tptr) >= 1);
- if ((tb = db_get_table(p, tptr[1], DB_WRITE, kind)) == NULL) {
- BIF_ERROR(p,BADARG);
- }
+ DB_TRAP_GET_TABLE(tb, tptr[1], DB_WRITE, kind,
+ &ets_select_delete_continue_exp);
cret = tb->common.meth->db_select_delete_continue(p,tb,a1,&ret);
@@ -2210,7 +2314,10 @@ static BIF_RETTYPE ets_select_delete_1(BIF_ALIST_1)
}
-BIF_RETTYPE ets_select_delete_2(BIF_ALIST_2)
+/*
+ * ets:select_delete/2 without special case for "delete-all".
+ */
+BIF_RETTYPE ets_internal_select_delete_2(BIF_ALIST_2)
{
BIF_RETTYPE result;
DbTable* tb;
@@ -2220,20 +2327,8 @@ BIF_RETTYPE ets_select_delete_2(BIF_ALIST_2)
CHECK_TABLES();
- if(eq(BIF_ARG_2, ms_delete_all)) {
- int nitems;
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE)) == NULL) {
- BIF_ERROR(BIF_P, BADARG);
- }
- nitems = erts_atomic_read_nob(&tb->common.nitems);
- tb->common.meth->db_delete_all_objects(BIF_P, tb);
- db_unlock(tb, LCK_WRITE);
- BIF_RET(erts_make_integer(nitems,BIF_P));
- }
+ DB_BIF_GET_TABLE(tb, DB_WRITE, LCK_WRITE_REC, BIF_ets_internal_select_delete_2);
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE_REC)) == NULL) {
- BIF_ERROR(BIF_P, BADARG);
- }
safety = ITERATION_SAFETY(BIF_P,tb);
if (safety == ITER_UNSAFE) {
local_fix_table(tb);
@@ -2350,7 +2445,7 @@ ets_all_reply(ErtsSchedulerData *esdp, ErtsEtsAllReq **reqpp,
ASSERT(!*tablepp);
/* Max heap size needed... */
- sz = esdp->ets_tables.count;
+ sz = erts_atomic_read_nob(&esdp->ets_tables.count);
sz *= ERTS_MAGIC_REF_THING_SIZE + 2;
sz += 3 + ERTS_REF_THING_SIZE;
hfragp = new_message_buffer(sz);
@@ -2434,7 +2529,8 @@ erts_handle_yielded_ets_all_request(ErtsSchedulerData *esdp,
if (!eaydp->queue)
return 0; /* All work completed! */
- if (yc < ERTS_ETS_ALL_TB_YCNT_START && yc > esdp->ets_tables.count)
+ if (yc < ERTS_ETS_ALL_TB_YCNT_START &&
+ yc > erts_atomic_read_nob(&esdp->ets_tables.count))
return 1; /* Yield! */
eaydp->ongoing = ongoing = eaydp->queue;
@@ -2513,7 +2609,6 @@ BIF_RETTYPE ets_internal_request_all_0(BIF_ALIST_0)
BIF_RET(ref);
}
-
/*
** db_slot(Db, Slot) -> [Items].
*/
@@ -2525,9 +2620,8 @@ BIF_RETTYPE ets_slot_2(BIF_ALIST_2)
CHECK_TABLES();
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_READ)) == NULL) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ DB_BIF_GET_TABLE(tb, DB_READ, LCK_READ, BIF_ets_slot_2);
+
/* The slot number is checked in table specific code. */
cret = tb->common.meth->db_slot(BIF_P, tb, BIF_ARG_2, &ret);
db_unlock(tb, LCK_READ);
@@ -2547,41 +2641,53 @@ BIF_RETTYPE ets_slot_2(BIF_ALIST_2)
BIF_RETTYPE ets_match_1(BIF_ALIST_1)
{
- return ets_select1(BIF_P, BIF_ARG_1);
+ return ets_select1(BIF_P, BIF_ets_match_1, BIF_ARG_1);
}
BIF_RETTYPE ets_match_2(BIF_ALIST_2)
{
+ DbTable* tb;
Eterm ms;
DeclareTmpHeap(buff,8,BIF_P);
Eterm *hp = buff;
Eterm res;
+ DB_BIF_GET_TABLE(tb, DB_READ, LCK_READ, BIF_ets_match_2);
+
UseTmpHeap(8,BIF_P);
ms = CONS(hp, am_DollarDollar, NIL);
hp += 2;
ms = TUPLE3(hp, BIF_ARG_2, NIL, ms);
hp += 4;
ms = CONS(hp, ms, NIL);
- res = ets_select2(BIF_P, BIF_ARG_1, ms);
+ res = ets_select2(BIF_P, tb, BIF_ARG_1, ms);
UnUseTmpHeap(8,BIF_P);
return res;
}
BIF_RETTYPE ets_match_3(BIF_ALIST_3)
{
+ DbTable* tb;
Eterm ms;
+ Sint chunk_size;
DeclareTmpHeap(buff,8,BIF_P);
Eterm *hp = buff;
Eterm res;
+ /* Chunk size strictly greater than 0 */
+ if (is_not_small(BIF_ARG_3) || (chunk_size = signed_val(BIF_ARG_3)) <= 0) {
+ BIF_ERROR(BIF_P, BADARG);
+ }
+
+ DB_BIF_GET_TABLE(tb, DB_READ, LCK_READ, BIF_ets_match_3);
+
UseTmpHeap(8,BIF_P);
ms = CONS(hp, am_DollarDollar, NIL);
hp += 2;
ms = TUPLE3(hp, BIF_ARG_2, NIL, ms);
hp += 4;
ms = CONS(hp, ms, NIL);
- res = ets_select3(BIF_P, BIF_ARG_1, ms, BIF_ARG_3);
+ res = ets_select3(BIF_P, tb, BIF_ARG_1, ms, chunk_size);
UnUseTmpHeap(8,BIF_P);
return res;
}
@@ -2589,34 +2695,35 @@ BIF_RETTYPE ets_match_3(BIF_ALIST_3)
BIF_RETTYPE ets_select_3(BIF_ALIST_3)
{
- return ets_select3(BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3);
+ DbTable* tb;
+ Sint chunk_size;
+
+ /* Chunk size strictly greater than 0 */
+ if (is_not_small(BIF_ARG_3) || (chunk_size = signed_val(BIF_ARG_3)) <= 0) {
+ BIF_ERROR(BIF_P, BADARG);
+ }
+
+ DB_BIF_GET_TABLE(tb, DB_READ, LCK_READ, BIF_ets_select_3);
+
+ return ets_select3(BIF_P, tb, BIF_ARG_1, BIF_ARG_2, chunk_size);
}
static BIF_RETTYPE
-ets_select3(Process* p, Eterm arg1, Eterm arg2, Eterm arg3)
+ets_select3(Process* p, DbTable* tb, Eterm tid, Eterm ms, Sint chunk_size)
{
BIF_RETTYPE result;
- DbTable* tb;
int cret;
Eterm ret;
- Sint chunk_size;
enum DbIterSafety safety;
CHECK_TABLES();
- /* Chunk size strictly greater than 0 */
- if (is_not_small(arg3) || (chunk_size = signed_val(arg3)) <= 0) {
- BIF_ERROR(p, BADARG);
- }
- if ((tb = db_get_table(p, arg1, DB_READ, LCK_READ)) == NULL) {
- BIF_ERROR(p, BADARG);
- }
safety = ITERATION_SAFETY(p,tb);
if (safety == ITER_UNSAFE) {
local_fix_table(tb);
}
- cret = tb->common.meth->db_select_chunk(p, tb, arg1,
- arg2, chunk_size,
+ cret = tb->common.meth->db_select_chunk(p, tb, tid,
+ ms, chunk_size,
0 /* not reversed */,
&ret);
if (DID_TRAP(p,ret) && safety != ITER_SAFE) {
@@ -2662,9 +2769,8 @@ static BIF_RETTYPE ets_select_trap_1(BIF_ALIST_1)
tptr = tuple_val(a1);
ASSERT(arityval(*tptr) >= 1);
- if ((tb = db_get_table(p, tptr[1], DB_READ, kind)) == NULL) {
- BIF_ERROR(p, BADARG);
- }
+ DB_TRAP_GET_TABLE(tb, tptr[1], DB_READ, kind,
+ &ets_select_continue_exp);
cret = tb->common.meth->db_select_continue(p, tb, a1,
&ret);
@@ -2694,10 +2800,10 @@ static BIF_RETTYPE ets_select_trap_1(BIF_ALIST_1)
BIF_RETTYPE ets_select_1(BIF_ALIST_1)
{
- return ets_select1(BIF_P, BIF_ARG_1);
+ return ets_select1(BIF_P, BIF_ets_select_1, BIF_ARG_1);
}
-static BIF_RETTYPE ets_select1(Process *p, Eterm arg1)
+static BIF_RETTYPE ets_select1(Process *p, int bif_ix, Eterm arg1)
{
BIF_RETTYPE result;
DbTable* tb;
@@ -2719,10 +2825,10 @@ static BIF_RETTYPE ets_select1(Process *p, Eterm arg1)
BIF_ERROR(p, BADARG);
}
tptr = tuple_val(arg1);
- if (arityval(*tptr) < 1 ||
- (tb = db_get_table(p, tptr[1], DB_READ, LCK_READ)) == NULL) {
- BIF_ERROR(p, BADARG);
- }
+ if (arityval(*tptr) < 1)
+ BIF_ERROR(p, BADARG);
+
+ DB_GET_TABLE(tb, tptr[1], DB_READ, LCK_READ, bif_ix, NULL, p);
safety = ITERATION_SAFETY(p,tb);
if (safety == ITER_UNSAFE) {
@@ -2758,33 +2864,27 @@ static BIF_RETTYPE ets_select1(Process *p, Eterm arg1)
BIF_RETTYPE ets_select_2(BIF_ALIST_2)
{
- return ets_select2(BIF_P, BIF_ARG_1, BIF_ARG_2);
+ DbTable* tb;
+ DB_BIF_GET_TABLE(tb, DB_READ, LCK_READ, BIF_ets_select_2);
+ return ets_select2(BIF_P, tb, BIF_ARG_1, BIF_ARG_2);
}
static BIF_RETTYPE
-ets_select2(Process* p, Eterm arg1, Eterm arg2)
+ets_select2(Process* p, DbTable* tb, Eterm tid, Eterm ms)
{
BIF_RETTYPE result;
- DbTable* tb;
int cret;
enum DbIterSafety safety;
Eterm ret;
CHECK_TABLES();
- /*
- * Make sure that the table exists.
- */
-
- if ((tb = db_get_table(p, arg1, DB_READ, LCK_READ)) == NULL) {
- BIF_ERROR(p, BADARG);
- }
safety = ITERATION_SAFETY(p,tb);
if (safety == ITER_UNSAFE) {
local_fix_table(tb);
}
- cret = tb->common.meth->db_select(p, tb, arg1, arg2, 0, &ret);
+ cret = tb->common.meth->db_select(p, tb, tid, ms, 0, &ret);
if (DID_TRAP(p,ret) && safety != ITER_SAFE) {
fix_table_locked(p, tb);
@@ -2827,9 +2927,9 @@ static BIF_RETTYPE ets_select_count_1(BIF_ALIST_1)
tptr = tuple_val(a1);
ASSERT(arityval(*tptr) >= 1);
- if ((tb = db_get_table(p, tptr[1], DB_READ, kind)) == NULL) {
- BIF_ERROR(p, BADARG);
- }
+
+ DB_TRAP_GET_TABLE(tb, tptr[1], DB_READ, kind,
+ &ets_select_count_continue_exp);
cret = tb->common.meth->db_select_count_continue(p, tb, a1, &ret);
@@ -2864,13 +2964,9 @@ BIF_RETTYPE ets_select_count_2(BIF_ALIST_2)
Eterm ret;
CHECK_TABLES();
- /*
- * Make sure that the table exists.
- */
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_READ)) == NULL) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ DB_BIF_GET_TABLE(tb, DB_READ, LCK_READ, BIF_ets_select_count_2);
+
safety = ITERATION_SAFETY(BIF_P,tb);
if (safety == ITER_UNSAFE) {
local_fix_table(tb);
@@ -2920,9 +3016,8 @@ static BIF_RETTYPE ets_select_replace_1(BIF_ALIST_1)
tptr = tuple_val(a1);
ASSERT(arityval(*tptr) >= 1);
- if ((tb = db_get_table(p, tptr[1], DB_WRITE, kind)) == NULL) {
- BIF_ERROR(p,BADARG);
- }
+ DB_TRAP_GET_TABLE(tb, tptr[1], DB_WRITE, kind,
+ &ets_select_replace_continue_exp);
cret = tb->common.meth->db_select_replace_continue(p,tb,a1,&ret);
@@ -2956,9 +3051,7 @@ BIF_RETTYPE ets_select_replace_2(BIF_ALIST_2)
CHECK_TABLES();
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_WRITE, LCK_WRITE_REC)) == NULL) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ DB_BIF_GET_TABLE(tb, DB_WRITE, LCK_WRITE_REC, BIF_ets_select_replace_2);
if (tb->common.status & DB_BAG) {
/* Bag implementation presented both semantic consistency
@@ -3009,13 +3102,8 @@ BIF_RETTYPE ets_select_reverse_3(BIF_ALIST_3)
Sint chunk_size;
CHECK_TABLES();
- /*
- * Make sure that the table exists.
- */
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_READ)) == NULL) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ DB_BIF_GET_TABLE(tb, DB_READ, LCK_READ, BIF_ets_select_reverse_3);
/* Chunk size strictly greater than 0 */
if (is_not_small(BIF_ARG_3) || (chunk_size = signed_val(BIF_ARG_3)) <= 0) {
@@ -3053,7 +3141,7 @@ BIF_RETTYPE ets_select_reverse_3(BIF_ALIST_3)
BIF_RETTYPE ets_select_reverse_1(BIF_ALIST_1)
{
- return ets_select1(BIF_P, BIF_ARG_1);
+ return ets_select1(BIF_P, BIF_ets_select_reverse_1, BIF_ARG_1);
}
BIF_RETTYPE ets_select_reverse_2(BIF_ALIST_2)
@@ -3065,13 +3153,9 @@ BIF_RETTYPE ets_select_reverse_2(BIF_ALIST_2)
Eterm ret;
CHECK_TABLES();
- /*
- * Make sure that the table exists.
- */
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_READ, LCK_READ)) == NULL) {
- BIF_ERROR(BIF_P, BADARG);
- }
+ DB_BIF_GET_TABLE(tb, DB_READ, LCK_READ, BIF_ets_select_reverse_2);
+
safety = ITERATION_SAFETY(BIF_P,tb);
if (safety == ITER_UNSAFE) {
local_fix_table(tb);
@@ -3103,45 +3187,63 @@ BIF_RETTYPE ets_select_reverse_2(BIF_ALIST_2)
/*
-** ets:match_object(Continuation), ets:match_object(Table, Pattern), ets:match_object(Table,Pattern,ChunkSize)
+** ets:match_object(Continuation)
*/
BIF_RETTYPE ets_match_object_1(BIF_ALIST_1)
{
- return ets_select1(BIF_P, BIF_ARG_1);
+ return ets_select1(BIF_P, BIF_ets_match_object_1, BIF_ARG_1);
}
+/*
+** ets:match_object(Table, Pattern)
+*/
BIF_RETTYPE ets_match_object_2(BIF_ALIST_2)
{
+ DbTable* tb;
Eterm ms;
DeclareTmpHeap(buff,8,BIF_P);
Eterm *hp = buff;
Eterm res;
+ DB_BIF_GET_TABLE(tb, DB_READ, LCK_READ, BIF_ets_match_object_2);
+
UseTmpHeap(8,BIF_P);
ms = CONS(hp, am_DollarUnderscore, NIL);
hp += 2;
ms = TUPLE3(hp, BIF_ARG_2, NIL, ms);
hp += 4;
ms = CONS(hp, ms, NIL);
- res = ets_select2(BIF_P, BIF_ARG_1, ms);
+ res = ets_select2(BIF_P, tb, BIF_ARG_1, ms);
UnUseTmpHeap(8,BIF_P);
return res;
}
+/*
+** ets:match_object(Table,Pattern,ChunkSize)
+*/
BIF_RETTYPE ets_match_object_3(BIF_ALIST_3)
{
+ DbTable* tb;
+ Sint chunk_size;
Eterm ms;
DeclareTmpHeap(buff,8,BIF_P);
Eterm *hp = buff;
Eterm res;
+ /* Chunk size strictly greater than 0 */
+ if (is_not_small(BIF_ARG_3) || (chunk_size = signed_val(BIF_ARG_3)) <= 0) {
+ BIF_ERROR(BIF_P, BADARG);
+ }
+
+ DB_BIF_GET_TABLE(tb, DB_READ, LCK_READ, BIF_ets_match_object_3);
+
UseTmpHeap(8,BIF_P);
ms = CONS(hp, am_DollarUnderscore, NIL);
hp += 2;
ms = TUPLE3(hp, BIF_ARG_2, NIL, ms);
hp += 4;
ms = CONS(hp, ms, NIL);
- res = ets_select3(BIF_P, BIF_ARG_1, ms, BIF_ARG_3);
+ res = ets_select3(BIF_P, tb, BIF_ARG_1, ms, chunk_size);
UnUseTmpHeap(8,BIF_P);
return res;
}
@@ -3162,16 +3264,17 @@ BIF_RETTYPE ets_info_1(BIF_ALIST_1)
Eterm res;
int i;
Eterm* hp;
+ Uint freason;
/*Process* rp = NULL;*/
/* If/when we implement lockless private tables:
Eterm owner;
*/
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_INFO, LCK_READ)) == NULL) {
- if (is_atom(BIF_ARG_1) || is_ref(BIF_ARG_1)) {
+ if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_INFO, LCK_READ, &freason)) == NULL) {
+ if (freason == BADARG && (is_atom(BIF_ARG_1) || is_ref(BIF_ARG_1)))
BIF_RET(am_undefined);
- }
- BIF_ERROR(BIF_P, BADARG);
+ else
+ return db_bif_fail(BIF_P, freason, BIF_ets_info_1, NULL);
}
/* If/when we implement lockless private tables:
@@ -3228,12 +3331,13 @@ BIF_RETTYPE ets_info_2(BIF_ALIST_2)
{
DbTable* tb;
Eterm ret = THE_NON_VALUE;
+ Uint freason;
- if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_INFO, LCK_READ)) == NULL) {
- if (is_atom(BIF_ARG_1) || is_ref(BIF_ARG_1)) {
+ if ((tb = db_get_table(BIF_P, BIF_ARG_1, DB_INFO, LCK_READ, &freason)) == NULL) {
+ if (freason == BADARG && (is_atom(BIF_ARG_1) || is_ref(BIF_ARG_1)))
BIF_RET(am_undefined);
- }
- BIF_ERROR(BIF_P, BADARG);
+ else
+ return db_bif_fail(BIF_P, freason, BIF_ets_info_2, NULL);
}
ret = table_info(BIF_P, tb, BIF_ARG_2);
db_unlock(tb, LCK_READ);
@@ -3321,7 +3425,6 @@ int erts_ets_rwmtx_spin_count = -1;
void init_db(ErtsDbSpinCount db_spin_count)
{
int i;
- Eterm *hp;
unsigned bits;
size_t size;
@@ -3387,7 +3490,11 @@ void init_db(ErtsDbSpinCount db_spin_count)
db_max_tabs, ((Uint)1)<<SMALL_BITS);
}
- meta_name_tab_mask = (((Uint) 1)<<(bits-1)) - 1; /* At least half the size of main tab */
+ /*
+ * We don't have ony hard limit for number of tables anymore, .
+ * but we use 'db_max_tabs' to determine size of name hash table.
+ */
+ meta_name_tab_mask = (((Uint) 1)<<bits) - 1;
size = sizeof(struct meta_name_tab_entry)*(meta_name_tab_mask+1);
meta_name_tab = erts_db_alloc_nt(ERTS_ALC_T_DB_TABLES, size);
ERTS_ETS_MISC_MEM_ADD(size);
@@ -3402,35 +3509,28 @@ void init_db(ErtsDbSpinCount db_spin_count)
/* Non visual BIF to trap to. */
erts_init_trap_export(&ets_select_delete_continue_exp,
- am_ets, am_atom_put("delete_trap",11), 1,
- &ets_select_delete_1);
+ am_ets, ERTS_MAKE_AM("select_delete_trap"), 1,
+ &ets_select_delete_trap_1);
/* Non visual BIF to trap to. */
erts_init_trap_export(&ets_select_count_continue_exp,
- am_ets, am_atom_put("count_trap",11), 1,
+ am_ets, ERTS_MAKE_AM("count_trap"), 1,
&ets_select_count_1);
/* Non visual BIF to trap to. */
erts_init_trap_export(&ets_select_replace_continue_exp,
- am_ets, am_atom_put("replace_trap",11), 1,
+ am_ets, ERTS_MAKE_AM("replace_trap"), 1,
&ets_select_replace_1);
/* Non visual BIF to trap to. */
erts_init_trap_export(&ets_select_continue_exp,
- am_ets, am_atom_put("select_trap",11), 1,
+ am_ets, ERTS_MAKE_AM("select_trap"), 1,
&ets_select_trap_1);
/* Non visual BIF to trap to. */
erts_init_trap_export(&ets_delete_continue_exp,
- am_ets, am_atom_put("delete_trap",11), 1,
+ am_ets, ERTS_MAKE_AM("delete_trap"), 1,
&ets_delete_trap);
-
- hp = ms_delete_all_buff;
- ms_delete_all = CONS(hp, am_true, NIL);
- hp += 2;
- ms_delete_all = TUPLE3(hp,am_Underscore,NIL,ms_delete_all);
- hp +=4;
- ms_delete_all = CONS(hp, ms_delete_all,NIL);
}
void
@@ -3442,7 +3542,7 @@ erts_ets_sched_spec_data_init(ErtsSchedulerData *esdp)
eaydp->tab = NULL;
eaydp->queue = NULL;
esdp->ets_tables.clist = NULL;
- esdp->ets_tables.count = 0;
+ erts_atomic_init_nob(&esdp->ets_tables.count, 0);
}
@@ -3547,6 +3647,7 @@ send_ets_transfer_message(Process *c_p, Process *proc,
hd_copy = copy_struct(heir_data, hd_sz, &hp, ohp);
sender = c_p->common.id;
msg = TUPLE4(hp, am_ETS_TRANSFER, tid, sender, hd_copy);
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
erts_queue_proc_message(c_p, proc, *locks, mp, msg);
}
@@ -3654,7 +3755,6 @@ erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks)
&& give_away_to_heir(c_p, tb)) {
break;
}
- tid_clear(c_p, tb);
/* Clear all access bits. */
tb->common.status &= ~(DB_PROTECTED | DB_PUBLIC | DB_PRIVATE);
tb->common.status |= DB_DELETE;
@@ -3664,6 +3764,7 @@ erts_db_process_exiting(Process *c_p, ErtsProcLocks c_p_locks)
free_heir_data(tb);
reds -= free_fixations_locked(c_p, tb);
+ tid_clear(c_p, tb);
db_unlock(tb, LCK_WRITE);
state->op = FREE_OWNED_TABLE;
break;
@@ -3792,7 +3893,8 @@ unlocked:
erts_rwmtx_runlock(&tb->common.rwlock);
erts_rwmtx_rwlock(&tb->common.rwlock);
*kind_p = LCK_WRITE;
- if (tb->common.status & DB_DELETE) return;
+ if (tb->common.status & (DB_DELETE|DB_BUSY))
+ return;
}
db_unfix_table_hash(&(tb->hash));
}
@@ -3810,7 +3912,7 @@ static void free_fixations_op(DbFixation* fix, void* vctx)
struct free_fixations_ctx* ctx = (struct free_fixations_ctx*) vctx;
erts_aint_t diff;
- ASSERT(!btid2tab(fix->tabs.btid));
+ ASSERT(btid2tab(fix->tabs.btid) == ctx->tb);
ASSERT(fix->counter > 0);
ASSERT(ctx->tb->common.status & DB_DELETE);
@@ -3940,7 +4042,8 @@ static BIF_RETTYPE ets_delete_trap(BIF_ALIST_1)
ASSERT(*ptr == make_pos_bignum_header(1));
- if (free_table_continue(BIF_P, tb, reds) < 0) {
+ reds = free_table_continue(BIF_P, tb, reds);
+ if (reds < 0) {
BUMP_ALL_REDS(BIF_P);
BIF_TRAP1(&ets_delete_continue_exp, BIF_P, cont);
}
@@ -4056,7 +4159,7 @@ static Eterm table_info(Process* p, DbTable* tb, Eterm What)
else if (What == am_data) {
print_table(ERTS_PRINT_STDOUT, NULL, 1, tb);
ret = am_true;
- } else if (What == am_atom_put("fixed",5)) {
+ } else if (ERTS_IS_ATOM_STR("fixed",What)) {
if (IS_FIXED(tb))
ret = am_true;
else
@@ -4108,7 +4211,7 @@ static Eterm table_info(Process* p, DbTable* tb, Eterm What)
ret = am_false;
}
erts_mtx_unlock(&tb->common.fixlock);
- } else if (What == am_atom_put("stats",5)) {
+ } else if (ERTS_IS_ATOM_STR("stats",What)) {
if (IS_HASH_TABLE(tb->common.status)) {
FloatDef f;
DbHashStats stats;
@@ -4248,6 +4351,18 @@ erts_db_get_max_tabs()
return db_max_tabs;
}
+Uint erts_ets_table_count(void)
+{
+ Uint tb_count = 0;
+ Uint six;
+
+ for (six = 0; six < erts_no_schedulers; six++) {
+ ErtsSchedulerData *esdp = &erts_aligned_scheduler_data[six].esd;
+ tb_count += erts_atomic_read_nob(&esdp->ets_tables.count);
+ }
+ return tb_count;
+}
+
/*
* For testing of meta tables only.
*
@@ -4321,5 +4436,8 @@ void erts_lcnt_update_db_locks(int enable) {
erts_schedule_multi_misc_aux_work(0, erts_no_schedulers,
&lcnt_update_db_locks_per_sched, (void*)(UWord)enable);
}
-
#endif /* ERTS_ENABLE_LOCK_COUNT */
+
+#ifdef ETS_DBG_FORCE_TRAP
+erts_aint_t erts_ets_dbg_force_trap = 0;
+#endif
diff --git a/erts/emulator/beam/erl_db.h b/erts/emulator/beam/erl_db.h
index eb6da2c9fb..23975d208f 100644
--- a/erts/emulator/beam/erl_db.h
+++ b/erts/emulator/beam/erl_db.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -45,7 +45,7 @@ typedef struct {
} ErtsEtsAllYieldData;
typedef struct {
- Uint count;
+ erts_atomic_t count;
DbTable *clist;
} ErtsEtsTables;
@@ -69,6 +69,7 @@ typedef struct {
/*TT*/
Uint erts_get_ets_misc_mem_size(void);
+Uint erts_ets_table_count(void);
typedef struct {
DbTableCommon common;
@@ -93,7 +94,7 @@ union db_table {
/*TT*/
};
-#define DB_DEF_MAX_TABS 2053 /* Superseeded by environment variable
+#define DB_DEF_MAX_TABS 8192 /* Superseeded by environment variable
"ERL_MAX_ETS_TABLES" */
#define ERL_MAX_ETS_TABLES_ENV "ERL_MAX_ETS_TABLES"
@@ -135,6 +136,10 @@ void erts_lcnt_enable_db_lock_count(DbTable *tb, int enable);
void erts_lcnt_update_db_locks(int enable);
#endif
+#ifdef ETS_DBG_FORCE_TRAP
+extern erts_aint_t erts_ets_dbg_force_trap;
+#endif
+
#endif /* ERL_DB_H__ */
#if defined(ERTS_WANT_DB_INTERNAL__) && !defined(ERTS_HAVE_DB_INTERNAL__)
diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c
index cb5c496e90..b988a19cf4 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1998-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
/*
** Implementation of unordered ETS tables.
** The tables are implemented as linear dynamic hash tables.
+** https://en.wikipedia.org/wiki/Linear_hashing
*/
/* SMP:
@@ -148,20 +149,14 @@ static ERTS_INLINE Uint hash_to_ix(DbTableHash* tb, HashValue hval)
return ix;
}
-/* Remember a slot containing a pseudo-deleted item (INVALID_HASH)
- * Return false if we got raced by unfixing thread
- * and the object should be deleted for real.
- */
-static ERTS_INLINE int add_fixed_deletion(DbTableHash* tb, int ix,
- erts_aint_t fixated_by_me)
+
+static ERTS_INLINE int link_fixdel(DbTableHash* tb,
+ FixedDeletion* fixd,
+ erts_aint_t fixated_by_me)
{
erts_aint_t was_next;
erts_aint_t exp_next;
- FixedDeletion* fixd = (FixedDeletion*) erts_db_alloc(ERTS_ALC_T_DB_FIX_DEL,
- (DbTable *) tb,
- sizeof(FixedDeletion));
- ERTS_ETS_MISC_MEM_ADD(sizeof(FixedDeletion));
- fixd->slot = ix;
+
was_next = erts_atomic_read_acqb(&tb->fixdel);
do { /* Lockless atomic insertion in linked list: */
if (NFIXED(tb) <= fixated_by_me) {
@@ -178,14 +173,33 @@ static ERTS_INLINE int add_fixed_deletion(DbTableHash* tb, int ix,
return 1;
}
+/* Remember a slot containing a pseudo-deleted item
+ * Return false if we got raced by unfixing thread
+ * and the object should be deleted for real.
+ */
+static int add_fixed_deletion(DbTableHash* tb, int ix,
+ erts_aint_t fixated_by_me)
+{
+ FixedDeletion* fixd = (FixedDeletion*) erts_db_alloc(ERTS_ALC_T_DB_FIX_DEL,
+ (DbTable *) tb,
+ sizeof(FixedDeletion));
+ ERTS_ETS_MISC_MEM_ADD(sizeof(FixedDeletion));
+ fixd->slot = ix;
+ fixd->all = 0;
+ return link_fixdel(tb, fixd, fixated_by_me);
+}
+
+
+static ERTS_INLINE int is_pseudo_deleted(HashDbTerm* p)
+{
+ return p->pseudo_deleted;
+}
-#define MAX_HASH 0xEFFFFFFFUL
-#define INVALID_HASH 0xFFFFFFFFUL
/* optimised version of make_hash (normal case? atomic key) */
#define MAKE_HASH(term) \
((is_atom(term) ? (atom_tab(atom_val(term))->slot.bucket.hvalue) : \
- make_internal_hash(term, 0)) % MAX_HASH)
+ make_internal_hash(term, 0)) & MAX_HASH_MASK)
# define DB_HASH_LOCK_MASK (DB_HASH_LOCK_CNT-1)
# define GET_LOCK(tb,hval) (&(tb)->locks->lck_vec[(hval) & DB_HASH_LOCK_MASK].lck)
@@ -270,17 +284,22 @@ static ERTS_INLINE Sint next_slot_w(DbTableHash* tb, Uint ix,
}
-/*
- * Some special binary flags
- */
-#define BIN_FLAG_ALL_OBJECTS BIN_FLAG_USR1
-
static ERTS_INLINE void free_term(DbTableHash *tb, HashDbTerm* p)
{
db_free_term((DbTable*)tb, p, offsetof(HashDbTerm, dbterm));
}
+static ERTS_INLINE void free_term_list(DbTableHash *tb, HashDbTerm* p)
+{
+ while (p) {
+ HashDbTerm* next = p->next;
+ free_term(tb, p);
+ p = next;
+ }
+}
+
+
/*
* Local types
*/
@@ -290,9 +309,6 @@ struct mp_prefound {
};
struct mp_info {
- int all_objects; /* True if complete objects are always
- * returned from the match_spec (can use
- * copy_shallow on the return value) */
int something_can_match; /* The match_spec is not "impossible" */
int key_given;
struct mp_prefound dlists[10]; /* Default list of "pre-found" buckets */
@@ -402,7 +418,7 @@ static void db_print_hash(fmtfn_t to,
void *to_arg,
int show,
DbTable *tbl);
-static int db_free_table_hash(DbTable *tbl);
+static int db_free_empty_table_hash(DbTable *tbl);
static SWord db_free_table_continue_hash(DbTable *tbl, SWord reds);
@@ -411,7 +427,7 @@ static void db_foreach_offheap_hash(DbTable *,
void (*)(ErlOffHeap *, void *),
void *);
-static int db_delete_all_objects_hash(Process* p, DbTable* tbl);
+static SWord db_delete_all_objects_hash(Process* p, DbTable* tbl, SWord reds);
#ifdef HARDDEBUG
static void db_check_table_hash(DbTableHash *tb);
#endif
@@ -436,7 +452,8 @@ static ERTS_INLINE void try_shrink(DbTableHash* tb)
static ERTS_INLINE int has_live_key(DbTableHash* tb, HashDbTerm* b,
Eterm key, HashValue hval)
{
- if (b->hvalue != hval) return 0;
+ if (b->hvalue != hval || is_pseudo_deleted(b))
+ return 0;
else {
Eterm itemKey = GETKEY(tb, b->dbterm.tpl);
ASSERT(!is_header(itemKey));
@@ -449,7 +466,8 @@ static ERTS_INLINE int has_live_key(DbTableHash* tb, HashDbTerm* b,
static ERTS_INLINE int has_key(DbTableHash* tb, HashDbTerm* b,
Eterm key, HashValue hval)
{
- if (b->hvalue != hval && b->hvalue != INVALID_HASH) return 0;
+ if (b->hvalue != hval)
+ return 0;
else {
Eterm itemKey = GETKEY(tb, b->dbterm.tpl);
ASSERT(!is_header(itemKey));
@@ -513,7 +531,7 @@ DbTableMethod db_hash =
db_select_replace_continue_hash,
db_take_hash,
db_delete_all_objects_hash,
- db_free_table_hash,
+ db_free_empty_table_hash,
db_free_table_continue_hash,
db_print_hash,
db_foreach_offheap_hash,
@@ -570,51 +588,61 @@ SWord db_unfix_table_hash(DbTableHash *tb)
SWord work = 0;
ERTS_LC_ASSERT(erts_lc_rwmtx_is_rwlocked(&tb->common.rwlock)
- || (erts_lc_rwmtx_is_rlocked(&tb->common.rwlock)
- && !tb->common.is_thread_safe));
+ || (erts_lc_rwmtx_is_rlocked(&tb->common.rwlock)
+ && !tb->common.is_thread_safe));
restart:
fixdel = (FixedDeletion*) erts_atomic_xchg_mb(&tb->fixdel,
- (erts_aint_t) NULL);
- while (fixdel != NULL) {
- FixedDeletion *fx = fixdel;
- int ix = fx->slot;
- HashDbTerm **bp;
- HashDbTerm *b;
- erts_rwmtx_t* lck = WLOCK_HASH(tb,ix);
-
- if (IS_FIXED(tb)) { /* interrupted by fixer */
- WUNLOCK_HASH(lck);
- restore_fixdel(tb,fixdel);
- if (!IS_FIXED(tb)) {
- goto restart; /* unfixed again! */
- }
- return work;
- }
- if (ix < NACTIVE(tb)) {
- bp = &BUCKET(tb, ix);
- b = *bp;
-
- while (b != NULL) {
- if (b->hvalue == INVALID_HASH) {
- *bp = b->next;
- free_term(tb, b);
- work++;
- b = *bp;
- } else {
- bp = &b->next;
- b = b->next;
- }
- }
- }
- /* else slot has been joined and purged by shrink() */
- WUNLOCK_HASH(lck);
- fixdel = fx->next;
- erts_db_free(ERTS_ALC_T_DB_FIX_DEL,
- (DbTable *) tb,
- (void *) fx,
- sizeof(FixedDeletion));
- ERTS_ETS_MISC_MEM_ADD(-sizeof(FixedDeletion));
- work++;
+ (erts_aint_t) NULL);
+ while (fixdel) {
+ FixedDeletion *free_me;
+
+ do {
+ HashDbTerm **bp;
+ HashDbTerm *b;
+ HashDbTerm *free_us = NULL;
+ erts_rwmtx_t* lck;
+
+ lck = WLOCK_HASH(tb, fixdel->slot);
+
+ if (IS_FIXED(tb)) { /* interrupted by fixer */
+ WUNLOCK_HASH(lck);
+ restore_fixdel(tb,fixdel);
+ if (!IS_FIXED(tb)) {
+ goto restart; /* unfixed again! */
+ }
+ return work;
+ }
+ if (fixdel->slot < NACTIVE(tb)) {
+ bp = &BUCKET(tb, fixdel->slot);
+ b = *bp;
+
+ while (b != NULL) {
+ if (is_pseudo_deleted(b)) {
+ HashDbTerm* nxt = b->next;
+ b->next = free_us;
+ free_us = b;
+ work++;
+ b = *bp = nxt;
+ } else {
+ bp = &b->next;
+ b = b->next;
+ }
+ }
+ }
+ /* else slot has been joined and purged by shrink() */
+ WUNLOCK_HASH(lck);
+ free_term_list(tb, free_us);
+
+ }while (fixdel->all && fixdel->slot-- > 0);
+
+ free_me = fixdel;
+ fixdel = fixdel->next;
+ erts_db_free(ERTS_ALC_T_DB_FIX_DEL,
+ (DbTable *) tb,
+ (void *) free_me,
+ sizeof(FixedDeletion));
+ ERTS_ETS_MISC_MEM_ADD(-sizeof(FixedDeletion));
+ work++;
}
/* ToDo: Maybe try grow/shrink the table as well */
@@ -764,8 +792,9 @@ int db_put_hash(DbTable *tbl, Eterm obj, int key_clash_fail)
*/
if (tb->common.status & DB_SET) {
HashDbTerm* bnext = b->next;
- if (b->hvalue == INVALID_HASH) {
+ if (is_pseudo_deleted(b)) {
erts_atomic_inc_nob(&tb->common.nitems);
+ b->pseudo_deleted = 0;
}
else if (key_clash_fail) {
ret = DB_ERROR_BADKEY;
@@ -773,14 +802,14 @@ int db_put_hash(DbTable *tbl, Eterm obj, int key_clash_fail)
}
q = replace_dbterm(tb, b, obj);
q->next = bnext;
- q->hvalue = hval; /* In case of INVALID_HASH */
+ ASSERT(q->hvalue == hval);
*bp = q;
goto Ldone;
}
else if (key_clash_fail) { /* && (DB_BAG || DB_DUPLICATE_BAG) */
q = b;
do {
- if (q->hvalue != INVALID_HASH) {
+ if (!is_pseudo_deleted(q)) {
ret = DB_ERROR_BADKEY;
goto Ldone;
}
@@ -792,9 +821,10 @@ int db_put_hash(DbTable *tbl, Eterm obj, int key_clash_fail)
q = b;
do {
if (db_eq(&tb->common,obj,&q->dbterm)) {
- if (q->hvalue == INVALID_HASH) {
+ if (is_pseudo_deleted(q)) {
erts_atomic_inc_nob(&tb->common.nitems);
- q->hvalue = hval;
+ q->pseudo_deleted = 0;
+ ASSERT(q->hvalue == hval);
if (q != b) { /* must move to preserve key insertion order */
*qp = q->next;
q->next = b;
@@ -812,6 +842,7 @@ int db_put_hash(DbTable *tbl, Eterm obj, int key_clash_fail)
Lnew:
q = new_dbterm(tb, obj);
q->hvalue = hval;
+ q->pseudo_deleted = 0;
q->next = b;
*bp = q;
nitems = erts_atomic_inc_read_nob(&tb->common.nitems);
@@ -839,7 +870,7 @@ get_term_list(Process *p, DbTableHash *tb, Eterm key, HashValue hval,
if (tb->common.status & (DB_BAG | DB_DUPLICATE_BAG)) {
while (b2 && has_key(tb, b2, key, hval)) {
- if (b2->hvalue != INVALID_HASH)
+ if (!is_pseudo_deleted(b2))
sz += b2->dbterm.size + 2;
b2 = b2->next;
@@ -935,7 +966,7 @@ static int db_get_element_hash(Process *p, DbTable *tbl,
while(b2 != NULL && has_key(tb,b2,key,hval)) {
if (ndex > arityval(b2->dbterm.tpl[0])
- && b2->hvalue != INVALID_HASH) {
+ && !is_pseudo_deleted(b2)) {
retval = DB_ERROR_BADITEM;
goto done;
}
@@ -943,7 +974,7 @@ static int db_get_element_hash(Process *p, DbTable *tbl,
}
b = b1;
while(b != b2) {
- if (b->hvalue != INVALID_HASH) {
+ if (!is_pseudo_deleted(b)) {
Eterm *hp;
Eterm copy = db_copy_element_from_ets(&tb->common, p,
&b->dbterm, ndex, &hp, 2);
@@ -978,6 +1009,7 @@ int db_erase_hash(DbTable *tbl, Eterm key, Eterm *ret)
int ix;
HashDbTerm** bp;
HashDbTerm* b;
+ HashDbTerm* free_us = NULL;
erts_rwmtx_t* lck;
int nitems_diff = 0;
@@ -993,16 +1025,17 @@ int db_erase_hash(DbTable *tbl, Eterm key, Eterm *ret)
if (nitems_diff == -1 && IS_FIXED(tb)
&& add_fixed_deletion(tb, ix, 0)) {
/* Pseudo remove (no need to keep several of same key) */
- b->hvalue = INVALID_HASH;
+ b->pseudo_deleted = 1;
} else {
- *bp = b->next;
- free_term(tb, b);
- b = *bp;
+ HashDbTerm* next = b->next;
+ b->next = free_us;
+ free_us = b;
+ b = *bp = next;
continue;
}
}
else {
- if (nitems_diff && b->hvalue != INVALID_HASH)
+ if (nitems_diff && !is_pseudo_deleted(b))
break;
}
bp = &b->next;
@@ -1013,6 +1046,7 @@ int db_erase_hash(DbTable *tbl, Eterm key, Eterm *ret)
erts_atomic_add_nob(&tb->common.nitems, nitems_diff);
try_shrink(tb);
}
+ free_term_list(tb, free_us);
*ret = am_true;
return DB_ERROR_NONE;
}
@@ -1027,6 +1061,7 @@ static int db_erase_object_hash(DbTable *tbl, Eterm object, Eterm *ret)
int ix;
HashDbTerm** bp;
HashDbTerm* b;
+ HashDbTerm* free_us = NULL;
erts_rwmtx_t* lck;
int nitems_diff = 0;
int nkeys = 0;
@@ -1045,13 +1080,14 @@ static int db_erase_object_hash(DbTable *tbl, Eterm object, Eterm *ret)
if (db_eq(&tb->common,object, &b->dbterm)) {
--nitems_diff;
if (nkeys==1 && IS_FIXED(tb) && add_fixed_deletion(tb,ix,0)) {
- b->hvalue = INVALID_HASH; /* Pseudo remove */
+ b->pseudo_deleted = 1;
bp = &b->next;
b = b->next;
} else {
- *bp = b->next;
- free_term(tb, b);
- b = *bp;
+ HashDbTerm* next = b->next;
+ b->next = free_us;
+ free_us = b;
+ b = *bp = next;
}
if (tb->common.status & (DB_DUPLICATE_BAG)) {
continue;
@@ -1060,7 +1096,7 @@ static int db_erase_object_hash(DbTable *tbl, Eterm object, Eterm *ret)
}
}
}
- else if (nitems_diff && b->hvalue != INVALID_HASH) {
+ else if (nitems_diff && !is_pseudo_deleted(b)) {
break;
}
bp = &b->next;
@@ -1071,6 +1107,7 @@ static int db_erase_object_hash(DbTable *tbl, Eterm object, Eterm *ret)
erts_atomic_add_nob(&tb->common.nitems, nitems_diff);
try_shrink(tb);
}
+ free_term_list(tb, free_us);
*ret = am_true;
return DB_ERROR_NONE;
}
@@ -1106,28 +1143,19 @@ static int db_slot_hash(Process *p, DbTable *tbl, Eterm slot_term, Eterm *ret)
/*
- * This is just here so I can take care of the return value
- * that is to be sent during a trap (the BIF_TRAP macros explicitly returns)
- */
-static BIF_RETTYPE bif_trap1(Export *bif,
- Process *p,
- Eterm p1)
-{
- BIF_TRAP1(bif, p, p1);
-}
-
-
-/*
* Match traversal callbacks
*/
+typedef struct match_callbacks_t_ match_callbacks_t;
+struct match_callbacks_t_
+{
/* Called when no match is possible.
* context_ptr: Pointer to context
* ret: Pointer to traversal function term return.
*
* Both the direct return value and 'ret' are used as the traversal function return values.
*/
-typedef int (*mtraversal_on_nothing_can_match_t)(void* context_ptr, Eterm* ret);
+ int (*on_nothing_can_match)(match_callbacks_t* ctx, Eterm* ret);
/* Called for each match result.
* context_ptr: Pointer to context
@@ -1138,8 +1166,8 @@ typedef int (*mtraversal_on_nothing_can_match_t)(void* context_ptr, Eterm* ret);
*
* Should return 1 for successful match, 0 otherwise.
*/
-typedef int (*mtraversal_on_match_res_t)(void* context_ptr, Sint slot_ix, HashDbTerm*** current_ptr_ptr,
- Eterm match_res);
+ int (*on_match_res)(match_callbacks_t* ctx, Sint slot_ix,
+ HashDbTerm*** current_ptr_ptr, Eterm match_res);
/* Called when either we've matched enough elements in this cycle or EOT was reached.
* context_ptr: Pointer to context
@@ -1152,8 +1180,8 @@ typedef int (*mtraversal_on_match_res_t)(void* context_ptr, Sint slot_ix, HashDb
* Both the direct return value and 'ret' are used as the traversal function return values.
* If *mpp is set to NULL, it won't be deallocated (useful for trapping.)
*/
-typedef int (*mtraversal_on_loop_ended_t)(void* context_ptr, Sint slot_ix, Sint got,
- Sint iterations_left, Binary** mpp, Eterm* ret);
+ int (*on_loop_ended)(match_callbacks_t* ctx, Sint slot_ix, Sint got,
+ Sint iterations_left, Binary** mpp, Eterm* ret);
/* Called when it's time to trap
* context_ptr: Pointer to context
@@ -1165,7 +1193,11 @@ typedef int (*mtraversal_on_loop_ended_t)(void* context_ptr, Sint slot_ix, Sint
* Both the direct return value and 'ret' are used as the traversal function return values.
* If *mpp is set to NULL, it won't be deallocated (useful for trapping.)
*/
-typedef int (*mtraversal_on_trap_t)(void* context_ptr, Sint slot_ix, Sint got, Binary** mpp, Eterm* ret);
+ int (*on_trap)(match_callbacks_t* ctx, Sint slot_ix, Sint got, Binary** mpp,
+ Eterm* ret);
+
+};
+
/*
* Begin hash table match traversal
@@ -1178,11 +1210,7 @@ static int match_traverse(Process* p, DbTableHash* tb,
Eterm** hpp, /* Heap */
int lock_for_write, /* Set to 1 if we're going to delete or
modify existing terms */
- mtraversal_on_nothing_can_match_t on_nothing_can_match,
- mtraversal_on_match_res_t on_match_res,
- mtraversal_on_loop_ended_t on_loop_ended,
- mtraversal_on_trap_t on_trap,
- void* context_ptr, /* State for callbacks above */
+ match_callbacks_t* ctx,
Eterm* ret)
{
Sint slot_ix; /* Slot index */
@@ -1212,14 +1240,10 @@ static int match_traverse(Process* p, DbTableHash* tb,
if (!mpi.something_can_match) {
/* Can't possibly match anything */
- ret_value = on_nothing_can_match(context_ptr, ret);
+ ret_value = ctx->on_nothing_can_match(ctx, ret);
goto done;
}
- if (mpi.all_objects) {
- mpi.mp->intern.flags |= BIN_FLAG_ALL_OBJECTS;
- }
-
/*
* Look for initial slot / bucket
*/
@@ -1235,7 +1259,8 @@ static int match_traverse(Process* p, DbTableHash* tb,
}
slot_ix = next_slot_function(tb,slot_ix,&lck);
if (slot_ix == 0) {
- ret_value = on_loop_ended(context_ptr, slot_ix, got, iterations_left, &mpi.mp, ret);
+ ret_value = ctx->on_loop_ended(ctx, slot_ix, got, iterations_left,
+ &mpi.mp, ret);
goto done;
}
}
@@ -1253,11 +1278,11 @@ static int match_traverse(Process* p, DbTableHash* tb,
*/
for(;;) {
if (*current_ptr != NULL) {
- if ((*current_ptr)->hvalue != INVALID_HASH) {
- match_res = db_match_dbterm(&tb->common, p, mpi.mp, 0,
+ if (!is_pseudo_deleted(*current_ptr)) {
+ match_res = db_match_dbterm(&tb->common, p, mpi.mp,
&(*current_ptr)->dbterm, hpp, 2);
saved_current = *current_ptr;
- if (on_match_res(context_ptr, slot_ix, &current_ptr, match_res)) {
+ if (ctx->on_match_res(ctx, slot_ix, &current_ptr, match_res)) {
++got;
}
--iterations_left;
@@ -1271,7 +1296,7 @@ static int match_traverse(Process* p, DbTableHash* tb,
else if (mpi.key_given) { /* Key is bound */
unlock_hash_function(lck);
if (current_list_pos == mpi.num_lists) {
- ret_value = on_loop_ended(context_ptr, -1, got, iterations_left, &mpi.mp, ret);
+ ret_value = ctx->on_loop_ended(ctx, -1, got, iterations_left, &mpi.mp, ret);
goto done;
} else {
slot_ix = mpi.lists[current_list_pos].ix;
@@ -1296,18 +1321,18 @@ static int match_traverse(Process* p, DbTableHash* tb,
* Since many heap fragments will make the GC slower, trap and GC now.
*/
unlock_hash_function(lck);
- ret_value = on_trap(context_ptr, slot_ix, got, &mpi.mp, ret);
+ ret_value = ctx->on_trap(ctx, slot_ix, got, &mpi.mp, ret);
goto done;
}
current_ptr = &BUCKET(tb,slot_ix);
}
}
- ret_value = on_loop_ended(context_ptr, slot_ix, got, iterations_left, &mpi.mp, ret);
+ ret_value = ctx->on_loop_ended(ctx, slot_ix, got, iterations_left, &mpi.mp, ret);
done:
/* We should only jump directly to this label if
- * we've already called on_nothing_can_match / on_loop_ended / on_trap
+ * we've already called ctx->nothing_can_match / loop_ended / trap
*/
if (mpi.mp != NULL) {
erts_bin_free(mpi.mp);
@@ -1332,13 +1357,9 @@ static int match_traverse_continue(Process* p, DbTableHash* tb,
Binary** mpp, /* Existing match program */
int lock_for_write, /* Set to 1 if we're going to delete or
modify existing terms */
- mtraversal_on_match_res_t on_match_res,
- mtraversal_on_loop_ended_t on_loop_ended,
- mtraversal_on_trap_t on_trap,
- void* context_ptr, /* For callbacks */
+ match_callbacks_t* ctx,
Eterm* ret)
{
- int all_objects = (*mpp)->intern.flags & BIN_FLAG_ALL_OBJECTS;
HashDbTerm** current_ptr; /* Refers to either the bucket pointer or
* the 'next' pointer in the previous term
*/
@@ -1362,7 +1383,7 @@ static int match_traverse_continue(Process* p, DbTableHash* tb,
|| (chunk_size && got >= chunk_size))
{
/* Already got all or enough in the match_list */
- ret_value = on_loop_ended(context_ptr, slot_ix, got, iterations_left, mpp, ret);
+ ret_value = ctx->on_loop_ended(ctx, slot_ix, got, iterations_left, mpp, ret);
goto done;
}
@@ -1380,11 +1401,11 @@ static int match_traverse_continue(Process* p, DbTableHash* tb,
current_ptr = &BUCKET(tb,slot_ix);
for(;;) {
if (*current_ptr != NULL) {
- if ((*current_ptr)->hvalue != INVALID_HASH) {
- match_res = db_match_dbterm(&tb->common, p, *mpp, all_objects,
+ if (!is_pseudo_deleted(*current_ptr)) {
+ match_res = db_match_dbterm(&tb->common, p, *mpp,
&(*current_ptr)->dbterm, hpp, 2);
saved_current = *current_ptr;
- if (on_match_res(context_ptr, slot_ix, &current_ptr, match_res)) {
+ if (ctx->on_match_res(ctx, slot_ix, &current_ptr, match_res)) {
++got;
}
--iterations_left;
@@ -1410,14 +1431,14 @@ static int match_traverse_continue(Process* p, DbTableHash* tb,
* Since many heap fragments will make the GC slower, trap and GC now.
*/
unlock_hash_function(lck);
- ret_value = on_trap(context_ptr, slot_ix, got, mpp, ret);
+ ret_value = ctx->on_trap(ctx, slot_ix, got, mpp, ret);
goto done;
}
current_ptr = &BUCKET(tb,slot_ix);
}
}
- ret_value = on_loop_ended(context_ptr, slot_ix, got, iterations_left, mpp, ret);
+ ret_value = ctx->on_loop_ended(ctx, slot_ix, got, iterations_left, mpp, ret);
done:
/* We should only jump directly to this label if
@@ -1434,7 +1455,7 @@ done:
* as well as their continuation-handling counterparts.
*/
-static ERTS_INLINE int on_mtraversal_simple_trap(Export* trap_function,
+static ERTS_INLINE int on_simple_trap(Export* trap_function,
Process* p,
DbTableHash* tb,
Eterm tid,
@@ -1480,16 +1501,16 @@ static ERTS_INLINE int on_mtraversal_simple_trap(Export* trap_function,
make_small(slot_ix),
mpb,
egot);
- *ret = bif_trap1(trap_function, p, continuation);
+ ERTS_BIF_PREP_TRAP1(*ret, trap_function, p, continuation);
return DB_ERROR_NONE;
}
-static ERTS_INLINE int unpack_simple_mtraversal_continuation(Eterm continuation,
- Eterm** tptr_ptr,
- Eterm* tid_ptr,
- Sint* slot_ix_p,
- Binary** mpp,
- Sint* got_p)
+static ERTS_INLINE int unpack_simple_continuation(Eterm continuation,
+ Eterm** tptr_ptr,
+ Eterm* tid_ptr,
+ Sint* slot_ix_p,
+ Binary** mpp,
+ Sint* got_p)
{
Eterm* tptr;
ASSERT(is_tuple(continuation));
@@ -1524,6 +1545,7 @@ static ERTS_INLINE int unpack_simple_mtraversal_continuation(Eterm continuation,
#define MAX_SELECT_CHUNK_ITERATIONS 1000
typedef struct {
+ match_callbacks_t base;
Process* p;
DbTableHash* tb;
Eterm tid;
@@ -1531,83 +1553,86 @@ typedef struct {
Sint chunk_size;
Eterm match_list;
Eterm* prev_continuation_tptr;
-} mtraversal_select_chunk_context_t;
+} select_chunk_context_t;
-static int mtraversal_select_chunk_on_nothing_can_match(void* context_ptr, Eterm* ret) {
- mtraversal_select_chunk_context_t* sc_context_ptr = (mtraversal_select_chunk_context_t*) context_ptr;
- *ret = (sc_context_ptr->chunk_size > 0 ? am_EOT : NIL);
+static int select_chunk_on_nothing_can_match(match_callbacks_t* ctx_base, Eterm* ret)
+{
+ select_chunk_context_t* ctx = (select_chunk_context_t*) ctx_base;
+ *ret = (ctx->chunk_size > 0 ? am_EOT : NIL);
return DB_ERROR_NONE;
}
-static int mtraversal_select_chunk_on_match_res(void* context_ptr, Sint slot_ix,
- HashDbTerm*** current_ptr_ptr,
- Eterm match_res)
+static int select_chunk_on_match_res(match_callbacks_t* ctx_base, Sint slot_ix,
+ HashDbTerm*** current_ptr_ptr,
+ Eterm match_res)
{
- mtraversal_select_chunk_context_t* sc_context_ptr = (mtraversal_select_chunk_context_t*) context_ptr;
+ select_chunk_context_t* ctx = (select_chunk_context_t*) ctx_base;
if (is_value(match_res)) {
- sc_context_ptr->match_list = CONS(sc_context_ptr->hp, match_res, sc_context_ptr->match_list);
+ ctx->match_list = CONS(ctx->hp, match_res, ctx->match_list);
return 1;
}
return 0;
}
-static int mtraversal_select_chunk_on_loop_ended(void* context_ptr, Sint slot_ix, Sint got,
- Sint iterations_left, Binary** mpp, Eterm* ret)
+static int select_chunk_on_loop_ended(match_callbacks_t* ctx_base,
+ Sint slot_ix, Sint got,
+ Sint iterations_left, Binary** mpp,
+ Eterm* ret)
{
- mtraversal_select_chunk_context_t* sc_context_ptr = (mtraversal_select_chunk_context_t*) context_ptr;
+ select_chunk_context_t* ctx = (select_chunk_context_t*) ctx_base;
Eterm mpb;
if (iterations_left == MAX_SELECT_CHUNK_ITERATIONS) {
/* We didn't get to iterate a single time, which means EOT */
- ASSERT(sc_context_ptr->match_list == NIL);
- *ret = (sc_context_ptr->chunk_size > 0 ? am_EOT : NIL);
+ ASSERT(ctx->match_list == NIL);
+ *ret = (ctx->chunk_size > 0 ? am_EOT : NIL);
return DB_ERROR_NONE;
}
else {
ASSERT(iterations_left < MAX_SELECT_CHUNK_ITERATIONS);
- BUMP_REDS(sc_context_ptr->p, MAX_SELECT_CHUNK_ITERATIONS - iterations_left);
- if (sc_context_ptr->chunk_size) {
+ BUMP_REDS(ctx->p, MAX_SELECT_CHUNK_ITERATIONS - iterations_left);
+ if (ctx->chunk_size) {
Eterm continuation;
Eterm rest = NIL;
Sint rest_size = 0;
- if (got > sc_context_ptr->chunk_size) { /* Split list in return value and 'rest' */
- Eterm tmp = sc_context_ptr->match_list;
- rest = sc_context_ptr->match_list;
- while (got-- > sc_context_ptr->chunk_size + 1) {
+ if (got > ctx->chunk_size) { /* Split list in return value and 'rest' */
+ Eterm tmp = ctx->match_list;
+ rest = ctx->match_list;
+ while (got-- > ctx->chunk_size + 1) {
tmp = CDR(list_val(tmp));
++rest_size;
}
++rest_size;
- sc_context_ptr->match_list = CDR(list_val(tmp));
+ ctx->match_list = CDR(list_val(tmp));
CDR(list_val(tmp)) = NIL; /* Destructive, the list has never
been in 'user space' */
}
if (rest != NIL || slot_ix >= 0) { /* Need more calls */
- Eterm tid = sc_context_ptr->tid;
- sc_context_ptr->hp = HAllocX(sc_context_ptr->p,
- 3 + 7 + ERTS_MAGIC_REF_THING_SIZE,
- ERTS_MAGIC_REF_THING_SIZE);
- mpb = erts_db_make_match_prog_ref(sc_context_ptr->p, *mpp, &sc_context_ptr->hp);
+ Eterm tid = ctx->tid;
+ ctx->hp = HAllocX(ctx->p,
+ 3 + 7 + ERTS_MAGIC_REF_THING_SIZE,
+ ERTS_MAGIC_REF_THING_SIZE);
+ mpb = erts_db_make_match_prog_ref(ctx->p, *mpp, &ctx->hp);
if (is_atom(tid))
- tid = erts_db_make_tid(sc_context_ptr->p,
- &sc_context_ptr->tb->common);
+ tid = erts_db_make_tid(ctx->p,
+ &ctx->tb->common);
continuation = TUPLE6(
- sc_context_ptr->hp,
+ ctx->hp,
tid,
make_small(slot_ix),
- make_small(sc_context_ptr->chunk_size),
+ make_small(ctx->chunk_size),
mpb, rest,
make_small(rest_size));
*mpp = NULL; /* Otherwise the caller will destroy it */
- sc_context_ptr->hp += 7;
- *ret = TUPLE2(sc_context_ptr->hp, sc_context_ptr->match_list, continuation);
+ ctx->hp += 7;
+ *ret = TUPLE2(ctx->hp, ctx->match_list, continuation);
return DB_ERROR_NONE;
} else { /* All data is exhausted */
- if (sc_context_ptr->match_list != NIL) { /* No more data to search but still a
+ if (ctx->match_list != NIL) { /* No more data to search but still a
result to return to the caller */
- sc_context_ptr->hp = HAlloc(sc_context_ptr->p, 3);
- *ret = TUPLE2(sc_context_ptr->hp, sc_context_ptr->match_list, am_EOT);
+ ctx->hp = HAlloc(ctx->p, 3);
+ *ret = TUPLE2(ctx->hp, ctx->match_list, am_EOT);
return DB_ERROR_NONE;
} else { /* Reached the end of the ttable with no data to return */
*ret = am_EOT;
@@ -1615,82 +1640,88 @@ static int mtraversal_select_chunk_on_loop_ended(void* context_ptr, Sint slot_ix
}
}
}
- *ret = sc_context_ptr->match_list;
+ *ret = ctx->match_list;
return DB_ERROR_NONE;
}
}
-static int mtraversal_select_chunk_on_trap(void* context_ptr, Sint slot_ix, Sint got,
- Binary** mpp, Eterm* ret)
+static int select_chunk_on_trap(match_callbacks_t* ctx_base,
+ Sint slot_ix, Sint got,
+ Binary** mpp, Eterm* ret)
{
- mtraversal_select_chunk_context_t* sc_context_ptr = (mtraversal_select_chunk_context_t*) context_ptr;
+ select_chunk_context_t* ctx = (select_chunk_context_t*) ctx_base;
Eterm mpb;
Eterm continuation;
Eterm* hp;
- BUMP_ALL_REDS(sc_context_ptr->p);
+ BUMP_ALL_REDS(ctx->p);
- if (sc_context_ptr->prev_continuation_tptr == NULL) {
- Eterm tid = sc_context_ptr->tid;
+ if (ctx->prev_continuation_tptr == NULL) {
+ Eterm tid = ctx->tid;
/* First time we're trapping */
- hp = HAllocX(sc_context_ptr->p, 7 + ERTS_MAGIC_REF_THING_SIZE,
+ hp = HAllocX(ctx->p, 7 + ERTS_MAGIC_REF_THING_SIZE,
ERTS_MAGIC_REF_THING_SIZE);
if (is_atom(tid))
- tid = erts_db_make_tid(sc_context_ptr->p, &sc_context_ptr->tb->common);
- mpb = erts_db_make_match_prog_ref(sc_context_ptr->p, *mpp, &hp);
+ tid = erts_db_make_tid(ctx->p, &ctx->tb->common);
+ mpb = erts_db_make_match_prog_ref(ctx->p, *mpp, &hp);
continuation = TUPLE6(
hp,
tid,
make_small(slot_ix),
- make_small(sc_context_ptr->chunk_size),
+ make_small(ctx->chunk_size),
mpb,
- sc_context_ptr->match_list,
+ ctx->match_list,
make_small(got));
*mpp = NULL; /* otherwise the caller will destroy it */
}
else {
/* Not the first time we're trapping; reuse continuation terms */
- hp = HAlloc(sc_context_ptr->p, 7);
+ hp = HAlloc(ctx->p, 7);
continuation = TUPLE6(
hp,
- sc_context_ptr->prev_continuation_tptr[1],
+ ctx->prev_continuation_tptr[1],
make_small(slot_ix),
- sc_context_ptr->prev_continuation_tptr[3],
- sc_context_ptr->prev_continuation_tptr[4],
- sc_context_ptr->match_list,
+ ctx->prev_continuation_tptr[3],
+ ctx->prev_continuation_tptr[4],
+ ctx->match_list,
make_small(got));
}
- *ret = bif_trap1(&ets_select_continue_exp, sc_context_ptr->p, continuation);
+ ERTS_BIF_PREP_TRAP1(*ret, &ets_select_continue_exp, ctx->p,
+ continuation);
return DB_ERROR_NONE;
}
-static int db_select_hash(Process *p, DbTable *tbl, Eterm tid, Eterm pattern, int reverse, Eterm *ret) {
+static int db_select_hash(Process *p, DbTable *tbl, Eterm tid, Eterm pattern,
+ int reverse, Eterm *ret)
+{
return db_select_chunk_hash(p, tbl, tid, pattern, 0, reverse, ret);
}
-static int db_select_chunk_hash(Process *p, DbTable *tbl, Eterm tid, Eterm pattern, Sint chunk_size,
+static int db_select_chunk_hash(Process *p, DbTable *tbl, Eterm tid,
+ Eterm pattern, Sint chunk_size,
int reverse, Eterm *ret)
{
- mtraversal_select_chunk_context_t sc_context;
- sc_context.p = p;
- sc_context.tb = &tbl->hash;
- sc_context.tid = tid;
- sc_context.hp = NULL;
- sc_context.chunk_size = chunk_size;
- sc_context.match_list = NIL;
- sc_context.prev_continuation_tptr = NULL;
+ select_chunk_context_t ctx;
+
+ ctx.base.on_nothing_can_match = select_chunk_on_nothing_can_match;
+ ctx.base.on_match_res = select_chunk_on_match_res;
+ ctx.base.on_loop_ended = select_chunk_on_loop_ended;
+ ctx.base.on_trap = select_chunk_on_trap,
+ ctx.p = p;
+ ctx.tb = &tbl->hash;
+ ctx.tid = tid;
+ ctx.hp = NULL;
+ ctx.chunk_size = chunk_size;
+ ctx.match_list = NIL;
+ ctx.prev_continuation_tptr = NULL;
return match_traverse(
- sc_context.p, sc_context.tb,
+ ctx.p, ctx.tb,
pattern, NULL,
- sc_context.chunk_size,
+ ctx.chunk_size,
MAX_SELECT_CHUNK_ITERATIONS,
- &sc_context.hp, 0,
- mtraversal_select_chunk_on_nothing_can_match,
- mtraversal_select_chunk_on_match_res,
- mtraversal_select_chunk_on_loop_ended,
- mtraversal_select_chunk_on_trap,
- &sc_context, ret);
+ &ctx.hp, 0,
+ &ctx.base, ret);
}
/*
@@ -1699,47 +1730,50 @@ static int db_select_chunk_hash(Process *p, DbTable *tbl, Eterm tid, Eterm patte
*
*/
-static int mtraversal_select_chunk_continue_on_loop_ended(void* context_ptr, Sint slot_ix, Sint got,
- Sint iterations_left, Binary** mpp, Eterm* ret)
+static
+int select_chunk_continue_on_loop_ended(match_callbacks_t* ctx_base,
+ Sint slot_ix, Sint got,
+ Sint iterations_left, Binary** mpp,
+ Eterm* ret)
{
- mtraversal_select_chunk_context_t* sc_context_ptr = (mtraversal_select_chunk_context_t*) context_ptr;
+ select_chunk_context_t* ctx = (select_chunk_context_t*) ctx_base;
Eterm continuation;
Eterm rest = NIL;
Eterm* hp;
ASSERT(iterations_left <= MAX_SELECT_CHUNK_ITERATIONS);
- BUMP_REDS(sc_context_ptr->p, MAX_SELECT_CHUNK_ITERATIONS - iterations_left);
- if (sc_context_ptr->chunk_size) {
+ BUMP_REDS(ctx->p, MAX_SELECT_CHUNK_ITERATIONS - iterations_left);
+ if (ctx->chunk_size) {
Sint rest_size = 0;
- if (got > sc_context_ptr->chunk_size) {
+ if (got > ctx->chunk_size) {
/* Cannot write destructively here,
the list may have
been in user space */
- hp = HAlloc(sc_context_ptr->p, (got - sc_context_ptr->chunk_size) * 2);
- while (got-- > sc_context_ptr->chunk_size) {
- rest = CONS(hp, CAR(list_val(sc_context_ptr->match_list)), rest);
+ hp = HAlloc(ctx->p, (got - ctx->chunk_size) * 2);
+ while (got-- > ctx->chunk_size) {
+ rest = CONS(hp, CAR(list_val(ctx->match_list)), rest);
hp += 2;
- sc_context_ptr->match_list = CDR(list_val(sc_context_ptr->match_list));
+ ctx->match_list = CDR(list_val(ctx->match_list));
++rest_size;
}
}
if (rest != NIL || slot_ix >= 0) {
- hp = HAlloc(sc_context_ptr->p, 3 + 7);
+ hp = HAlloc(ctx->p, 3 + 7);
continuation = TUPLE6(
hp,
- sc_context_ptr->prev_continuation_tptr[1],
+ ctx->prev_continuation_tptr[1],
make_small(slot_ix),
- sc_context_ptr->prev_continuation_tptr[3],
- sc_context_ptr->prev_continuation_tptr[4],
+ ctx->prev_continuation_tptr[3],
+ ctx->prev_continuation_tptr[4],
rest,
make_small(rest_size));
hp += 7;
- *ret = TUPLE2(hp, sc_context_ptr->match_list, continuation);
+ *ret = TUPLE2(hp, ctx->match_list, continuation);
return DB_ERROR_NONE;
} else {
- if (sc_context_ptr->match_list != NIL) {
- hp = HAlloc(sc_context_ptr->p, 3);
- *ret = TUPLE2(hp, sc_context_ptr->match_list, am_EOT);
+ if (ctx->match_list != NIL) {
+ hp = HAlloc(ctx->p, 3);
+ *ret = TUPLE2(hp, ctx->match_list, am_EOT);
return DB_ERROR_NONE;
} else {
*ret = am_EOT;
@@ -1747,15 +1781,17 @@ static int mtraversal_select_chunk_continue_on_loop_ended(void* context_ptr, Sin
}
}
}
- *ret = sc_context_ptr->match_list;
+ *ret = ctx->match_list;
return DB_ERROR_NONE;
}
/*
* This is called when select traps
*/
-static int db_select_continue_hash(Process* p, DbTable* tbl, Eterm continuation, Eterm* ret) {
- mtraversal_select_chunk_context_t sc_context = {0};
+static int db_select_continue_hash(Process* p, DbTable* tbl, Eterm continuation,
+ Eterm* ret)
+{
+ select_chunk_context_t ctx;
Eterm* tptr;
Eterm tid;
Binary* mp;
@@ -1790,21 +1826,21 @@ static int db_select_continue_hash(Process* p, DbTable* tbl, Eterm continuation,
match_list = tptr[5];
/* Proceed */
- sc_context.p = p;
- sc_context.tb = &tbl->hash;
- sc_context.tid = tid;
- sc_context.hp = NULL;
- sc_context.chunk_size = chunk_size;
- sc_context.match_list = match_list;
- sc_context.prev_continuation_tptr = tptr;
+ ctx.base.on_match_res = select_chunk_on_match_res;
+ ctx.base.on_loop_ended = select_chunk_continue_on_loop_ended;
+ ctx.base.on_trap = select_chunk_on_trap;
+ ctx.p = p;
+ ctx.tb = &tbl->hash;
+ ctx.tid = tid;
+ ctx.hp = NULL;
+ ctx.chunk_size = chunk_size;
+ ctx.match_list = match_list;
+ ctx.prev_continuation_tptr = tptr;
return match_traverse_continue(
- sc_context.p, sc_context.tb, sc_context.chunk_size,
- iterations_left, &sc_context.hp, slot_ix, got, &mp, 0,
- mtraversal_select_chunk_on_match_res, /* Reuse callback */
- mtraversal_select_chunk_continue_on_loop_ended,
- mtraversal_select_chunk_on_trap, /* Reuse callback */
- &sc_context, ret);
+ ctx.p, ctx.tb, ctx.chunk_size,
+ iterations_left, &ctx.hp, slot_ix, got, &mp, 0,
+ &ctx.base, ret);
badparam:
*ret = NIL;
@@ -1823,75 +1859,83 @@ badparam:
#define MAX_SELECT_COUNT_ITERATIONS 1000
typedef struct {
+ match_callbacks_t base;
Process* p;
DbTableHash* tb;
Eterm tid;
- Eterm* hp;
Eterm* prev_continuation_tptr;
-} mtraversal_select_count_context_t;
+} select_count_context_t;
-static int mtraversal_select_count_on_nothing_can_match(void* context_ptr, Eterm* ret) {
+static int select_count_on_nothing_can_match(match_callbacks_t* ctx_base,
+ Eterm* ret)
+{
*ret = make_small(0);
return DB_ERROR_NONE;
}
-static int mtraversal_select_count_on_match_res(void* context_ptr, Sint slot_ix,
- HashDbTerm*** current_ptr_ptr,
- Eterm match_res)
+static int select_count_on_match_res(match_callbacks_t* ctx_base, Sint slot_ix,
+ HashDbTerm*** current_ptr_ptr,
+ Eterm match_res)
{
return (match_res == am_true);
}
-static int mtraversal_select_count_on_loop_ended(void* context_ptr, Sint slot_ix, Sint got,
- Sint iterations_left, Binary** mpp, Eterm* ret)
+static int select_count_on_loop_ended(match_callbacks_t* ctx_base,
+ Sint slot_ix, Sint got,
+ Sint iterations_left, Binary** mpp,
+ Eterm* ret)
{
- mtraversal_select_count_context_t* scnt_context_ptr = (mtraversal_select_count_context_t*) context_ptr;
+ select_count_context_t* ctx = (select_count_context_t*) ctx_base;
ASSERT(iterations_left <= MAX_SELECT_COUNT_ITERATIONS);
- BUMP_REDS(scnt_context_ptr->p, MAX_SELECT_COUNT_ITERATIONS - iterations_left);
- *ret = erts_make_integer(got, scnt_context_ptr->p);
+ BUMP_REDS(ctx->p, MAX_SELECT_COUNT_ITERATIONS - iterations_left);
+ *ret = erts_make_integer(got, ctx->p);
return DB_ERROR_NONE;
}
-static int mtraversal_select_count_on_trap(void* context_ptr, Sint slot_ix, Sint got,
- Binary** mpp, Eterm* ret)
+static int select_count_on_trap(match_callbacks_t* ctx_base,
+ Sint slot_ix, Sint got,
+ Binary** mpp, Eterm* ret)
{
- mtraversal_select_count_context_t* scnt_context_ptr = (mtraversal_select_count_context_t*) context_ptr;
- return on_mtraversal_simple_trap(
+ select_count_context_t* ctx = (select_count_context_t*) ctx_base;
+ return on_simple_trap(
&ets_select_count_continue_exp,
- scnt_context_ptr->p,
- scnt_context_ptr->tb,
- scnt_context_ptr->tid,
- scnt_context_ptr->prev_continuation_tptr,
+ ctx->p,
+ ctx->tb,
+ ctx->tid,
+ ctx->prev_continuation_tptr,
slot_ix, got, mpp, ret);
}
-static int db_select_count_hash(Process *p, DbTable *tbl, Eterm tid, Eterm pattern, Eterm *ret) {
- mtraversal_select_count_context_t scnt_context = {0};
+static int db_select_count_hash(Process *p, DbTable *tbl, Eterm tid,
+ Eterm pattern, Eterm *ret)
+{
+ select_count_context_t ctx;
Sint iterations_left = MAX_SELECT_COUNT_ITERATIONS;
Sint chunk_size = 0;
- scnt_context.p = p;
- scnt_context.tb = &tbl->hash;
- scnt_context.tid = tid;
- scnt_context.hp = NULL;
- scnt_context.prev_continuation_tptr = NULL;
+ ctx.base.on_nothing_can_match = select_count_on_nothing_can_match;
+ ctx.base.on_match_res = select_count_on_match_res;
+ ctx.base.on_loop_ended = select_count_on_loop_ended;
+ ctx.base.on_trap = select_count_on_trap;
+ ctx.p = p;
+ ctx.tb = &tbl->hash;
+ ctx.tid = tid;
+ ctx.prev_continuation_tptr = NULL;
return match_traverse(
- scnt_context.p, scnt_context.tb,
+ ctx.p, ctx.tb,
pattern, NULL,
chunk_size, iterations_left, NULL, 0,
- mtraversal_select_count_on_nothing_can_match,
- mtraversal_select_count_on_match_res,
- mtraversal_select_count_on_loop_ended,
- mtraversal_select_count_on_trap,
- &scnt_context, ret);
+ &ctx.base, ret);
}
/*
* This is called when select_count traps
*/
-static int db_select_count_continue_hash(Process* p, DbTable* tbl, Eterm continuation, Eterm* ret) {
- mtraversal_select_count_context_t scnt_context = {0};
+static int db_select_count_continue_hash(Process* p, DbTable* tbl,
+ Eterm continuation, Eterm* ret)
+{
+ select_count_context_t ctx;
Eterm* tptr;
Eterm tid;
Binary* mp;
@@ -1900,25 +1944,24 @@ static int db_select_count_continue_hash(Process* p, DbTable* tbl, Eterm continu
Sint chunk_size = 0;
*ret = NIL;
- if (unpack_simple_mtraversal_continuation(continuation, &tptr, &tid, &slot_ix, &mp, &got)) {
+ if (unpack_simple_continuation(continuation, &tptr, &tid, &slot_ix, &mp, &got)) {
*ret = NIL;
return DB_ERROR_BADPARAM;
}
- scnt_context.p = p;
- scnt_context.tb = &tbl->hash;
- scnt_context.tid = tid;
- scnt_context.hp = NULL;
- scnt_context.prev_continuation_tptr = tptr;
+ ctx.base.on_match_res = select_count_on_match_res;
+ ctx.base.on_loop_ended = select_count_on_loop_ended;
+ ctx.base.on_trap = select_count_on_trap;
+ ctx.p = p;
+ ctx.tb = &tbl->hash;
+ ctx.tid = tid;
+ ctx.prev_continuation_tptr = tptr;
return match_traverse_continue(
- scnt_context.p, scnt_context.tb, chunk_size,
+ ctx.p, ctx.tb, chunk_size,
MAX_SELECT_COUNT_ITERATIONS,
NULL, slot_ix, got, &mp, 0,
- mtraversal_select_count_on_match_res, /* Reuse callback */
- mtraversal_select_count_on_loop_ended, /* Reuse callback */
- mtraversal_select_count_on_trap, /* Reuse callback */
- &scnt_context, ret);
+ &ctx.base, ret);
}
#undef MAX_SELECT_COUNT_ITERATIONS
@@ -1933,104 +1976,119 @@ static int db_select_count_continue_hash(Process* p, DbTable* tbl, Eterm continu
#define MAX_SELECT_DELETE_ITERATIONS 1000
typedef struct {
+ match_callbacks_t base;
Process* p;
DbTableHash* tb;
Eterm tid;
- Eterm* hp;
Eterm* prev_continuation_tptr;
erts_aint_t fixated_by_me;
Uint last_pseudo_delete;
-} mtraversal_select_delete_context_t;
+ HashDbTerm* free_us;
+} select_delete_context_t;
-static int mtraversal_select_delete_on_nothing_can_match(void* context_ptr, Eterm* ret) {
+static int select_delete_on_nothing_can_match(match_callbacks_t* ctx_base,
+ Eterm* ret)
+{
*ret = make_small(0);
return DB_ERROR_NONE;
}
-static int mtraversal_select_delete_on_match_res(void* context_ptr, Sint slot_ix,
- HashDbTerm*** current_ptr_ptr,
- Eterm match_res)
+static int select_delete_on_match_res(match_callbacks_t* ctx_base, Sint slot_ix,
+ HashDbTerm*** current_ptr_ptr,
+ Eterm match_res)
{
HashDbTerm** current_ptr = *current_ptr_ptr;
- mtraversal_select_delete_context_t* sd_context_ptr = (mtraversal_select_delete_context_t*) context_ptr;
+ select_delete_context_t* ctx = (select_delete_context_t*) ctx_base;
HashDbTerm* del;
if (match_res != am_true)
return 0;
- if (NFIXED(sd_context_ptr->tb) > sd_context_ptr->fixated_by_me) { /* fixated by others? */
- if (slot_ix != sd_context_ptr->last_pseudo_delete) {
- if (!add_fixed_deletion(sd_context_ptr->tb, slot_ix, sd_context_ptr->fixated_by_me))
+ if (NFIXED(ctx->tb) > ctx->fixated_by_me) { /* fixated by others? */
+ if (slot_ix != ctx->last_pseudo_delete) {
+ if (!add_fixed_deletion(ctx->tb, slot_ix, ctx->fixated_by_me))
goto do_erase;
- sd_context_ptr->last_pseudo_delete = slot_ix;
+ ctx->last_pseudo_delete = slot_ix;
}
- (*current_ptr)->hvalue = INVALID_HASH;
+ (*current_ptr)->pseudo_deleted = 1;
}
else {
do_erase:
del = *current_ptr;
*current_ptr = (*current_ptr)->next; // replace pointer to term using next
- free_term(sd_context_ptr->tb, del);
+ del->next = ctx->free_us;
+ ctx->free_us = del;
}
- erts_atomic_dec_nob(&sd_context_ptr->tb->common.nitems);
+ erts_atomic_dec_nob(&ctx->tb->common.nitems);
return 1;
}
-static int mtraversal_select_delete_on_loop_ended(void* context_ptr, Sint slot_ix, Sint got,
- Sint iterations_left, Binary** mpp, Eterm* ret)
+static int select_delete_on_loop_ended(match_callbacks_t* ctx_base,
+ Sint slot_ix, Sint got,
+ Sint iterations_left, Binary** mpp,
+ Eterm* ret)
{
- mtraversal_select_delete_context_t* sd_context_ptr = (mtraversal_select_delete_context_t*) context_ptr;
+ select_delete_context_t* ctx = (select_delete_context_t*) ctx_base;
+ free_term_list(ctx->tb, ctx->free_us);
+ ctx->free_us = NULL;
ASSERT(iterations_left <= MAX_SELECT_DELETE_ITERATIONS);
- BUMP_REDS(sd_context_ptr->p, MAX_SELECT_DELETE_ITERATIONS - iterations_left);
+ BUMP_REDS(ctx->p, MAX_SELECT_DELETE_ITERATIONS - iterations_left);
if (got) {
- try_shrink(sd_context_ptr->tb);
+ try_shrink(ctx->tb);
}
- *ret = erts_make_integer(got, sd_context_ptr->p);
+ *ret = erts_make_integer(got, ctx->p);
return DB_ERROR_NONE;
}
-static int mtraversal_select_delete_on_trap(void* context_ptr, Sint slot_ix, Sint got,
- Binary** mpp, Eterm* ret)
+static int select_delete_on_trap(match_callbacks_t* ctx_base,
+ Sint slot_ix, Sint got,
+ Binary** mpp, Eterm* ret)
{
- mtraversal_select_delete_context_t* sd_context_ptr = (mtraversal_select_delete_context_t*) context_ptr;
- return on_mtraversal_simple_trap(
+ select_delete_context_t* ctx = (select_delete_context_t*) ctx_base;
+ free_term_list(ctx->tb, ctx->free_us);
+ ctx->free_us = NULL;
+ return on_simple_trap(
&ets_select_delete_continue_exp,
- sd_context_ptr->p,
- sd_context_ptr->tb,
- sd_context_ptr->tid,
- sd_context_ptr->prev_continuation_tptr,
+ ctx->p,
+ ctx->tb,
+ ctx->tid,
+ ctx->prev_continuation_tptr,
slot_ix, got, mpp, ret);
}
-static int db_select_delete_hash(Process *p, DbTable *tbl, Eterm tid, Eterm pattern, Eterm *ret) {
- mtraversal_select_delete_context_t sd_context = {0};
+static int db_select_delete_hash(Process *p, DbTable *tbl, Eterm tid,
+ Eterm pattern, Eterm *ret)
+{
+ select_delete_context_t ctx;
Sint chunk_size = 0;
- sd_context.p = p;
- sd_context.tb = &tbl->hash;
- sd_context.tid = tid;
- sd_context.hp = NULL;
- sd_context.prev_continuation_tptr = NULL;
- sd_context.fixated_by_me = sd_context.tb->common.is_thread_safe ? 0 : 1; /* TODO: something nicer */
- sd_context.last_pseudo_delete = (Uint) -1;
+ ctx.base.on_nothing_can_match = select_delete_on_nothing_can_match;
+ ctx.base.on_match_res = select_delete_on_match_res;
+ ctx.base.on_loop_ended = select_delete_on_loop_ended;
+ ctx.base.on_trap = select_delete_on_trap;
+ ctx.p = p;
+ ctx.tb = &tbl->hash;
+ ctx.tid = tid;
+ ctx.prev_continuation_tptr = NULL;
+ ctx.fixated_by_me = ctx.tb->common.is_thread_safe ? 0 : 1; /* TODO: something nicer */
+ ctx.last_pseudo_delete = (Uint) -1;
+ ctx.free_us = NULL;
return match_traverse(
- sd_context.p, sd_context.tb,
+ ctx.p, ctx.tb,
pattern, NULL,
chunk_size,
MAX_SELECT_DELETE_ITERATIONS, NULL, 1,
- mtraversal_select_delete_on_nothing_can_match,
- mtraversal_select_delete_on_match_res,
- mtraversal_select_delete_on_loop_ended,
- mtraversal_select_delete_on_trap,
- &sd_context, ret);
+ &ctx.base, ret);
}
/*
* This is called when select_delete traps
*/
-static int db_select_delete_continue_hash(Process* p, DbTable* tbl, Eterm continuation, Eterm* ret) {
- mtraversal_select_delete_context_t sd_context = {0};
+static int db_select_delete_continue_hash(Process* p, DbTable* tbl,
+ Eterm continuation, Eterm* ret)
+{
+ select_delete_context_t ctx;
Eterm* tptr;
Eterm tid;
Binary* mp;
@@ -2038,27 +2096,27 @@ static int db_select_delete_continue_hash(Process* p, DbTable* tbl, Eterm contin
Sint slot_ix;
Sint chunk_size = 0;
- if (unpack_simple_mtraversal_continuation(continuation, &tptr, &tid, &slot_ix, &mp, &got)) {
+ if (unpack_simple_continuation(continuation, &tptr, &tid, &slot_ix, &mp, &got)) {
*ret = NIL;
return DB_ERROR_BADPARAM;
}
- sd_context.p = p;
- sd_context.tb = &tbl->hash;
- sd_context.tid = tid;
- sd_context.hp = NULL;
- sd_context.prev_continuation_tptr = tptr;
- sd_context.fixated_by_me = ONLY_WRITER(p, sd_context.tb) ? 0 : 1; /* TODO: something nicer */
- sd_context.last_pseudo_delete = (Uint) -1;
+ ctx.base.on_match_res = select_delete_on_match_res;
+ ctx.base.on_loop_ended = select_delete_on_loop_ended;
+ ctx.base.on_trap = select_delete_on_trap;
+ ctx.p = p;
+ ctx.tb = &tbl->hash;
+ ctx.tid = tid;
+ ctx.prev_continuation_tptr = tptr;
+ ctx.fixated_by_me = ONLY_WRITER(p, ctx.tb) ? 0 : 1; /* TODO: something nicer */
+ ctx.last_pseudo_delete = (Uint) -1;
+ ctx.free_us = NULL;
return match_traverse_continue(
- sd_context.p, sd_context.tb, chunk_size,
+ ctx.p, ctx.tb, chunk_size,
MAX_SELECT_DELETE_ITERATIONS,
NULL, slot_ix, got, &mp, 1,
- mtraversal_select_delete_on_match_res, /* Reuse callback */
- mtraversal_select_delete_on_loop_ended, /* Reuse callback */
- mtraversal_select_delete_on_trap, /* Reuse callback */
- &sd_context, ret);
+ &ctx.base, ret);
}
#undef MAX_SELECT_DELETE_ITERATIONS
@@ -2073,24 +2131,26 @@ static int db_select_delete_continue_hash(Process* p, DbTable* tbl, Eterm contin
#define MAX_SELECT_REPLACE_ITERATIONS 1000
typedef struct {
+ match_callbacks_t base;
Process* p;
DbTableHash* tb;
Eterm tid;
- Eterm* hp;
Eterm* prev_continuation_tptr;
-} mtraversal_select_replace_context_t;
+} select_replace_context_t;
-static int mtraversal_select_replace_on_nothing_can_match(void* context_ptr, Eterm* ret) {
+static int select_replace_on_nothing_can_match(match_callbacks_t* ctx_base,
+ Eterm* ret)
+{
*ret = make_small(0);
return DB_ERROR_NONE;
}
-static int mtraversal_select_replace_on_match_res(void* context_ptr, Sint slot_ix,
- HashDbTerm*** current_ptr_ptr,
- Eterm match_res)
+static int select_replace_on_match_res(match_callbacks_t* ctx_base, Sint slot_ix,
+ HashDbTerm*** current_ptr_ptr,
+ Eterm match_res)
{
- mtraversal_select_replace_context_t* sr_context_ptr = (mtraversal_select_replace_context_t*) context_ptr;
- DbTableHash* tb = sr_context_ptr->tb;
+ select_replace_context_t* ctx = (select_replace_context_t*) ctx_base;
+ DbTableHash* tb = ctx->tb;
HashDbTerm* new;
HashDbTerm* next;
HashValue hval;
@@ -2106,6 +2166,7 @@ static int mtraversal_select_replace_on_match_res(void* context_ptr, Sint slot_i
new = new_dbterm(tb, match_res);
new->next = next;
new->hvalue = hval;
+ new->pseudo_deleted = 0;
free_term(tb, **current_ptr_ptr);
**current_ptr_ptr = new; /* replace 'next' pointer in previous object */
*current_ptr_ptr = &((**current_ptr_ptr)->next); /* advance to next object */
@@ -2114,35 +2175,37 @@ static int mtraversal_select_replace_on_match_res(void* context_ptr, Sint slot_i
return 0;
}
-static int mtraversal_select_replace_on_loop_ended(void* context_ptr, Sint slot_ix, Sint got,
- Sint iterations_left, Binary** mpp, Eterm* ret)
+static int select_replace_on_loop_ended(match_callbacks_t* ctx_base, Sint slot_ix,
+ Sint got, Sint iterations_left,
+ Binary** mpp, Eterm* ret)
{
- mtraversal_select_replace_context_t* sr_context_ptr = (mtraversal_select_replace_context_t*) context_ptr;
+ select_replace_context_t* ctx = (select_replace_context_t*) ctx_base;
ASSERT(iterations_left <= MAX_SELECT_REPLACE_ITERATIONS);
/* the more objects we've replaced, the more reductions we've consumed */
- BUMP_REDS(sr_context_ptr->p,
+ BUMP_REDS(ctx->p,
MIN(MAX_SELECT_REPLACE_ITERATIONS * 2,
(MAX_SELECT_REPLACE_ITERATIONS - iterations_left) + (int)got));
- *ret = erts_make_integer(got, sr_context_ptr->p);
+ *ret = erts_make_integer(got, ctx->p);
return DB_ERROR_NONE;
}
-static int mtraversal_select_replace_on_trap(void* context_ptr, Sint slot_ix, Sint got,
- Binary** mpp, Eterm* ret)
+static int select_replace_on_trap(match_callbacks_t* ctx_base,
+ Sint slot_ix, Sint got,
+ Binary** mpp, Eterm* ret)
{
- mtraversal_select_replace_context_t* sr_context_ptr = (mtraversal_select_replace_context_t*) context_ptr;
- return on_mtraversal_simple_trap(
+ select_replace_context_t* ctx = (select_replace_context_t*) ctx_base;
+ return on_simple_trap(
&ets_select_replace_continue_exp,
- sr_context_ptr->p,
- sr_context_ptr->tb,
- sr_context_ptr->tid,
- sr_context_ptr->prev_continuation_tptr,
+ ctx->p,
+ ctx->tb,
+ ctx->tid,
+ ctx->prev_continuation_tptr,
slot_ix, got, mpp, ret);
}
static int db_select_replace_hash(Process *p, DbTable *tbl, Eterm tid, Eterm pattern, Eterm *ret)
{
- mtraversal_select_replace_context_t sr_context = {0};
+ select_replace_context_t ctx;
Sint chunk_size = 0;
/* Bag implementation presented both semantic consistency and performance issues,
@@ -2150,22 +2213,21 @@ static int db_select_replace_hash(Process *p, DbTable *tbl, Eterm tid, Eterm pat
*/
ASSERT(!(tbl->hash.common.status & DB_BAG));
- sr_context.p = p;
- sr_context.tb = &tbl->hash;
- sr_context.tid = tid;
- sr_context.hp = NULL;
- sr_context.prev_continuation_tptr = NULL;
+ ctx.base.on_nothing_can_match = select_replace_on_nothing_can_match;
+ ctx.base.on_match_res = select_replace_on_match_res;
+ ctx.base.on_loop_ended = select_replace_on_loop_ended;
+ ctx.base.on_trap = select_replace_on_trap;
+ ctx.p = p;
+ ctx.tb = &tbl->hash;
+ ctx.tid = tid;
+ ctx.prev_continuation_tptr = NULL;
return match_traverse(
- sr_context.p, sr_context.tb,
+ ctx.p, ctx.tb,
pattern, db_match_keeps_key,
chunk_size,
MAX_SELECT_REPLACE_ITERATIONS, NULL, 1,
- mtraversal_select_replace_on_nothing_can_match,
- mtraversal_select_replace_on_match_res,
- mtraversal_select_replace_on_loop_ended,
- mtraversal_select_replace_on_trap,
- &sr_context, ret);
+ &ctx.base, ret);
}
/*
@@ -2173,7 +2235,7 @@ static int db_select_replace_hash(Process *p, DbTable *tbl, Eterm tid, Eterm pat
*/
static int db_select_replace_continue_hash(Process* p, DbTable* tbl, Eterm continuation, Eterm* ret)
{
- mtraversal_select_replace_context_t sr_context = {0};
+ select_replace_context_t ctx;
Eterm* tptr;
Eterm tid ;
Binary* mp;
@@ -2182,26 +2244,25 @@ static int db_select_replace_continue_hash(Process* p, DbTable* tbl, Eterm conti
Sint chunk_size = 0;
*ret = NIL;
- if (unpack_simple_mtraversal_continuation(continuation, &tptr, &tid, &slot_ix, &mp, &got)) {
+ if (unpack_simple_continuation(continuation, &tptr, &tid, &slot_ix, &mp, &got)) {
*ret = NIL;
return DB_ERROR_BADPARAM;
}
/* Proceed */
- sr_context.p = p;
- sr_context.tb = &tbl->hash;
- sr_context.tid = tid;
- sr_context.hp = NULL;
- sr_context.prev_continuation_tptr = tptr;
+ ctx.base.on_match_res = select_replace_on_match_res;
+ ctx.base.on_loop_ended = select_replace_on_loop_ended;
+ ctx.base.on_trap = select_replace_on_trap;
+ ctx.p = p;
+ ctx.tb = &tbl->hash;
+ ctx.tid = tid;
+ ctx.prev_continuation_tptr = tptr;
return match_traverse_continue(
- sr_context.p, sr_context.tb, chunk_size,
+ ctx.p, ctx.tb, chunk_size,
MAX_SELECT_REPLACE_ITERATIONS,
NULL, slot_ix, got, &mp, 1,
- mtraversal_select_replace_on_match_res, /* Reuse callback */
- mtraversal_select_replace_on_loop_ended, /* Reuse callback */
- mtraversal_select_replace_on_trap, /* Reuse callback */
- &sr_context, ret);
+ &ctx.base, ret);
}
@@ -2209,6 +2270,7 @@ static int db_take_hash(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
{
DbTableHash *tb = &tbl->hash;
HashDbTerm **bp, *b;
+ HashDbTerm *free_us = NULL;
HashValue hval = MAKE_HASH(key);
erts_rwmtx_t *lck = WLOCK_HASH(tb, hval);
int ix = hash_to_ix(tb, hval);
@@ -2226,12 +2288,13 @@ static int db_take_hash(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
&& add_fixed_deletion(tb, ix, 0)) {
/* Pseudo remove (no need to keep several of same key) */
bp = &b->next;
- b->hvalue = INVALID_HASH;
+ b->pseudo_deleted = 1;
b = b->next;
} else {
- *bp = b->next;
- free_term(tb, b);
- b = *bp;
+ HashDbTerm* next = b->next;
+ b->next = free_us;
+ free_us = b;
+ b = *bp = next;
}
}
break;
@@ -2242,6 +2305,7 @@ static int db_take_hash(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
erts_atomic_add_nob(&tb->common.nitems, nitems_diff);
try_shrink(tb);
}
+ free_term_list(tb, free_us);
return DB_ERROR_NONE;
}
@@ -2255,25 +2319,52 @@ void db_initialize_hash(void)
}
-int db_mark_all_deleted_hash(DbTable *tbl)
+static SWord db_mark_all_deleted_hash(DbTable *tbl, SWord reds)
{
+ const int LOOPS_PER_REDUCTION = 8;
DbTableHash *tb = &tbl->hash;
- HashDbTerm* list;
+ FixedDeletion* fixdel;
+ SWord loops = reds * LOOPS_PER_REDUCTION;
int i;
ERTS_LC_ASSERT(IS_TAB_WLOCKED(tb));
- for (i = 0; i < NACTIVE(tb); i++) {
- if ((list = BUCKET(tb,i)) != NULL) {
- add_fixed_deletion(tb, i, 0);
- do {
- list->hvalue = INVALID_HASH;
- list = list->next;
- }while(list != NULL);
- }
+ fixdel = (FixedDeletion*) erts_atomic_read_nob(&tb->fixdel);
+ if (fixdel && fixdel->trap) {
+ /* Continue after trap */
+ ASSERT(fixdel->all);
+ ASSERT(fixdel->slot < NACTIVE(tb));
+ i = fixdel->slot;
+ }
+ else {
+ /* First call */
+ fixdel = erts_db_alloc(ERTS_ALC_T_DB_FIX_DEL,
+ (DbTable *) tb,
+ sizeof(FixedDeletion));
+ ERTS_ETS_MISC_MEM_ADD(sizeof(FixedDeletion));
+ link_fixdel(tb, fixdel, 0);
+ i = 0;
}
+
+ do {
+ HashDbTerm* b;
+ for (b = BUCKET(tb,i); b; b = b->next)
+ b->pseudo_deleted = 1;
+ } while (++i < NACTIVE(tb) && --loops > 0);
+
+ if (i < NACTIVE(tb)) {
+ /* Yield */
+ fixdel->slot = i;
+ fixdel->all = 0;
+ fixdel->trap = 1;
+ return -1;
+ }
+
+ fixdel->slot = NACTIVE(tb) - 1;
+ fixdel->all = 1;
+ fixdel->trap = 0;
erts_atomic_set_nob(&tb->common.nitems, 0);
- return DB_ERROR_NONE;
+ return loops < 0 ? 0 : loops / LOOPS_PER_REDUCTION;
}
@@ -2316,7 +2407,7 @@ static void db_print_hash(fmtfn_t to, void *to_arg, int show, DbTable *tbl)
continue;
erts_print(to, to_arg, "%d: [", i);
while(list != 0) {
- if (list->hvalue == INVALID_HASH)
+ if (is_pseudo_deleted(list))
erts_print(to, to_arg, "*");
if (tb->common.compress) {
Eterm key = GETKEY(tb, list->dbterm.tpl);
@@ -2335,9 +2426,9 @@ static void db_print_hash(fmtfn_t to, void *to_arg, int show, DbTable *tbl)
}
}
-/* release all memory occupied by a single table */
-static int db_free_table_hash(DbTable *tbl)
+static int db_free_empty_table_hash(DbTable *tbl)
{
+ ASSERT(NITEMS(tbl) == 0);
while (db_free_table_continue_hash(tbl, ERTS_SWORD_MAX) < 0)
;
return 0;
@@ -2415,7 +2506,6 @@ static int analyze_pattern(DbTableHash *tb, Eterm pattern,
mpi->num_lists = 0;
mpi->key_given = 1;
mpi->something_can_match = 0;
- mpi->all_objects = 1;
mpi->mp = NULL;
for (lst = pattern; is_list(lst); lst = CDR(list_val(lst)))
@@ -2468,7 +2558,6 @@ static int analyze_pattern(DbTableHash *tb, Eterm pattern,
if (!is_list(body) || CDR(list_val(body)) != NIL ||
CAR(list_val(body)) != am_DollarUnderscore) {
- mpi->all_objects = 0;
}
++i;
if (!(mpi->key_given)) {
@@ -2682,7 +2771,7 @@ static Eterm build_term_list(Process* p, HashDbTerm* ptr1, HashDbTerm* ptr2,
if (!sz) {
ptr = ptr1;
while(ptr != ptr2) {
- if (ptr->hvalue != INVALID_HASH)
+ if (!is_pseudo_deleted(ptr))
sz += ptr->dbterm.size + 2;
ptr = ptr->next;
}
@@ -2693,7 +2782,7 @@ static Eterm build_term_list(Process* p, HashDbTerm* ptr1, HashDbTerm* ptr2,
ptr = ptr1;
while(ptr != ptr2) {
- if (ptr->hvalue != INVALID_HASH) {
+ if (!is_pseudo_deleted(ptr)) {
copy = db_copy_object_from_ets(&tb->common, &ptr->dbterm, &hp, &MSO(p));
list = CONS(hp, copy, list);
hp += 2;
@@ -2786,7 +2875,7 @@ static void grow(DbTableHash* tb, int nitems)
p = *pnext;
to_pnext = &BUCKET(tb, to_ix);
while (p != NULL) {
- if (p->hvalue == INVALID_HASH) { /* rare but possible with fine locking */
+ if (is_pseudo_deleted(p)) { /* rare but possible with fine locking */
*pnext = p->next;
free_term(tb, p);
p = *pnext;
@@ -2859,7 +2948,7 @@ static void shrink(DbTableHash* tb, int nitems)
* as we must step through "src" anyway to purge pseudo deleted.
*/
while(*bp != NULL) {
- if ((*bp)->hvalue == INVALID_HASH) {
+ if (is_pseudo_deleted(*bp)) {
HashDbTerm* deleted = *bp;
*bp = deleted->next;
free_term(tb, deleted);
@@ -2917,7 +3006,7 @@ static HashDbTerm* next_live(DbTableHash *tb, Uint *iptr, erts_rwmtx_t** lck_ptr
ERTS_LC_ASSERT(IS_HASH_RLOCKED(tb,*iptr));
for ( ; list != NULL; list = list->next) {
- if (list->hvalue != INVALID_HASH)
+ if (!is_pseudo_deleted(list))
return list;
}
@@ -2926,7 +3015,7 @@ static HashDbTerm* next_live(DbTableHash *tb, Uint *iptr, erts_rwmtx_t** lck_ptr
list = BUCKET(tb,i);
while (list != NULL) {
- if (list->hvalue != INVALID_HASH) {
+ if (!is_pseudo_deleted(list)) {
*iptr = i;
return list;
}
@@ -2959,7 +3048,7 @@ db_lookup_dbterm_hash(Process *p, DbTable *tbl, Eterm key, Eterm obj,
break;
}
if (has_key(tb, b, key, hval)) {
- if (b->hvalue != INVALID_HASH) {
+ if (!is_pseudo_deleted(b)) {
goto Ldone;
}
break;
@@ -2989,16 +3078,18 @@ db_lookup_dbterm_hash(Process *p, DbTable *tbl, Eterm key, Eterm obj,
HashDbTerm *q = new_dbterm(tb, obj);
q->hvalue = hval;
+ q->pseudo_deleted = 0;
q->next = NULL;
*bp = b = q;
flags |= DB_INC_TRY_GROW;
} else {
HashDbTerm *q, *next = b->next;
- ASSERT(b->hvalue == INVALID_HASH);
+ ASSERT(is_pseudo_deleted(b));
q = replace_dbterm(tb, b, obj);
q->next = next;
- q->hvalue = hval;
+ ASSERT(q->hvalue == hval);
+ q->pseudo_deleted = 0;
*bp = b = q;
erts_atomic_inc_nob(&tb->common.nitems);
}
@@ -3036,7 +3127,7 @@ db_finalize_dbterm_hash(int cret, DbUpdateHandle* handle)
if (handle->flags & DB_NEW_OBJECT && cret != DB_ERROR_NONE) {
if (IS_FIXED(tb) && add_fixed_deletion(tb, hash_to_ix(tb, b->hvalue),
0)) {
- b->hvalue = INVALID_HASH;
+ b->pseudo_deleted = 1;
} else {
*bp = b->next;
free_me = b;
@@ -3073,16 +3164,19 @@ db_finalize_dbterm_hash(int cret, DbUpdateHandle* handle)
return;
}
-static int db_delete_all_objects_hash(Process* p, DbTable* tbl)
+static SWord db_delete_all_objects_hash(Process* p, DbTable* tbl, SWord reds)
{
if (IS_FIXED(tbl)) {
- db_mark_all_deleted_hash(tbl);
+ reds = db_mark_all_deleted_hash(tbl, reds);
} else {
- db_free_table_hash(tbl);
+ reds = db_free_table_continue_hash(tbl, reds);
+ if (reds < 0)
+ return reds;
+
db_create_hash(p, tbl);
erts_atomic_set_nob(&tbl->hash.common.nitems, 0);
}
- return 0;
+ return reds;
}
void db_foreach_offheap_hash(DbTable *tbl,
@@ -3125,7 +3219,7 @@ void db_calc_stats_hash(DbTableHash* tb, DbHashStats* stats)
len = 0;
for (b = BUCKET(tb,ix); b!=NULL; b=b->next) {
len++;
- if (b->hvalue == INVALID_HASH)
+ if (is_pseudo_deleted(b))
++kept_items;
}
sum += len;
diff --git a/erts/emulator/beam/erl_db_hash.h b/erts/emulator/beam/erl_db_hash.h
index 7d27609825..eae5537ba4 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1998-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,13 +24,26 @@
#include "erl_db_util.h" /* DbTerm & DbTableCommon */
typedef struct fixed_deletion {
- int slot;
+ UWord slot : sizeof(UWord)*8 - 2;
+ UWord all : 1;
+ UWord trap : 1;
struct fixed_deletion *next;
} FixedDeletion;
+
+typedef Uint32 HashVal;
+
typedef struct hash_db_term {
struct hash_db_term* next; /* next bucket */
- HashValue hvalue; /* stored hash value */
+#if SIZEOF_VOID_P == 4
+ Uint32 hvalue : 31; /* stored hash value */
+ Uint32 pseudo_deleted : 1;
+# define MAX_HASH_MASK (((Uint32)1 << 31)-1)
+#elif SIZEOF_VOID_P == 8
+ Uint32 hvalue;
+ Uint32 pseudo_deleted;
+# define MAX_HASH_MASK ((Uint32)(Sint32)-1)
+#endif
DbTerm dbterm; /* The actual term */
} HashDbTerm;
@@ -86,9 +99,6 @@ int db_get_hash(Process *p, DbTable *tbl, Eterm key, Eterm *ret);
int db_erase_hash(DbTable *tbl, Eterm key, Eterm *ret);
-/* not yet in method table */
-int db_mark_all_deleted_hash(DbTable *tbl);
-
typedef struct {
float avg_chain_len;
float std_dev_chain_len;
diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c
index 5a276b9d88..2eb874b005 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1998-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -170,11 +170,6 @@ static ERTS_INLINE TreeDbTerm* replace_dbterm(DbTableTree *tb, TreeDbTerm* old,
#define DIR_END 2
/*
- * Special binary flag
- */
-#define BIN_FLAG_ALL_OBJECTS BIN_FLAG_USR1
-
-/*
* Number of records to delete before trapping.
*/
#define DELETE_RECORD_LIMIT 12000
@@ -218,9 +213,6 @@ static void do_dump_tree2(DbTableTree*, int to, void *to_arg, int show,
* functions.
*/
struct mp_info {
- int all_objects; /* True if complete objects are always
- * returned from the match_spec (can use
- * copy_shallow on the return value) */
int something_can_match; /* The match_spec is not "impossible" */
int some_limitation; /* There is some limitation on the search
* area, i. e. least and/or most is set.*/
@@ -248,7 +240,6 @@ struct select_context {
Eterm *lastobj;
Sint32 max;
int keypos;
- int all_objects;
Sint got;
Sint chunk_size;
};
@@ -263,7 +254,6 @@ struct select_count_context {
Eterm *lastobj;
Sint32 max;
int keypos;
- int all_objects;
Sint got;
};
@@ -293,7 +283,6 @@ struct select_replace_context {
Eterm *lastobj;
Sint32 max;
int keypos;
- int all_objects;
Sint replaced;
};
@@ -428,7 +417,7 @@ static int db_select_replace_continue_tree(Process *p, DbTable *tbl,
static int db_take_tree(Process *, DbTable *, Eterm, Eterm *);
static void db_print_tree(fmtfn_t to, void *to_arg,
int show, DbTable *tbl);
-static int db_free_table_tree(DbTable *tbl);
+static int db_free_empty_table_tree(DbTable *tbl);
static SWord db_free_table_continue_tree(DbTable *tbl, SWord);
@@ -436,7 +425,7 @@ static void db_foreach_offheap_tree(DbTable *,
void (*)(ErlOffHeap *, void *),
void *);
-static int db_delete_all_objects_tree(Process* p, DbTable* tbl);
+static SWord db_delete_all_objects_tree(Process* p, DbTable* tbl, SWord reds);
#ifdef HARDDEBUG
static void db_check_table_tree(DbTable *tbl);
@@ -481,7 +470,7 @@ DbTableMethod db_tree =
db_select_replace_continue_tree,
db_take_tree,
db_delete_all_objects_tree,
- db_free_table_tree,
+ db_free_empty_table_tree,
db_free_table_continue_tree,
db_print_tree,
db_foreach_offheap_tree,
@@ -992,7 +981,6 @@ static int db_select_continue_tree(Process *p,
sc.lastobj = NULL;
sc.max = 1000;
sc.keypos = tb->common.keypos;
- sc.all_objects = mp->intern.flags & BIN_FLAG_ALL_OBJECTS;
sc.chunk_size = chunk_size;
reverse = unsigned_val(tptr[7]);
sc.got = signed_val(tptr[8]);
@@ -1143,7 +1131,6 @@ static int db_select_tree(Process *p, DbTable *tbl, Eterm tid,
}
sc.mp = mpi.mp;
- sc.all_objects = mpi.all_objects;
if (!mpi.got_partial && mpi.some_limitation &&
CMP_EQ(mpi.least,mpi.most)) {
@@ -1183,8 +1170,6 @@ static int db_select_tree(Process *p, DbTable *tbl, Eterm tid,
sz = size_object(key);
hp = HAlloc(p, 9 + sz + ERTS_MAGIC_REF_THING_SIZE);
key = copy_struct(key, sz, &hp, &MSO(p));
- if (mpi.all_objects)
- (mpi.mp)->intern.flags |= BIN_FLAG_ALL_OBJECTS;
mpb= erts_db_make_match_prog_ref(p,mpi.mp,&hp);
continuation = TUPLE8
@@ -1346,7 +1331,6 @@ static int db_select_count_tree(Process *p, DbTable *tbl, Eterm tid,
}
sc.mp = mpi.mp;
- sc.all_objects = mpi.all_objects;
if (!mpi.got_partial && mpi.some_limitation &&
CMP_EQ(mpi.least,mpi.most)) {
@@ -1381,8 +1365,6 @@ static int db_select_count_tree(Process *p, DbTable *tbl, Eterm tid,
hp += BIG_UINT_HEAP_SIZE;
}
key = copy_struct(key, sz, &hp, &MSO(p));
- if (mpi.all_objects)
- (mpi.mp)->intern.flags |= BIN_FLAG_ALL_OBJECTS;
mpb = erts_db_make_match_prog_ref(p,mpi.mp,&hp);
continuation = TUPLE5
@@ -1449,7 +1431,6 @@ static int db_select_chunk_tree(Process *p, DbTable *tbl, Eterm tid,
}
sc.mp = mpi.mp;
- sc.all_objects = mpi.all_objects;
if (!mpi.got_partial && mpi.some_limitation &&
CMP_EQ(mpi.least,mpi.most)) {
@@ -1506,8 +1487,6 @@ static int db_select_chunk_tree(Process *p, DbTable *tbl, Eterm tid,
sz = size_object(key);
hp = HAlloc(p, 9 + sz + ERTS_MAGIC_REF_THING_SIZE);
key = copy_struct(key, sz, &hp, &MSO(p));
- if (mpi.all_objects)
- (mpi.mp)->intern.flags |= BIN_FLAG_ALL_OBJECTS;
mpb = erts_db_make_match_prog_ref(p,mpi.mp,&hp);
continuation = TUPLE8
@@ -1532,8 +1511,6 @@ static int db_select_chunk_tree(Process *p, DbTable *tbl, Eterm tid,
hp = HAlloc(p, 9 + sz + ERTS_MAGIC_REF_THING_SIZE);
key = copy_struct(key, sz, &hp, &MSO(p));
- if (mpi.all_objects)
- (mpi.mp)->intern.flags |= BIN_FLAG_ALL_OBJECTS;
mpb = erts_db_make_match_prog_ref(p,mpi.mp,&hp);
continuation = TUPLE8
(hp,
@@ -1882,7 +1859,6 @@ static int db_select_replace_tree(Process *p, DbTable *tbl, Eterm tid,
}
sc.mp = mpi.mp;
- sc.all_objects = mpi.all_objects;
stack = get_static_stack(tb);
if (!mpi.got_partial && mpi.some_limitation &&
@@ -1928,8 +1904,6 @@ static int db_select_replace_tree(Process *p, DbTable *tbl, Eterm tid,
hp += BIG_UINT_HEAP_SIZE;
}
key = copy_struct(key, sz, &hp, &MSO(p));
- if (mpi.all_objects)
- (mpi.mp)->intern.flags |= BIN_FLAG_ALL_OBJECTS;
mpb = erts_db_make_match_prog_ref(p,mpi.mp,&hp);
continuation = TUPLE5
@@ -1995,8 +1969,9 @@ static void db_print_tree(fmtfn_t to, void *to_arg,
}
/* release all memory occupied by a single table */
-static int db_free_table_tree(DbTable *tbl)
+static int db_free_empty_table_tree(DbTable *tbl)
{
+ ASSERT(tbl->tree.root == NULL);
while (db_free_table_continue_tree(tbl, ERTS_SWORD_MAX) < 0)
;
return 1;
@@ -2023,12 +1998,14 @@ static SWord db_free_table_continue_tree(DbTable *tbl, SWord reds)
return reds;
}
-static int db_delete_all_objects_tree(Process* p, DbTable* tbl)
+static SWord db_delete_all_objects_tree(Process* p, DbTable* tbl, SWord reds)
{
- db_free_table_tree(tbl);
+ reds = db_free_table_continue_tree(tbl, reds);
+ if (reds < 0)
+ return reds;
db_create_tree(p, tbl);
erts_atomic_set_nob(&tbl->tree.common.nitems, 0);
- return 0;
+ return reds;
}
static void do_db_tree_foreach_offheap(TreeDbTerm *,
@@ -2214,7 +2191,6 @@ static int analyze_pattern(DbTableTree *tb, Eterm pattern,
mpi->got_partial = 0;
mpi->something_can_match = 0;
mpi->mp = NULL;
- mpi->all_objects = 1;
mpi->save_term = NULL;
for (lst = pattern; is_list(lst); lst = CDR(list_val(lst)))
@@ -2264,7 +2240,6 @@ static int analyze_pattern(DbTableTree *tb, Eterm pattern,
if (!is_list(body) || CDR(list_val(body)) != NIL ||
CAR(list_val(body)) != am_DollarUnderscore) {
- mpi->all_objects = 0;
}
++i;
@@ -3151,7 +3126,7 @@ static int partly_bound_can_match_lesser(Eterm partly_bound_1,
if (ret)
erts_fprintf(stderr," can match lesser than ");
else
- erts_fprintf(stderr," can not match lesser than ");
+ erts_fprintf(stderr," cannot match lesser than ");
erts_fprintf(stderr,"%T\n",partly_bound_2);
#endif
return ret;
@@ -3169,7 +3144,7 @@ static int partly_bound_can_match_greater(Eterm partly_bound_1,
if (ret)
erts_fprintf(stderr," can match greater than ");
else
- erts_fprintf(stderr," can not match greater than ");
+ erts_fprintf(stderr," cannot match greater than ");
erts_fprintf(stderr,"%T\n",partly_bound_2);
#endif
return ret;
@@ -3339,8 +3314,7 @@ static int doit_select(DbTableTree *tb, TreeDbTerm *this, void *ptr,
GETKEY_WITH_POS(sc->keypos, this->dbterm.tpl)) > 0))) {
return 0;
}
- ret = db_match_dbterm(&tb->common,sc->p,sc->mp,sc->all_objects,
- &this->dbterm, &hp, 2);
+ ret = db_match_dbterm(&tb->common, sc->p, sc->mp, &this->dbterm, &hp, 2);
if (is_value(ret)) {
sc->accum = CONS(hp, ret, sc->accum);
}
@@ -3371,8 +3345,7 @@ static int doit_select_count(DbTableTree *tb, TreeDbTerm *this, void *ptr,
GETKEY_WITH_POS(sc->keypos, this->dbterm.tpl)) > 0)) {
return 0;
}
- ret = db_match_dbterm(&tb->common, sc->p, sc->mp, 0,
- &this->dbterm, NULL, 0);
+ ret = db_match_dbterm(&tb->common, sc->p, sc->mp, &this->dbterm, NULL, 0);
if (ret == am_true) {
++(sc->got);
}
@@ -3401,8 +3374,7 @@ static int doit_select_chunk(DbTableTree *tb, TreeDbTerm *this, void *ptr,
return 0;
}
- ret = db_match_dbterm(&tb->common, sc->p, sc->mp, sc->all_objects,
- &this->dbterm, &hp, 2);
+ ret = db_match_dbterm(&tb->common, sc->p, sc->mp, &this->dbterm, &hp, 2);
if (is_value(ret)) {
++(sc->got);
sc->accum = CONS(hp, ret, sc->accum);
@@ -3437,8 +3409,7 @@ static int doit_select_delete(DbTableTree *tb, TreeDbTerm *this, void *ptr,
cmp_partly_bound(sc->end_condition,
GETKEY_WITH_POS(sc->keypos, this->dbterm.tpl)) > 0)
return 0;
- ret = db_match_dbterm(&tb->common, sc->p, sc->mp, 0,
- &this->dbterm, NULL, 0);
+ ret = db_match_dbterm(&tb->common, sc->p, sc->mp, &this->dbterm, NULL, 0);
if (ret == am_true) {
key = GETKEY(sc->tb, this->dbterm.tpl);
linkout_tree(sc->tb, key);
@@ -3465,8 +3436,7 @@ static int doit_select_replace(DbTableTree *tb, TreeDbTerm **this, void *ptr,
GETKEY_WITH_POS(sc->keypos, (*this)->dbterm.tpl)) > 0)) {
return 0;
}
- ret = db_match_dbterm(&tb->common, sc->p, sc->mp, 0,
- &(*this)->dbterm, NULL, 0);
+ ret = db_match_dbterm(&tb->common, sc->p, sc->mp, &(*this)->dbterm, NULL, 0);
if (is_value(ret)) {
TreeDbTerm* new;
diff --git a/erts/emulator/beam/erl_db_tree.h b/erts/emulator/beam/erl_db_tree.h
index dc1b93d410..54da2a6bc1 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1998-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c
index ef22cda1f0..f1d47326b4 100644
--- a/erts/emulator/beam/erl_db_util.c
+++ b/erts/emulator/beam/erl_db_util.c
@@ -2770,9 +2770,7 @@ Eterm db_format_dmc_err_info(Process *p, DMCErrInfo *ei)
sys_strcpy(buff,tmp->error_string);
sl = sys_strlen(buff);
shp = HAlloc(p, sl * 2 + 5);
- sev = (tmp->severity == dmcWarning) ?
- am_atom_put("warning",7) :
- am_error;
+ sev = (tmp->severity == dmcWarning) ? am_warning : am_error;
tlist = buf_to_intlist(&shp, buff, sl, NIL);
tpl = TUPLE2(shp, sev, tlist);
shp += 3;
@@ -5180,7 +5178,7 @@ BIF_RETTYPE match_spec_test_3(BIF_ALIST_3)
{
Eterm res;
#ifdef DMC_DEBUG
- if (BIF_ARG_3 == am_atom_put("dis",3)) {
+ if (BIF_ARG_3 == ERTS_MAKE_AM("dis")) {
test_disassemble_next = 1;
BIF_RET(am_true);
} else
@@ -5291,7 +5289,7 @@ static Eterm match_spec_test(Process *p, Eterm against, Eterm spec, int trace)
erts_free(ERTS_ALC_T_DB_TMP, arr);
}
erts_bin_free(mps);
- ret = TUPLE4(hp, am_atom_put("ok",2), res, flg, lint_res);
+ ret = TUPLE4(hp, am_ok, res, flg, lint_res);
}
return ret;
}
@@ -5333,7 +5331,7 @@ void db_free_tmp_uncompressed(DbTerm* obj)
}
Eterm db_match_dbterm(DbTableCommon* tb, Process* c_p, Binary* bprog,
- int all, DbTerm* obj, Eterm** hpp, Uint extra)
+ DbTerm* obj, Eterm** hpp, Uint extra)
{
enum erts_pam_run_flags flags;
Uint32 dummy;
diff --git a/erts/emulator/beam/erl_db_util.h b/erts/emulator/beam/erl_db_util.h
index 6b126f35d6..6ec3b4f98f 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1998-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
** DMC_DEBUG does NOT need DEBUG, but DEBUG needs DMC_DEBUG
*/
#define DMC_DEBUG 1
+#define ETS_DBG_FORCE_TRAP 1
#endif
/*
@@ -180,10 +181,9 @@ typedef struct db_table_method
Eterm* ret);
int (*db_take)(Process *, DbTable *, Eterm, Eterm *);
- int (*db_delete_all_objects)(Process* p,
- DbTable* db /* [in out] */ );
+ SWord (*db_delete_all_objects)(Process* p, DbTable* db, SWord reds);
- int (*db_free_table)(DbTable* db /* [in out] */ );
+ int (*db_free_empty_table)(DbTable* db);
SWord (*db_free_table_continue)(DbTable* db, SWord reds);
void (*db_print)(fmtfn_t to,
@@ -267,6 +267,10 @@ typedef struct db_table_common {
Uint32 status; /* bit masks defined below */
int keypos; /* defaults to 1 */
int compress;
+
+#ifdef ETS_DBG_FORCE_TRAP
+ erts_atomic_t dbg_force_trap; /* &1 force enabled, &2 trap this call */
+#endif
} DbTableCommon;
/* These are status bit patterns */
@@ -281,9 +285,7 @@ typedef struct db_table_common {
#define DB_FINE_LOCKED (1 << 8) /* write_concurrency */
#define DB_FREQ_READ (1 << 9) /* read_concurrency */
#define DB_NAMED_TABLE (1 << 10)
-
-#define ERTS_ETS_TABLE_TYPES (DB_BAG|DB_SET|DB_DUPLICATE_BAG|DB_ORDERED_SET\
- |DB_FINE_LOCKED|DB_FREQ_READ|DB_NAMED_TABLE)
+#define DB_BUSY (1 << 11)
#define IS_HASH_TABLE(Status) (!!((Status) & \
(DB_BAG | DB_SET | DB_DUPLICATE_BAG)))
@@ -469,7 +471,7 @@ Binary *db_match_compile(Eterm *matchexpr, Eterm *guards,
/* Returns newly allocated MatchProg binary with refc == 0*/
Eterm db_match_dbterm(DbTableCommon* tb, Process* c_p, Binary* bprog,
- int all, DbTerm* obj, Eterm** hpp, Uint extra);
+ DbTerm* obj, Eterm** hpp, Uint extra);
Eterm db_prog_match(Process *p, Process *self,
Binary *prog, Eterm term,
diff --git a/erts/emulator/beam/erl_dirty_bif.tab b/erts/emulator/beam/erl_dirty_bif.tab
index 10c76d2579..086275fbe5 100644
--- a/erts/emulator/beam/erl_dirty_bif.tab
+++ b/erts/emulator/beam/erl_dirty_bif.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2016. All Rights Reserved.
+# Copyright Ericsson AB 2016-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_drv_thread.c b/erts/emulator/beam/erl_drv_thread.c
index 4cf42fce57..c5dbc87dee 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2007-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index 0692cea0ee..a65dbbf42b 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -413,21 +413,20 @@ erts_gc_after_bif_call_lhf(Process* p, ErlHeapFragment *live_hf_end,
{
int cost;
- if (p->flags & F_HIBERNATE_SCHED) {
+ if (p->flags & (F_HIBERNATE_SCHED|F_HIPE_RECV_LOCKED)) {
/*
* We just hibernated. We do *not* want to mess
* up the hibernation by an ordinary GC...
+ *
+ * OR
+ *
+ * We left a receive in HiPE with message
+ * queue lock locked, and we do not want to
+ * do a GC with message queue locked...
*/
return result;
}
-#ifdef HIPE
- if (p->hipe_smp.have_receive_locks) {
- /* Do not want to GC with message queue locked... */
- return result;
- }
-#endif
-
if (!p->mbuf) {
/* Must have GC:d in BIF call... invalidate live_hf_end */
live_hf_end = ERTS_INVALID_HFRAG_PTR;
diff --git a/erts/emulator/beam/erl_goodfit_alloc.c b/erts/emulator/beam/erl_goodfit_alloc.c
index e3ba67f0af..01d4aa54ff 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2003-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index 57c6c10c7f..5da7b43b9e 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -128,7 +128,7 @@ const Eterm etp_hole_marker = 0;
static int modified_sched_thread_suggested_stack_size = 0;
-Eterm erts_init_process_id;
+Eterm erts_init_process_id = ERTS_INVALID_PID;
/*
* Note about VxWorks: All variables must be initialized by executable code,
@@ -2258,6 +2258,7 @@ erl_start(int argc, char **argv)
erts_init_process_id = erl_first_process_otp("otp_ring0", NULL, 0,
boot_argc, boot_argv);
+ ASSERT(erts_init_process_id != ERTS_INVALID_PID);
{
/*
diff --git a/erts/emulator/beam/erl_io_queue.c b/erts/emulator/beam/erl_io_queue.c
index d779d1031a..2ae5b56b5c 100644
--- a/erts/emulator/beam/erl_io_queue.c
+++ b/erts/emulator/beam/erl_io_queue.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2017. All Rights Reserved.
+ * Copyright Ericsson AB 2017-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_lock_check.h b/erts/emulator/beam/erl_lock_check.h
index 138bc810bd..d10e32985a 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2005-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_lock_count.h b/erts/emulator/beam/erl_lock_count.h
index 89d95a73cf..0d47b16e0b 100644
--- a/erts/emulator/beam/erl_lock_count.h
+++ b/erts/emulator/beam/erl_lock_count.h
@@ -532,7 +532,7 @@ ERTS_GLB_INLINE
void lcnt_dec_lock_state__(ethr_atomic_t *l_state) {
ethr_sint_t state = ethr_atomic_dec_read_acqb(l_state);
- /* We can not assume that state is >= -1 here; unlock and unacquire might
+ /* We cannot assume that state is >= -1 here; unlock and unacquire might
* bring it below -1 and race to increment it back. */
if(state < 0) {
diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c
index 3d565b1bb8..3d6c9eb43f 100644
--- a/erts/emulator/beam/erl_map.c
+++ b/erts/emulator/beam/erl_map.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2014-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2014-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1505,25 +1505,6 @@ int hashmap_key_hash_cmp(Eterm* ap, Eterm* bp)
return ap ? -1 : 1;
}
-/* maps:new/0 */
-
-BIF_RETTYPE maps_new_0(BIF_ALIST_0) {
- Eterm* hp;
- Eterm tup;
- flatmap_t *mp;
-
- hp = HAlloc(BIF_P, (MAP_HEADER_FLATMAP_SZ + 1));
- tup = make_tuple(hp);
- *hp++ = make_arityval(0);
-
- mp = (flatmap_t*)hp;
- mp->thing_word = MAP_HEADER_FLATMAP;
- mp->size = 0;
- mp->keys = tup;
-
- BIF_RET(make_flatmap(mp));
-}
-
/* maps:put/3 */
BIF_RETTYPE maps_put_3(BIF_ALIST_3) {
@@ -1707,11 +1688,16 @@ int erts_maps_update(Process *p, Eterm key, Eterm value, Eterm map, Eterm *res)
return 0;
found_key:
- *hp++ = value;
- vs++;
- if (++i < n)
- sys_memcpy(hp, vs, (n - i)*sizeof(Eterm));
- *res = make_flatmap(shp);
+ if(*vs == value) {
+ HRelease(p, shp + MAP_HEADER_FLATMAP_SZ + n, shp);
+ *res = map;
+ } else {
+ *hp++ = value;
+ vs++;
+ if (++i < n)
+ sys_memcpy(hp, vs, (n - i)*sizeof(Eterm));
+ *res = make_flatmap(shp);
+ }
return 1;
}
@@ -1767,9 +1753,7 @@ Eterm erts_maps_put(Process *p, Eterm key, Eterm value, Eterm map) {
if (is_immed(key)) {
for( i = 0; i < n; i ++) {
if (ks[i] == key) {
- *hp++ = value;
- vs++;
- c = 1;
+ goto found_key;
} else {
*hp++ = *vs++;
}
@@ -1777,18 +1761,13 @@ Eterm erts_maps_put(Process *p, Eterm key, Eterm value, Eterm map) {
} else {
for( i = 0; i < n; i ++) {
if (EQ(ks[i], key)) {
- *hp++ = value;
- vs++;
- c = 1;
+ goto found_key;
} else {
*hp++ = *vs++;
}
}
}
- if (c)
- return res;
-
/* the map will grow */
if (n >= MAP_SMALL_MAP_LIMIT) {
@@ -1843,6 +1822,18 @@ Eterm erts_maps_put(Process *p, Eterm key, Eterm value, Eterm map) {
*/
*shp = make_pos_bignum_header(0);
return res;
+
+found_key:
+ if(*vs == value) {
+ HRelease(p, shp + MAP_HEADER_FLATMAP_SZ + n, shp);
+ return map;
+ } else {
+ *hp++ = value;
+ vs++;
+ if (++i < n)
+ sys_memcpy(hp, vs, (n - i)*sizeof(Eterm));
+ return res;
+ }
}
ASSERT(is_hashmap(map));
@@ -3058,7 +3049,7 @@ BIF_RETTYPE erts_internal_map_next_3(BIF_ALIST_3) {
Uint path_length = 0;
Uint *path_rest = NULL;
int i, elems, orig_elems;
- Eterm node = map, res, *path_ptr = NULL, *hp;
+ Eterm node = map, res, *patch_ptr = NULL, *hp;
/* A stack WSTACK is used when traversing the hashmap.
* It contains: node, idx, sz, ptr
@@ -3117,15 +3108,22 @@ BIF_RETTYPE erts_internal_map_next_3(BIF_ALIST_3) {
}
if (type == iterator) {
- /* iterator uses the format {K, V, {K, V, {K, V, [Path | Map]}}},
- * so each element is 4 words large */
+ /*
+ * Iterator uses the format {K1, V1, {K2, V2, {K3, V3, [Path | Map]}}},
+ * so each element is 4 words large.
+ * To make iteration order independent of input reductions
+ * the KV-pairs are here built in DESTRUCTIVE non-reverse order.
+ */
hp = HAlloc(BIF_P, 4 * elems);
- res = am_none;
} else {
- /* list used the format [Path, Map, {K,V}, {K,V} | BIF_ARG_3],
- * so each element is 2+3 words large */
+ /*
+ * List used the format [Path, Map, {K3,V3}, {K2,V2}, {K1,V1} | BIF_ARG_3],
+ * so each element is 2+3 words large.
+ * To make list order independent of input reductions
+ * the KV-pairs are here built in FUNCTIONAL reverse order
+ * as this is how the list as a whole is constructed.
+ */
hp = HAlloc(BIF_P, (2 + 3) * elems);
- res = BIF_ARG_3;
}
orig_elems = elems;
@@ -3149,12 +3147,15 @@ BIF_RETTYPE erts_internal_map_next_3(BIF_ALIST_3) {
if (is_list(ptr[PATH_ELEM(curr_path)])) {
Eterm *lst = list_val(ptr[PATH_ELEM(curr_path)]);
if (type == iterator) {
- res = TUPLE3(hp, CAR(lst), CDR(lst), res); hp += 4;
- /* Note where we should patch the Iterator is needed */
- path_ptr = hp-1;
+ res = make_tuple(hp);
+ hp[0] = make_arityval(3);
+ hp[1] = CAR(lst);
+ hp[2] = CDR(lst);
+ patch_ptr = &hp[3];
+ hp += 4;
} else {
Eterm tup = TUPLE2(hp, CAR(lst), CDR(lst)); hp += 3;
- res = CONS(hp, tup, res); hp += 2;
+ res = CONS(hp, tup, BIF_ARG_3); hp += 2;
}
elems--;
break;
@@ -3188,7 +3189,12 @@ BIF_RETTYPE erts_internal_map_next_3(BIF_ALIST_3) {
while (idx < sz && elems != 0 && is_list(ptr[idx])) {
Eterm *lst = list_val(ptr[idx]);
if (type == iterator) {
- res = TUPLE3(hp, CAR(lst), CDR(lst), res); hp += 4;
+ *patch_ptr = make_tuple(hp);
+ hp[0] = make_arityval(3);
+ hp[1] = CAR(lst);
+ hp[2] = CDR(lst);
+ patch_ptr = &hp[3];
+ hp += 4;
} else {
Eterm tup = TUPLE2(hp, CAR(lst), CDR(lst)); hp += 3;
res = CONS(hp, tup, res); hp += 2;
@@ -3286,7 +3292,7 @@ BIF_RETTYPE erts_internal_map_next_3(BIF_ALIST_3) {
if (type == iterator) {
hp = HAlloc(BIF_P, 2);
- *path_ptr = CONS(hp, path, map); hp += 2;
+ *patch_ptr = CONS(hp, path, map); hp += 2;
} else {
hp = HAlloc(BIF_P, 4);
res = CONS(hp, map, res); hp += 2;
@@ -3294,6 +3300,7 @@ BIF_RETTYPE erts_internal_map_next_3(BIF_ALIST_3) {
}
} else {
if (type == iterator) {
+ *patch_ptr = am_none;
HRelease(BIF_P, hp + 4 * elems, hp);
} else {
HRelease(BIF_P, hp + (2+3) * elems, hp);
diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c
index bea7a0fe86..a3274d7443 100644
--- a/erts/emulator/beam/erl_message.c
+++ b/erts/emulator/beam/erl_message.c
@@ -379,7 +379,10 @@ queue_messages(Process* receiver,
erts_proc_unlock(receiver, ERTS_PROC_LOCK_MSGQ);
}
- erts_proc_notify_new_message(receiver, receiver_locks);
+ if (last == &first->next)
+ erts_proc_notify_new_message(receiver, receiver_locks);
+ else
+ erts_proc_notify_new_sig(receiver, state, ERTS_PSFLG_ACTIVE);
}
static ERTS_INLINE
@@ -406,6 +409,11 @@ ErtsMessage* prepend_pending_sig_maybe(Process* sender, Process* receiver,
*
* @brief Send one message from *NOT* a local process.
*
+ * seq_trace does not work with this type of messages
+ * to it is set to am_undefined which means that the
+ * receiving process will not remove the seq_trace token
+ * when it gets this message.
+ *
*/
void
erts_queue_message(Process* receiver, ErtsProcLocks receiver_locks,
@@ -414,11 +422,19 @@ erts_queue_message(Process* receiver, ErtsProcLocks receiver_locks,
ASSERT(is_not_internal_pid(from));
ERL_MESSAGE_TERM(mp) = msg;
ERL_MESSAGE_FROM(mp) = from;
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
queue_messages(receiver, receiver_locks, mp, &mp->next, 1);
}
/**
* @brief Send one message from a local process.
+ *
+ * It is up to the caller of this function to set the
+ * correct seq_trace. The general rule of thumb is that
+ * it should be set to am_undefined if the message
+ * cannot be traced using seq_trace, if it can be
+ * traced it should be set to the trace token. It should
+ * very rarely be explicitly set to NIL!
*/
void
erts_queue_proc_message(Process* sender,
@@ -581,8 +597,7 @@ void
erts_send_message(Process* sender,
Process* receiver,
ErtsProcLocks *receiver_locks,
- Eterm message,
- unsigned flags)
+ Eterm message)
{
Uint msize;
ErtsMessage* mp;
@@ -616,7 +631,7 @@ erts_send_message(Process* sender,
receiver_state = erts_atomic32_read_nob(&receiver->state);
- if (SEQ_TRACE_TOKEN(sender) != NIL && !(flags & ERTS_SND_FLG_NO_SEQ_TRACE)) {
+ if (SEQ_TRACE_TOKEN(sender) != NIL) {
Eterm* hp;
Eterm stoken = SEQ_TRACE_TOKEN(sender);
Uint seq_trace_size = 0;
diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h
index d120111634..b2550814fd 100644
--- a/erts/emulator/beam/erl_message.h
+++ b/erts/emulator/beam/erl_message.h
@@ -405,8 +405,6 @@ typedef struct erl_trace_message_queue__ {
#define SAVE_MESSAGE(p) \
(p)->sig_qs.save = &(*(p)->sig_qs.save)->next
-#define ERTS_SND_FLG_NO_SEQ_TRACE (((unsigned) 1) << 0)
-
#define ERTS_HEAP_FRAG_SIZE(DATA_WORDS) \
(sizeof(ErlHeapFragment) - sizeof(Eterm) + (DATA_WORDS)*sizeof(Eterm))
@@ -429,7 +427,7 @@ typedef struct erl_trace_message_queue__ {
do { \
(MP)->next = NULL; \
ERL_MESSAGE_TERM(MP) = THE_NON_VALUE; \
- ERL_MESSAGE_TOKEN(MP) = NIL; \
+ ERL_MESSAGE_TOKEN(MP) = THE_NON_VALUE; \
ERL_MESSAGE_FROM(MP) = NIL; \
ERL_MESSAGE_DT_UTAG_INIT(MP); \
MP->data.attached = NULL; \
@@ -446,7 +444,7 @@ void erts_queue_proc_message(Process* from,Process* to, ErtsProcLocks,ErtsMessag
void erts_queue_proc_messages(Process* from, Process* to, ErtsProcLocks,
ErtsMessage*, ErtsMessage**, Uint);
void erts_deliver_exit_message(Eterm, Process*, ErtsProcLocks *, Eterm, Eterm);
-void erts_send_message(Process*, Process*, ErtsProcLocks*, Eterm, unsigned);
+void erts_send_message(Process*, Process*, ErtsProcLocks*, Eterm);
void erts_link_mbuf_to_proc(Process *proc, ErlHeapFragment *bp);
Uint erts_msg_attached_data_size_aux(ErtsMessage *msg);
diff --git a/erts/emulator/beam/erl_monitor_link.c b/erts/emulator/beam/erl_monitor_link.c
index 70f36fb6b7..48d9bd4ca5 100644
--- a/erts/emulator/beam/erl_monitor_link.c
+++ b/erts/emulator/beam/erl_monitor_link.c
@@ -630,7 +630,9 @@ erts_monitor_tree_lookup_create(ErtsMonitor **root, int *created, Uint16 type,
ErtsMonitor *res;
ErtsMonitorCreateCtxt cctxt = {type, origin};
- ERTS_ML_ASSERT(type == ERTS_MON_TYPE_NODE || type == ERTS_MON_TYPE_NODES);
+ ERTS_ML_ASSERT(type == ERTS_MON_TYPE_NODE
+ || type == ERTS_MON_TYPE_NODES
+ || type == ERTS_MON_TYPE_SUSPEND);
res = (ErtsMonitor *) ml_rbt_lookup_create((ErtsMonLnkNode **) root,
target, create_monitor,
@@ -760,11 +762,13 @@ erts_monitor_create(Uint16 type, Eterm ref, Eterm orgn, Eterm trgt, Eterm name)
switch (type) {
case ERTS_MON_TYPE_PROC:
case ERTS_MON_TYPE_PORT:
- case ERTS_MON_TYPE_TIME_OFFSET:
if (is_nil(name)) {
ErtsMonitorDataHeap *mdhp;
ErtsORefThing *ortp;
+ case ERTS_MON_TYPE_TIME_OFFSET:
+
+ ERTS_ML_ASSERT(is_nil(name));
ERTS_ML_ASSERT(is_immed(orgn) && is_immed(trgt));
ERTS_ML_ASSERT(is_internal_ordinary_ref(ref));
@@ -860,10 +864,38 @@ erts_monitor_create(Uint16 type, Eterm ref, Eterm orgn, Eterm trgt, Eterm name)
mdep->dist = NULL;
break;
}
- case ERTS_MON_TYPE_SUSPEND:
- ERTS_INTERNAL_ERROR("Use erts_monitor_suspend_create() instead...");
- mdp = NULL;
+ case ERTS_MON_TYPE_SUSPEND: {
+ ErtsMonitorSuspend *msp;
+
+ ERTS_ML_ASSERT(is_nil(name));
+ ERTS_ML_ASSERT(is_nil(ref));
+ ERTS_ML_ASSERT(is_internal_pid(orgn) && is_internal_pid(trgt));
+
+ msp = erts_alloc(ERTS_ALC_T_MONITOR_SUSPEND,
+ sizeof(ErtsMonitorSuspend));
+ mdp = &msp->md;
+ ERTS_ML_ASSERT(((void *) mdp) == ((void *) msp));
+
+ mdp->ref = NIL;
+
+ mdp->origin.other.item = trgt;
+ mdp->origin.offset = (Uint16) offsetof(ErtsMonitorData, origin);
+ mdp->origin.key_offset = (Uint16) offsetof(ErtsMonitor, other.item);
+ ERTS_ML_ASSERT(mdp->origin.key_offset >= mdp->origin.offset);
+ mdp->origin.flags = (Uint16) ERTS_ML_FLG_EXTENDED;
+ mdp->origin.type = type;
+
+ mdp->target.other.item = orgn;
+ mdp->target.offset = (Uint16) offsetof(ErtsMonitorData, target);
+ mdp->target.key_offset = (Uint16) offsetof(ErtsMonitor, other.item);
+ mdp->target.flags = ERTS_ML_FLG_TARGET|ERTS_ML_FLG_EXTENDED;
+ mdp->target.type = type;
+
+ msp->next = NULL;
+ erts_atomic_init_relb(&msp->state, 0);
+
break;
+ }
default:
ERTS_INTERNAL_ERROR("Invalid monitor type");
mdp = NULL;
@@ -887,10 +919,11 @@ erts_monitor_destroy__(ErtsMonitorData *mdp)
ERTS_ML_ASSERT(!(mdp->target.flags & ERTS_ML_FLG_IN_TABLE));
ERTS_ML_ASSERT((mdp->origin.flags & ERTS_ML_FLGS_SAME)
== (mdp->target.flags & ERTS_ML_FLGS_SAME));
- ERTS_ML_ASSERT(mdp->origin.type != ERTS_MON_TYPE_SUSPEND);
if (!(mdp->origin.flags & ERTS_ML_FLG_EXTENDED))
erts_free(ERTS_ALC_T_MONITOR, mdp);
+ else if (mdp->origin.type == ERTS_MON_TYPE_SUSPEND)
+ erts_free(ERTS_ALC_T_MONITOR_SUSPEND, mdp);
else {
ErtsMonitorDataExtended *mdep = (ErtsMonitorDataExtended *) mdp;
ErlOffHeap oh;
@@ -927,10 +960,10 @@ erts_monitor_size(ErtsMonitor *mon)
Uint size, refc;
ErtsMonitorData *mdp = erts_monitor_to_data(mon);
- ERTS_ML_ASSERT(mon->type != ERTS_MON_TYPE_SUSPEND);
-
if (!(mon->flags & ERTS_ML_FLG_EXTENDED))
size = sizeof(ErtsMonitorDataHeap);
+ else if (mon->type == ERTS_MON_TYPE_SUSPEND)
+ size = sizeof(ErtsMonitorSuspend);
else {
ErtsMonitorDataExtended *mdep;
Uint hsz = 0;
@@ -957,54 +990,6 @@ erts_monitor_size(ErtsMonitor *mon)
return size / refc;
}
-
-/* suspend monitors... */
-
-ErtsMonitorSuspend *
-erts_monitor_suspend_create(Eterm pid)
-{
- ErtsMonitorSuspend *msp;
-
- ERTS_ML_ASSERT(is_internal_pid(pid));
-
- msp = erts_alloc(ERTS_ALC_T_SUSPEND_MON,
- sizeof(ErtsMonitorSuspend));
- msp->mon.offset = (Uint16) offsetof(ErtsMonitorSuspend, mon);
- msp->mon.key_offset = (Uint16) offsetof(ErtsMonitor, other.item);
- msp->mon.other.item = pid;
- msp->mon.flags = 0;
- msp->mon.type = ERTS_MON_TYPE_SUSPEND;
- msp->pending = 0;
- msp->active = 0;
- return msp;
-}
-
-static ErtsMonLnkNode *
-create_monitor_suspend(Eterm pid, void *unused)
-{
- ErtsMonitorSuspend *msp = erts_monitor_suspend_create(pid);
- return (ErtsMonLnkNode *) &msp->mon;
-}
-
-ErtsMonitorSuspend *
-erts_monitor_suspend_tree_lookup_create(ErtsMonitor **root, int *created,
- Eterm pid)
-{
- ErtsMonitor *mon;
- mon = (ErtsMonitor *) ml_rbt_lookup_create((ErtsMonLnkNode **) root,
- pid, create_monitor_suspend,
- NULL,
- created);
- return erts_monitor_suspend(mon);
-}
-
-void
-erts_monitor_suspend_destroy(ErtsMonitorSuspend *msp)
-{
- ERTS_ML_ASSERT(!(msp->mon.flags & ERTS_ML_FLG_IN_TABLE));
- erts_free(ERTS_ALC_T_SUSPEND_MON, msp);
-}
-
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
* Link Operations *
* *
diff --git a/erts/emulator/beam/erl_monitor_link.h b/erts/emulator/beam/erl_monitor_link.h
index 603aead8cc..9ff8aa509a 100644
--- a/erts/emulator/beam/erl_monitor_link.h
+++ b/erts/emulator/beam/erl_monitor_link.h
@@ -246,15 +246,28 @@
*
* --- ERTS_MON_TYPE_SUSPEND -------------------------------------
*
- * Suspend monitor.
+ * Suspend monitor. A local process (origin) suspends another
+ * local process (target).
*
- * Other Item: Suspendee process identifier
- * Key: Suspendee process identifier
- *
- * Valid keys are only ordinary internal references.
+ * Origin:
+ * Other Item: Process identifier of suspendee
+ * (target)
+ * Key: Process identifier of suspendee
+ * (target)
+ * Target:
+ * Other Item: Process identifier of suspender
+ * (origin)
+ * Key: Process identifier of suspender
+ * (origin)
+ * Shared:
+ * Next: Pointer to another suspend monitor
+ * State: Number of suspends and a flag
+ * indicating if the suspend is
+ * active or not.
*
- * This type of monitor is a bit strange and the whole process
- * suspend functionality should be improved...
+ * Origin part of the monitor is stored in the monitor tree of
+ * origin process and target part of the monitor is stored in
+ * monitor list for local targets on the target process.
*
*
*
@@ -638,11 +651,15 @@ struct ErtsMonitorDataExtended__ {
Eterm heap[1]; /* heap start... */
};
-typedef struct {
- ErtsMonitor mon;
- int pending;
- int active;
-} ErtsMonitorSuspend;
+typedef struct ErtsMonitorSuspend__ ErtsMonitorSuspend;
+
+struct ErtsMonitorSuspend__ {
+ ErtsMonitorData md; /* origin = suspender; target = suspendee */
+ ErtsMonitorSuspend *next;
+ erts_atomic_t state;
+};
+#define ERTS_MSUSPEND_STATE_FLG_ACTIVE ((erts_aint_t) (((Uint) 1) << (sizeof(Uint)*8 - 1)))
+#define ERTS_MSUSPEND_STATE_COUNTER_MASK (~ERTS_MSUSPEND_STATE_FLG_ACTIVE)
/*
* --- Monitor tree operations ---
@@ -1094,24 +1111,25 @@ int erts_monitor_list_foreach_delete_yielding(ErtsMonitor **list,
*
* @brief Create a monitor
*
- * Can create all types of monitors exept for suspend monitors
+ * Can create all types of monitors
*
* When the funcion is called it is assumed that:
* - 'ref' is an internal ordinary reference if type is ERTS_MON_TYPE_PROC,
* ERTS_MON_TYPE_PORT, ERTS_MON_TYPE_TIME_OFFSET, or ERTS_MON_TYPE_RESOURCE
- * - 'ref' is NIL if type is ERTS_MON_TYPE_NODE or ERTS_MON_TYPE_NODES
+ * - 'ref' is NIL if type is ERTS_MON_TYPE_NODE, ERTS_MON_TYPE_NODES, or
+ * ERTS_MON_TYPE_SUSPEND
* - 'ref' is and ordinary internal reference or an external reference if
* type is ERTS_MON_TYPE_DIST_PROC
* - 'name' is an atom or NIL if type is ERTS_MON_TYPE_PROC,
* ERTS_MON_TYPE_PORT, or ERTS_MON_TYPE_DIST_PROC
* - 'name is NIL if type is ERTS_MON_TYPE_TIME_OFFSET, ERTS_MON_TYPE_RESOURCE,
- * ERTS_MON_TYPE_NODE, or ERTS_MON_TYPE_NODES
+ * ERTS_MON_TYPE_NODE, ERTS_MON_TYPE_NODES, or ERTS_MON_TYPE_SUSPEND
* If the above is not true, bad things will happen.
*
* @param[in] type ERTS_MON_TYPE_PROC, ERTS_MON_TYPE_PORT,
* ERTS_MON_TYPE_TIME_OFFSET, ERTS_MON_TYPE_DIST_PROC,
* ERTS_MON_TYPE_RESOURCE, ERTS_MON_TYPE_NODE,
- * or ERTS_MON_TYPE_NODES
+ * ERTS_MON_TYPE_NODES, or ERTS_MON_TYPE_SUSPEND
*
* @param[in] ref A reference or NIL depending on type
*
@@ -1119,6 +1137,10 @@ int erts_monitor_list_foreach_delete_yielding(ErtsMonitor **list,
*
* @param[in] target The key of the target
*
+ * @param[in] name An atom (the name) or NIL depending on type
+ *
+ * @returns A pointer to monitor data structure
+ *
*/
ErtsMonitorData *erts_monitor_create(Uint16 type, Eterm ref, Eterm origin,
Eterm target, Eterm name);
@@ -1347,7 +1369,8 @@ erts_monitor_to_data(ErtsMonitor *mon)
ERTS_ML_ASSERT(erts_monitor_origin_offset == (size_t) mdp->origin.offset);
ERTS_ML_ASSERT(!!(mdp->target.flags & ERTS_ML_FLG_TARGET));
ERTS_ML_ASSERT(erts_monitor_target_offset == (size_t) mdp->target.offset);
- if (mon->type == ERTS_MON_TYPE_NODE || mon->type == ERTS_MON_TYPE_NODES) {
+ if (mon->type == ERTS_MON_TYPE_NODE || mon->type == ERTS_MON_TYPE_NODES
+ || mon->type == ERTS_MON_TYPE_SUSPEND) {
ERTS_ML_ASSERT(erts_monitor_node_key_offset == (size_t) mdp->origin.key_offset);
ERTS_ML_ASSERT(erts_monitor_node_key_offset == (size_t) mdp->target.key_offset);
}
diff --git a/erts/emulator/beam/erl_msacc.c b/erts/emulator/beam/erl_msacc.c
index d13d6080e1..375b004b5b 100644
--- a/erts/emulator/beam/erl_msacc.c
+++ b/erts/emulator/beam/erl_msacc.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2014-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2014-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_msacc.h b/erts/emulator/beam/erl_msacc.h
index 895b1ae319..abea18b340 100644
--- a/erts/emulator/beam/erl_msacc.h
+++ b/erts/emulator/beam/erl_msacc.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2014-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2014-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_mtrace.c b/erts/emulator/beam/erl_mtrace.c
index 2807b443a1..6e0a0dcff7 100644
--- a/erts/emulator/beam/erl_mtrace.c
+++ b/erts/emulator/beam/erl_mtrace.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2003-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_nfunc_sched.c b/erts/emulator/beam/erl_nfunc_sched.c
index f97e86bf95..b8cf2bee0e 100644
--- a/erts/emulator/beam/erl_nfunc_sched.c
+++ b/erts/emulator/beam/erl_nfunc_sched.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2016. All Rights Reserved.
+ * Copyright Ericsson AB 2016-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_nfunc_sched.h b/erts/emulator/beam/erl_nfunc_sched.h
index b8a4e4ebc3..1cb252eba5 100644
--- a/erts/emulator/beam/erl_nfunc_sched.h
+++ b/erts/emulator/beam/erl_nfunc_sched.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2016. All Rights Reserved.
+ * Copyright Ericsson AB 2016-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index e208792868..7339aa8874 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -453,8 +453,18 @@ static void full_flush_env(ErlNifEnv* env)
static void full_cache_env(ErlNifEnv* env)
{
- if (env->proc->static_flags & ERTS_STC_FLG_SHADOW_PROC)
+ if (env->proc->static_flags & ERTS_STC_FLG_SHADOW_PROC) {
erts_cache_dirty_shadow_proc(env->proc);
+ /*
+ * If shadow proc had heap fragments when flushed
+ * those have now been moved to the real proc.
+ * Ensure heap pointers do not point into a heap
+ * fragment on real proc...
+ */
+ ASSERT(!env->proc->mbuf);
+ env->hp_end = HEAP_LIMIT(env->proc);
+ env->hp = HEAP_TOP(env->proc);
+ }
cache_env(env);
}
@@ -744,8 +754,58 @@ int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid,
rp_locks = ERTS_PROC_LOCK_MAIN;
if (menv) {
+ Eterm token = c_p ? SEQ_TRACE_TOKEN(c_p) : am_undefined;
+ if (token != NIL && token != am_undefined) {
+ /* This code is copied from erts_send_message */
+ Eterm stoken = SEQ_TRACE_TOKEN(c_p);
+#ifdef USE_VM_PROBES
+ DTRACE_CHARBUF(sender_name, 64);
+ DTRACE_CHARBUF(receiver_name, 64);
+ Sint tok_label = 0;
+ Sint tok_lastcnt = 0;
+ Sint tok_serial = 0;
+ Eterm utag = NIL;
+ *sender_name = *receiver_name = '\0';
+ if (DTRACE_ENABLED(message_send)) {
+ erts_snprintf(sender_name, sizeof(DTRACE_CHARBUF_NAME(sender_name)),
+ "%T", c_p->common.id);
+ erts_snprintf(receiver_name, sizeof(DTRACE_CHARBUF_NAME(receiver_name)),
+ "%T", rp->common.id);
+ }
+#endif
+ if (have_seqtrace(stoken)) {
+ seq_trace_update_send(c_p);
+ seq_trace_output(stoken, msg, SEQ_TRACE_SEND,
+ rp->common.id, c_p);
+ }
+#ifdef USE_VM_PROBES
+ if (!(DT_UTAG_FLAGS(c_p) & DT_UTAG_SPREADING)) {
+ stoken = NIL;
+ }
+#endif
+ token = enif_make_copy(msg_env, stoken);
+
+#ifdef USE_VM_PROBES
+ if (DT_UTAG_FLAGS(c_p) & DT_UTAG_SPREADING) {
+ if (is_immed(DT_UTAG(c_p)))
+ utag = DT_UTAG(c_p);
+ else
+ utag = enif_make_copy(msg_env, DT_UTAG(c_p));
+ }
+ if (DTRACE_ENABLED(message_send)) {
+ if (have_seqtrace(stoken)) {
+ tok_label = SEQ_TRACE_T_DTRACE_LABEL(stoken);
+ tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(stoken));
+ tok_serial = signed_val(SEQ_TRACE_T_SERIAL(stoken));
+ }
+ DTRACE6(message_send, sender_name, receiver_name,
+ size_object(msg), tok_label, tok_lastcnt, tok_serial);
+ }
+#endif
+ }
flush_env(msg_env);
mp = erts_alloc_message(0, NULL);
+ ERL_MESSAGE_TOKEN(mp) = token;
mp->data.heap_frag = menv->env.heap_frag;
ASSERT(mp->data.heap_frag == MBUF(&menv->phony_proc));
if (mp->data.heap_frag != NULL) {
@@ -783,6 +843,7 @@ int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid,
ohp = &bp->off_heap;
}
}
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
msg = copy_struct_litopt(msg, sz, &hp, ohp, &litarea);
}
@@ -826,6 +887,7 @@ int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid,
ERL_MESSAGE_TERM(mp) = msg;
ERL_MESSAGE_FROM(mp) = from;
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
if (!msgq) {
msgq = erts_alloc(ERTS_ALC_T_TRACE_MSG_QUEUE,
@@ -978,7 +1040,7 @@ ERL_NIF_TERM enif_make_copy(ErlNifEnv* dst_env, ERL_NIF_TERM src_term)
Eterm* hp;
/*
* No preserved sharing allowed as long as literals are also preserved.
- * Process independent environment can not be reached by purge.
+ * Process independent environment cannot be reached by purge.
*/
sz = size_object(src_term);
hp = alloc_heap(dst_env, sz);
@@ -1255,8 +1317,10 @@ size_t enif_binary_to_term(ErlNifEnv *dst_env,
if (is_non_value(*term)) {
return 0;
}
- erts_factory_close(&factory);
- cache_env(dst_env);
+ if (size > 0) {
+ erts_factory_close(&factory);
+ cache_env(dst_env);
+ }
ASSERT(bp > data);
return bp - data;
diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h
index 1906da732b..4c09496ef1 100644
--- a/erts/emulator/beam/erl_nif.h
+++ b/erts/emulator/beam/erl_nif.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2009-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h
index 61f8fcf6ed..81f64f2390 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2009-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_node_container_utils.h b/erts/emulator/beam/erl_node_container_utils.h
index 99e938266b..eb23e1eaa5 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c
index 4a3671df0c..4928d80f27 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2006-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1567,8 +1567,9 @@ fail:
erts_port_dec_refc(pp);
if (ptp) {
- abort_signal_task(pp, ERTS_PROC2PORT_SIG_ABORT,
- ptp->type, &ptp->u.alive.td, 0);
+ if (ptp->type == ERTS_PORT_TASK_PROC_SIG)
+ abort_signal_task(pp, ERTS_PROC2PORT_SIG_ABORT,
+ ptp->type, &ptp->u.alive.td, 0);
port_task_free(ptp);
}
diff --git a/erts/emulator/beam/erl_printf_term.c b/erts/emulator/beam/erl_printf_term.c
index 910f241a3a..990a01b96f 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2005-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c
index 5165cd22a5..f343e984f7 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.c
+++ b/erts/emulator/beam/erl_proc_sig_queue.c
@@ -39,6 +39,7 @@
#include "big.h"
#include "erl_gc.h"
#include "bif.h"
+#include "erl_bif_unique.h"
#include "erl_proc_sig_queue.h"
#include "dtrace-wrapper.h"
@@ -49,10 +50,10 @@
* Note that not all signal are handled using this functionality!
*/
-#define ERTS_SIG_Q_OP_MAX 11
+#define ERTS_SIG_Q_OP_MAX 13
-#define ERTS_SIG_Q_OP_EXIT 0
-#define ERTS_SIG_Q_OP_EXIT_LINKED 1
+#define ERTS_SIG_Q_OP_EXIT 0 /* Exit signal due to bif call */
+#define ERTS_SIG_Q_OP_EXIT_LINKED 1 /* Exit signal due to link break*/
#define ERTS_SIG_Q_OP_MONITOR_DOWN 2
#define ERTS_SIG_Q_OP_MONITOR 3
#define ERTS_SIG_Q_OP_DEMONITOR 4
@@ -62,7 +63,9 @@
#define ERTS_SIG_Q_OP_TRACE_CHANGE_STATE 8
#define ERTS_SIG_Q_OP_PERSISTENT_MON_MSG 9
#define ERTS_SIG_Q_OP_IS_ALIVE 10
-#define ERTS_SIG_Q_OP_PROCESS_INFO ERTS_SIG_Q_OP_MAX
+#define ERTS_SIG_Q_OP_PROCESS_INFO 11
+#define ERTS_SIG_Q_OP_SYNC_SUSPEND 12
+#define ERTS_SIG_Q_OP_RPC ERTS_SIG_Q_OP_MAX
#define ERTS_SIG_Q_TYPE_MAX (ERTS_MON_LNK_TYPE_MAX + 5)
@@ -154,6 +157,17 @@ typedef struct {
} ErtsIsAliveRequest;
typedef struct {
+ Eterm message;
+ Eterm requester;
+ int async;
+} ErtsSyncSuspendRequest;
+
+typedef struct {
+ ErtsMonitorSuspend *mon;
+ ErtsMessage *sync;
+} ErtsProcSigPendingSuspend;
+
+typedef struct {
ErtsSignalCommon common;
Sint refc;
Sint delayed_len;
@@ -176,6 +190,15 @@ typedef struct {
#define ERTS_PROC_SIG_PI_MSGQ_LEN_IGNORE ((Sint) -1)
#define ERTS_PROC_SIG_PI_MSGQ_LEN_SYNC ((Sint) -2)
+typedef struct {
+ ErtsSignalCommon common;
+ Eterm requester;
+ Eterm (*func)(Process *, void *, int *, ErlHeapFragment **);
+ void *arg;
+ Eterm ref;
+ ErtsORefThing oref_thing;
+} ErtsProcSigRPC;
+
static int handle_msg_tracing(Process *c_p,
ErtsSigRecvTracing *tracing,
ErtsMessage ***next_nm_sig);
@@ -400,13 +423,13 @@ sig_enqueue_trace(Process *c_p, ErtsMessage **sigp, int op,
}
static void
-sig_enqueue_trace_cleanup(ErtsMessage *first, ErtsSignal *sig, ErtsMessage *last)
+sig_enqueue_trace_cleanup(ErtsMessage *first, ErtsSignal *sig)
{
ErtsMessage *tmp;
/* The usual case; no tracing signals... */
- if (sig == (ErtsSignal *) first && sig == (ErtsSignal *) last) {
- sig->common.next = NULL;
+ if (sig == (ErtsSignal *) first) {
+ ASSERT(sig->common.next == NULL);
return;
}
@@ -422,6 +445,8 @@ sig_enqueue_trace_cleanup(ErtsMessage *first, ErtsSignal *sig, ErtsMessage *last
case ERTS_SIG_Q_OP_TRACE_CHANGE_STATE:
destroy_trace_info((ErtsSigTraceInfo *) tmp_free);
break;
+ case ERTS_SIG_Q_OP_MONITOR:
+ break; /* ignore flushed pending signal */
default:
ERTS_INTERNAL_ERROR("Unexpected signal op");
break;
@@ -519,41 +544,42 @@ erts_aint32_t erts_enqueue_signals(Process *rp, ErtsMessage *first,
return enqueue_signals(rp, first, last, last_next, num_msgs, in_state);
}
-static ERTS_INLINE void
-ensure_dirty_proc_handled(Eterm pid,
- erts_aint32_t state,
- erts_aint32_t prio)
+void
+erts_make_dirty_proc_handled(Eterm pid,
+ erts_aint32_t state,
+ erts_aint32_t prio)
{
- if (state & (ERTS_PSFLG_DIRTY_RUNNING
- | ERTS_PSFLG_DIRTY_RUNNING_SYS)) {
- Eterm *hp;
- ErtsMessage *mp;
- Process *sig_handler;
+ Eterm *hp;
+ ErtsMessage *mp;
+ Process *sig_handler;
- if (prio < 0)
- prio = (int) ERTS_PSFLGS_GET_USR_PRIO(state);
+ ASSERT(state & (ERTS_PSFLG_DIRTY_RUNNING |
+ ERTS_PSFLG_DIRTY_RUNNING_SYS));
- switch (prio) {
- case PRIORITY_MAX:
- sig_handler = erts_dirty_process_signal_handler_max;
- break;
- case PRIORITY_HIGH:
- sig_handler = erts_dirty_process_signal_handler_high;
- break;
- default:
- sig_handler = erts_dirty_process_signal_handler;
- break;
- }
+ if (prio < 0)
+ prio = (int) ERTS_PSFLGS_GET_USR_PRIO(state);
- /* Make sure signals are handled... */
- mp = erts_alloc_message(0, &hp);
- erts_queue_message(sig_handler, 0, mp, pid, am_system);
+ switch (prio) {
+ case PRIORITY_MAX:
+ sig_handler = erts_dirty_process_signal_handler_max;
+ break;
+ case PRIORITY_HIGH:
+ sig_handler = erts_dirty_process_signal_handler_high;
+ break;
+ default:
+ sig_handler = erts_dirty_process_signal_handler;
+ break;
}
+
+ /* Make sure signals are handled... */
+ mp = erts_alloc_message(0, &hp);
+ erts_queue_message(sig_handler, 0, mp, pid, am_system);
}
static void
check_push_msgq_len_offs_marker(Process *rp, ErtsSignal *sig);
+
static int
proc_queue_signal(Process *c_p, Eterm pid, ErtsSignal *sig, int op)
{
@@ -643,7 +669,7 @@ proc_queue_signal(Process *c_p, Eterm pid, ErtsSignal *sig, int op)
first_last_done:
sig->common.specific.next = NULL;
- /* may add signals before and/or after sig */
+ /* may add signals before sig */
sig_enqueue_trace(c_p, sigp, op, rp, &last_next);
last->next = NULL;
@@ -664,29 +690,18 @@ first_last_done:
erts_proc_unlock(rp, ERTS_PROC_LOCK_MSGQ);
if (res == 0) {
+ sig_enqueue_trace_cleanup(first, sig);
if (pend_sig) {
+ erts_proc_sig_send_monitor_down((ErtsMonitor*)pend_sig, am_noproc);
if (sig == pend_sig) {
/* We did a switch, callers signal is now pending (still ok) */
ASSERT(esdp->pending_signal.sig);
res = 1;
}
- else {
- ASSERT(first == (ErtsMessage*)pend_sig);
- first = first->next;
- }
- erts_proc_sig_send_monitor_down((ErtsMonitor*)pend_sig, am_noproc);
}
- sig_enqueue_trace_cleanup(first, sig, last);
}
-
- if (!(state & (ERTS_PSFLG_EXITING
- | ERTS_PSFLG_ACTIVE_SYS
- | ERTS_PSFLG_SIG_IN_Q))) {
- /* Schedule process... */
- state = erts_proc_sys_schedule(rp, state, 0);
- }
-
- ensure_dirty_proc_handled(rp->common.id, state, -1);
+ else
+ erts_proc_notify_new_sig(rp, state, 0);
if (!is_normal_sched)
erts_proc_dec_refc(rp);
@@ -742,7 +757,10 @@ maybe_elevate_sig_handling_prio(Process *c_p, Eterm other)
if (res) {
/* ensure handled if dirty executing... */
state = erts_atomic32_read_nob(&rp->state);
- ensure_dirty_proc_handled(other, state, my_prio);
+ if (state & (ERTS_PSFLG_DIRTY_RUNNING
+ | ERTS_PSFLG_DIRTY_RUNNING_SYS)) {
+ erts_make_dirty_proc_handled(other, state, my_prio);
+ }
}
}
}
@@ -1149,10 +1167,7 @@ erts_proc_sig_send_persistent_monitor_msg(Uint16 type, Eterm key,
ERL_MESSAGE_TERM(mp) = ERTS_PROC_SIG_MAKE_TAG(ERTS_SIG_Q_OP_PERSISTENT_MON_MSG,
type, 0);
ERL_MESSAGE_FROM(mp) = from;
- ERL_MESSAGE_TOKEN(mp) = NIL;
-#ifdef USE_VM_PROBES
- ERL_MESSAGE_DT_UTAG(mp) = NIL;
-#endif
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
if (!proc_queue_signal(NULL, to, (ErtsSignal *) mp,
ERTS_SIG_Q_OP_PERSISTENT_MON_MSG)) {
@@ -1311,6 +1326,8 @@ erts_proc_sig_send_monitor_down(ErtsMonitor *mon, Eterm reason)
/* Pass signal using old monitor structure... */
ErtsSignal *sig;
+ send_using_monitor_struct:
+
mon->other.item = reason; /* Pass immed reason via other.item... */
sig = (ErtsSignal *) mon;
sig->common.tag = ERTS_PROC_SIG_MAKE_TAG(ERTS_SIG_Q_OP_MONITOR_DOWN,
@@ -1322,6 +1339,18 @@ erts_proc_sig_send_monitor_down(ErtsMonitor *mon, Eterm reason)
ErtsMonitorData *mdp = erts_monitor_to_data(mon);
Eterm from_tag, monitored, heap[3];
+ if (mon->type == ERTS_MON_TYPE_SUSPEND) {
+ /*
+ * Set reason to 'undefined', since exit
+ * reason is not used for suspend monitors,
+ * and send using monitor structure. This
+ * since we don't want to trigger
+ * unnecessary memory allocation etc...
+ */
+ reason = am_undefined;
+ goto send_using_monitor_struct;
+ }
+
if (!(mon->flags & ERTS_ML_FLG_NAME)) {
from_tag = monitored = mdp->origin.other.item;
if (is_external_pid(from_tag)) {
@@ -1532,11 +1561,6 @@ erts_proc_sig_send_is_alive_request(Process *c_p, Eterm to, Eterm ref)
ERL_MESSAGE_TERM(mp) = ERTS_PROC_SIG_MAKE_TAG(ERTS_SIG_Q_OP_IS_ALIVE,
ERTS_SIG_Q_TYPE_UNDEFINED,
0);
- ERL_MESSAGE_TOKEN(mp) = NIL;
- ERL_MESSAGE_FROM(mp) = am_system;
-#ifdef USE_VM_PROBES
- ERL_MESSAGE_DT_UTAG(mp) = NIL;
-#endif
if (proc_queue_signal(c_p, to, (ErtsSignal *) mp, ERTS_SIG_Q_OP_IS_ALIVE))
(void) maybe_elevate_sig_handling_prio(c_p, to);
@@ -1599,7 +1623,168 @@ erts_proc_sig_send_process_info_request(Process *c_p,
else
erts_free(ERTS_ALC_T_SIG_DATA, pis);
return res;
-}
+}
+
+void
+erts_proc_sig_send_sync_suspend(Process *c_p, Eterm to, Eterm tag, Eterm reply)
+{
+ ErlHeapFragment *hfrag;
+ Uint hsz, tag_sz;
+ Eterm *hp, *start_hp, tag_cpy, msg, default_reply;
+ ErlOffHeap *ohp;
+ ErtsMessage *mp;
+ ErtsSyncSuspendRequest *ssusp;
+ int async_suspend;
+
+ tag_sz = size_object(tag);
+
+ hsz = 3 + tag_sz + sizeof(ErtsSyncSuspendRequest)/sizeof(Eterm);
+
+ mp = erts_alloc_message(hsz, &hp);
+ hfrag = &mp->hfrag;
+ mp->next = NULL;
+ ohp = &hfrag->off_heap;
+ start_hp = hp;
+
+ tag_cpy = copy_struct(tag, tag_sz, &hp, ohp);
+
+ async_suspend = is_non_value(reply);
+ default_reply = async_suspend ? am_suspended : reply;
+
+ msg = TUPLE2(hp, tag_cpy, default_reply);
+ hp += 3;
+
+ hfrag->used_size = hp - start_hp;
+
+ ssusp = (ErtsSyncSuspendRequest *) (char *) hp;
+ ssusp->message = msg;
+ ssusp->requester = c_p->common.id;
+ ssusp->async = async_suspend;
+
+ ERL_MESSAGE_TERM(mp) = ERTS_PROC_SIG_MAKE_TAG(ERTS_SIG_Q_OP_SYNC_SUSPEND,
+ ERTS_SIG_Q_TYPE_UNDEFINED,
+ 0);
+
+ if (proc_queue_signal(c_p, to, (ErtsSignal *) mp, ERTS_SIG_Q_OP_SYNC_SUSPEND))
+ (void) maybe_elevate_sig_handling_prio(c_p, to);
+ else {
+ Eterm *tp;
+ /* It wasn't alive; reply to ourselves... */
+ mp->next = NULL;
+ mp->data.attached = ERTS_MSG_COMBINED_HFRAG;
+ tp = tuple_val(msg);
+ tp[2] = async_suspend ? am_badarg : am_exited;
+ erts_queue_message(c_p, ERTS_PROC_LOCK_MAIN,
+ mp, msg, am_system);
+ }
+}
+
+Eterm
+erts_proc_sig_send_rpc_request(Process *c_p,
+ Eterm to,
+ int reply,
+ Eterm (*func)(Process *, void *, int *, ErlHeapFragment **),
+ void *arg)
+{
+ Eterm res;
+ ErtsProcSigRPC *sig = erts_alloc(ERTS_ALC_T_SIG_DATA,
+ sizeof(ErtsProcSigRPC));
+ sig->common.tag = ERTS_PROC_SIG_MAKE_TAG(ERTS_SIG_Q_OP_RPC,
+ ERTS_SIG_Q_TYPE_UNDEFINED,
+ 0);
+ sig->requester = reply ? c_p->common.id : NIL;
+ sig->func = func;
+ sig->arg = arg;
+
+ if (!reply) {
+ res = am_ok;
+ sig->ref = am_ok;
+ }
+ else {
+ res = erts_make_ref(c_p);
+
+ sys_memcpy((void *) &sig->oref_thing,
+ (void *) internal_ref_val(res),
+ sizeof(ErtsORefThing));
+
+ sig->ref = make_internal_ref(&sig->oref_thing);
+
+ ERTS_RECV_MARK_SAVE(c_p);
+ ERTS_RECV_MARK_SET(c_p);
+ }
+
+ if (proc_queue_signal(c_p, to, (ErtsSignal *) sig, ERTS_SIG_Q_OP_RPC))
+ (void) maybe_elevate_sig_handling_prio(c_p, to);
+ else {
+ erts_free(ERTS_ALC_T_SIG_DATA, sig);
+ res = THE_NON_VALUE;
+ if (reply)
+ JOIN_MESSAGE(c_p);
+ }
+
+ return res;
+}
+
+static int
+handle_rpc(Process *c_p, ErtsProcSigRPC *rpc, int cnt, int limit, int *yieldp)
+{
+ Process *rp;
+ ErlHeapFragment *bp = NULL;
+ Eterm res;
+ Uint hsz;
+ int reds, out_cnt;
+
+ /*
+ * reds in:
+ * Reductions left.
+ *
+ * reds out:
+ * Absolute value of reds out equals consumed
+ * amount of reds. If a negative value, force
+ * a yield.
+ */
+
+ reds = (limit - cnt) / ERTS_SIG_REDS_CNT_FACTOR;
+ if (reds <= 0)
+ reds = 1;
+
+ res = (*rpc->func)(c_p, rpc->arg, &reds, &bp);
+
+ if (reds < 0) {
+ /* Force yield... */
+ *yieldp = !0;
+ reds *= -1;
+ }
+
+ out_cnt = reds*ERTS_SIG_REDS_CNT_FACTOR;
+
+ hsz = 3 + sizeof(ErtsORefThing)/sizeof(Eterm);
+
+ rp = erts_proc_lookup(rpc->requester);
+ if (!rp) {
+ if (bp)
+ free_message_buffer(bp);
+ }
+ else {
+ Eterm *hp, msg, ref;
+ ErtsMessage *mp = erts_alloc_message(hsz, &hp);
+
+ sys_memcpy((void *) hp, (void *) &rpc->oref_thing,
+ sizeof(rpc->oref_thing));
+
+ ref = make_internal_ref(hp);
+ hp += sizeof(rpc->oref_thing)/sizeof(Eterm);
+ msg = TUPLE2(hp, ref, res);
+
+ mp->hfrag.next = bp;
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
+ erts_queue_proc_message(c_p, rp, 0, mp, msg);
+ }
+
+ erts_free(ERTS_ALC_T_SIG_DATA, rpc);
+
+ return out_cnt;
+}
static void
is_alive_response(Process *c_p, ErtsMessage *mp, int is_alive)
@@ -1957,10 +2142,7 @@ handle_exit_signal(Process *c_p, ErtsSigRecvTracing *tracing,
pid = STORE_NC(&hp, ohp, from);
ERL_MESSAGE_TERM(mp) = TUPLE3(hp, am_EXIT, pid, reason);
- ERL_MESSAGE_TOKEN(mp) = NIL;
-#ifdef USE_VM_PROBES
- ERL_MESSAGE_DT_UTAG(mp) = NIL;
-#endif
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
if (is_immed(pid))
ERL_MESSAGE_FROM(mp) = pid;
else {
@@ -2148,10 +2330,7 @@ convert_to_down_message(Process *c_p,
type, from, reason);
hp += 6;
- ERL_MESSAGE_TOKEN(mp) = NIL;
-#ifdef USE_VM_PROBES
- ERL_MESSAGE_DT_UTAG(mp) = NIL;
-#endif
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
/* Replace original signal with the exit message... */
convert_to_msg(c_p, sig, mp, next_nm_sig);
@@ -2199,10 +2378,7 @@ convert_to_nodedown_messages(Process *c_p,
ERL_MESSAGE_TERM(mp) = TUPLE2(hp, am_nodedown, node);
ERL_MESSAGE_FROM(mp) = am_system;
- ERL_MESSAGE_TOKEN(mp) = NIL;
-#ifdef USE_VM_PROBES
- ERL_MESSAGE_DT_UTAG(mp) = NIL;
-#endif
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
mp->next = nd_first;
nd_first = mp;
if (!nd_last)
@@ -2525,6 +2701,9 @@ handle_process_info(Process *c_p, ErtsSigRecvTracing *tracing,
Uint reds = 0;
Process *rp;
+ ASSERT(!!is_alive == !(erts_atomic32_read_nob(&c_p->state)
+ & ERTS_PSFLG_EXITING));
+
if (pisig->msgq_len_offset != ERTS_PROC_SIG_PI_MSGQ_LEN_IGNORE) {
/*
* Request requires message queue data to be updated
@@ -2629,6 +2808,7 @@ handle_process_info(Process *c_p, ErtsSigRecvTracing *tracing,
if (is_alive)
erts_factory_trim_and_close(&hfact, &msg, 1);
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
erts_queue_proc_message(c_p, rp, locks, mp, msg);
if (!is_alive && locks)
@@ -2643,6 +2823,156 @@ handle_process_info(Process *c_p, ErtsSigRecvTracing *tracing,
return ((int) reds)*4 + 8;
}
+static void
+handle_suspend(Process *c_p, ErtsMonitor *mon, int *yieldp)
+{
+ erts_aint32_t state = erts_atomic32_read_nob(&c_p->state);
+
+ ASSERT(mon->type == ERTS_MON_TYPE_SUSPEND);
+
+ if (!(state & ERTS_PSFLG_DIRTY_RUNNING)) {
+ ErtsMonitorSuspend *msp;
+ erts_aint_t mstate;
+
+ msp = (ErtsMonitorSuspend *) erts_monitor_to_data(mon);
+ mstate = erts_atomic_read_bor_acqb(&msp->state,
+ ERTS_MSUSPEND_STATE_FLG_ACTIVE);
+ ASSERT(!(mstate & ERTS_MSUSPEND_STATE_FLG_ACTIVE)); (void) mstate;
+ erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL);
+ *yieldp = !0;
+ }
+ else {
+ /* Executing dirty; delay suspend... */
+ ErtsProcSigPendingSuspend *psusp;
+ ErtsMonitorSuspend *msp;
+
+ psusp = ERTS_PROC_GET_PENDING_SUSPEND(c_p);
+ if (!psusp) {
+ psusp = erts_alloc(ERTS_ALC_T_SIG_DATA,
+ sizeof(ErtsProcSigPendingSuspend));
+ psusp->mon = NULL;
+ psusp->sync = NULL;
+ ERTS_PROC_SET_PENDING_SUSPEND(c_p, (void *) psusp);
+ }
+
+ msp = (ErtsMonitorSuspend *) erts_monitor_to_data(mon);
+
+ msp->next = psusp->mon;
+ psusp->mon = msp;
+
+ erts_atomic32_inc_nob(&msp->md.refc);
+ }
+}
+
+static void
+sync_suspend_reply(Process *c_p, ErtsMessage *mp, erts_aint32_t state)
+{
+ /*
+ * Sender prepared the message for us. Just patch
+ * the result if necessary. The default prepared
+ * result is 'false'.
+ */
+ Process *rp;
+ ErtsSyncSuspendRequest *ssusp;
+
+ ssusp = (ErtsSyncSuspendRequest *) (char *) (&mp->hfrag.mem[0]
+ + mp->hfrag.used_size);
+
+ ASSERT(ERTS_SIG_IS_NON_MSG(mp));
+ ASSERT(ERTS_PROC_SIG_OP(((ErtsSignal *) mp)->common.tag)
+ == ERTS_SIG_Q_OP_SYNC_SUSPEND);
+ ASSERT(mp->hfrag.alloc_size > mp->hfrag.used_size);
+ ASSERT((mp->hfrag.alloc_size - mp->hfrag.used_size)*sizeof(UWord)
+ >= sizeof(ErtsSyncSuspendRequest));
+ ASSERT(is_internal_pid(ssusp->requester));
+ ASSERT(ssusp->requester != c_p->common.id);
+ ASSERT(is_tuple_arity(ssusp->message, 2));
+ ASSERT(is_immed(tuple_val(ssusp->message)[2]));
+
+ ERL_MESSAGE_TERM(mp) = ssusp->message;
+ mp->data.attached = ERTS_MSG_COMBINED_HFRAG;
+ mp->next = NULL;
+
+ rp = erts_proc_lookup(ssusp->requester);
+ if (!rp)
+ erts_cleanup_messages(mp);
+ else {
+ if ((state & (ERTS_PSFLG_EXITING
+ | ERTS_PSFLG_SUSPENDED)) != ERTS_PSFLG_SUSPENDED) {
+ /* Not suspended -> patch result... */
+ if (state & ERTS_PSFLG_EXITING) {
+ Eterm *tp = tuple_val(ssusp->message);
+ tp[2] = ssusp->async ? am_exited : am_badarg;
+ }
+ else {
+ Eterm *tp = tuple_val(ssusp->message);
+ ASSERT(!(state & ERTS_PSFLG_SUSPENDED));
+ tp[2] = ssusp->async ? am_not_suspended : am_internal_error;
+ }
+ }
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
+ erts_queue_proc_message(c_p, rp, 0, mp, ssusp->message);
+ }
+}
+
+static void
+handle_sync_suspend(Process *c_p, ErtsMessage *mp)
+{
+ ErtsProcSigPendingSuspend *psusp;
+
+ psusp = (ErtsProcSigPendingSuspend *) ERTS_PROC_GET_PENDING_SUSPEND(c_p);
+ if (!psusp)
+ sync_suspend_reply(c_p, mp, erts_atomic32_read_nob(&c_p->state));
+ else {
+ mp->next = psusp->sync;
+ psusp->sync = mp;
+ }
+}
+
+void
+erts_proc_sig_handle_pending_suspend(Process *c_p)
+{
+ ErtsMonitorSuspend *msp;
+ ErtsMessage *sync;
+ ErtsProcSigPendingSuspend *psusp;
+ erts_aint32_t state = erts_atomic32_read_nob(&c_p->state);
+
+ psusp = (ErtsProcSigPendingSuspend *) ERTS_PROC_GET_PENDING_SUSPEND(c_p);
+
+ msp = psusp->mon;
+
+ while (msp) {
+ ErtsMonitorSuspend *next_msp = msp->next;
+ msp->next = NULL;
+ if (!(state & ERTS_PSFLG_EXITING)
+ && erts_monitor_is_in_table(&msp->md.target)) {
+ erts_aint_t mstate;
+
+ mstate = erts_atomic_read_bor_acqb(&msp->state,
+ ERTS_MSUSPEND_STATE_FLG_ACTIVE);
+ ASSERT(!(mstate & ERTS_MSUSPEND_STATE_FLG_ACTIVE)); (void) mstate;
+ erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL);
+ }
+
+ erts_monitor_release(&msp->md.target);
+
+ msp = next_msp;
+ }
+
+ sync = psusp->sync;
+
+ while (sync) {
+ ErtsMessage *next_sync = sync->next;
+ sync->next = NULL;
+ sync_suspend_reply(c_p, sync, state);
+ sync = next_sync;
+ }
+
+ erts_free(ERTS_ALC_T_SIG_DATA, psusp);
+
+ ERTS_PROC_SET_PENDING_SUSPEND(c_p, NULL);
+}
+
/*
* Called in order to handle incoming signals.
*/
@@ -2653,17 +2983,15 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep,
{
Eterm tag;
erts_aint32_t state;
- int cnt, limit, abs_lim, msg_tracing;
+ int yield, cnt, limit, abs_lim, msg_tracing;
ErtsMessage *sig, ***next_nm_sig;
ErtsSigRecvTracing tracing;
ERTS_HDBG_CHECK_SIGNAL_PRIV_QUEUE(c_p, 0);
ERTS_LC_ASSERT(ERTS_PROC_LOCK_MAIN == erts_proc_lc_my_proc_locks(c_p));
- if (local_only)
- state = -1; /* can never be a valid state... */
- else {
- state = erts_atomic32_read_nob(&c_p->state);
+ state = erts_atomic32_read_nob(&c_p->state);
+ if (!local_only) {
if (ERTS_PSFLG_SIG_IN_Q & state) {
erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ);
erts_proc_sig_fetch(c_p);
@@ -2673,15 +3001,18 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep,
limit = *redsp;
*redsp = 0;
+ yield = 0;
if (!c_p->sig_qs.cont) {
- if (state == -1)
- *statep = erts_atomic32_read_nob(&c_p->state);
- else
- *statep = state;
+ *statep = state;
return !0;
}
+ if (state & ERTS_PSFLG_EXITING) {
+ *statep = state;
+ return 0;
+ }
+
next_nm_sig = &c_p->sig_qs.nmsigs.next;
setup_tracing_state(c_p, &tracing);
@@ -2786,6 +3117,18 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep,
cnt += handle_nodedown(c_p, sig, mdp, next_nm_sig);
}
break;
+ case ERTS_MON_TYPE_SUSPEND:
+ tmon = (ErtsMonitor *) sig;
+ ASSERT(erts_monitor_is_target(tmon));
+ ASSERT(!erts_monitor_is_in_table(tmon));
+ mdp = erts_monitor_to_data(tmon);
+ if (erts_monitor_is_in_table(&mdp->origin)) {
+ erts_monitor_tree_delete(&ERTS_P_MONITORS(c_p),
+ &mdp->origin);
+ omon = &mdp->origin;
+ remove_nm_sig(c_p, sig, next_nm_sig);
+ }
+ break;
default:
ERTS_INTERNAL_ERROR("invalid monitor type");
break;
@@ -2849,9 +3192,13 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep,
if (mon->type == ERTS_MON_TYPE_DIST_PROC)
erts_monitor_tree_insert(&ERTS_P_MONITORS(c_p), mon);
- else
+ else {
erts_monitor_list_insert(&ERTS_P_LT_MONITORS(c_p), mon);
+ if (mon->type == ERTS_MON_TYPE_SUSPEND)
+ handle_suspend(c_p, mon, &yield);
+ }
ERTS_PROC_SIG_HDBG_PRIV_CHKQ(c_p, &tracing, next_nm_sig);
+ cnt += 2;
break;
}
@@ -2895,9 +3242,16 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep,
erts_monitor_tree_delete(&ERTS_P_MONITORS(c_p), tmon);
else {
erts_monitor_list_delete(&ERTS_P_LT_MONITORS(c_p), tmon);
- if (type == ERTS_MON_TYPE_RESOURCE) {
+ switch (type) {
+ case ERTS_MON_TYPE_RESOURCE:
erts_nif_demonitored((ErtsResource *) tmon->other.ptr);
cnt++;
+ break;
+ case ERTS_MON_TYPE_SUSPEND:
+ erts_resume(c_p, ERTS_PROC_LOCK_MAIN);
+ break;
+ default:
+ break;
}
}
erts_monitor_release_both(mdp);
@@ -3012,6 +3366,21 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep,
ERTS_PROC_SIG_HDBG_PRIV_CHKQ(c_p, &tracing, next_nm_sig);
break;
+ case ERTS_SIG_Q_OP_SYNC_SUSPEND:
+ ERTS_PROC_SIG_HDBG_PRIV_CHKQ(c_p, &tracing, next_nm_sig);
+ remove_nm_sig(c_p, sig, next_nm_sig);
+ handle_sync_suspend(c_p, sig);
+ ERTS_PROC_SIG_HDBG_PRIV_CHKQ(c_p, &tracing, next_nm_sig);
+ break;
+
+ case ERTS_SIG_Q_OP_RPC:
+ ERTS_PROC_SIG_HDBG_PRIV_CHKQ(c_p, &tracing, next_nm_sig);
+ remove_nm_sig(c_p, sig, next_nm_sig);
+ cnt += handle_rpc(c_p, (ErtsProcSigRPC *) sig, cnt,
+ limit, &yield);
+ ERTS_PROC_SIG_HDBG_PRIV_CHKQ(c_p, &tracing, next_nm_sig);
+ break;
+
case ERTS_SIG_Q_OP_TRACE_CHANGE_STATE: {
Uint16 type = ERTS_PROC_SIG_TYPE(tag);
@@ -3169,6 +3538,15 @@ stop: {
*redsp = cnt/4 + 1;
+ if (yield) {
+ int vreds = max_reds - *redsp;
+ if (vreds > 0) {
+ ErtsSchedulerData *esdp = erts_get_scheduler_data();
+ esdp->virtual_reds += vreds;
+ }
+ *redsp = max_reds;
+ }
+
return res;
}
}
@@ -3277,6 +3655,8 @@ erts_proc_sig_handle_exit(Process *c_p, int *redsp)
case ERTS_MON_TYPE_PROC:
case ERTS_MON_TYPE_DIST_PROC:
case ERTS_MON_TYPE_NODE:
+ case ERTS_MON_TYPE_NODES:
+ case ERTS_MON_TYPE_SUSPEND:
erts_monitor_release((ErtsMonitor *) sig);
break;
default:
@@ -3332,6 +3712,17 @@ erts_proc_sig_handle_exit(Process *c_p, int *redsp)
handle_process_info(c_p, NULL, sig, next_nm_sig, 0);
break;
+ case ERTS_SIG_Q_OP_SYNC_SUSPEND:
+ handle_sync_suspend(c_p, sig);
+ break;
+
+ case ERTS_SIG_Q_OP_RPC: {
+ int yield = 0;
+ handle_rpc(c_p, (ErtsProcSigRPC *) sig,
+ cnt, limit, &yield);
+ break;
+ }
+
case ERTS_SIG_Q_OP_TRACE_CHANGE_STATE:
destroy_trace_info((ErtsSigTraceInfo *) sig);
break;
@@ -3467,6 +3858,7 @@ erts_proc_sig_signal_size(ErtsSignal *sig)
}
break;
+ case ERTS_SIG_Q_OP_SYNC_SUSPEND:
case ERTS_SIG_Q_OP_PERSISTENT_MON_MSG:
case ERTS_SIG_Q_OP_IS_ALIVE:
size = ((ErtsMessage *) sig)->hfrag.alloc_size;
@@ -3522,6 +3914,10 @@ erts_proc_sig_signal_size(ErtsSignal *sig)
break;
}
+ case ERTS_SIG_Q_OP_RPC:
+ size = sizeof(ErtsProcSigRPC);
+ break;
+
default:
ERTS_INTERNAL_ERROR("Unknown signal");
break;
@@ -3598,17 +3994,13 @@ erts_proc_sig_receive_helper(Process *c_p,
*/
*get_outp = 0;
*msgpp = NULL;
+
return consumed_reds;
}
erts_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ);
- if (left_reds <= 0) {
- *get_outp = -1; /* yield */
- *msgpp = NULL;
-
- ASSERT(consumed_reds >= (fcalls - neg_o_reds));
- return consumed_reds;
- }
+ if (left_reds <= 0)
+ break; /* Yield */
/* handle newly arrived signals... */
}
@@ -3629,19 +4021,27 @@ erts_proc_sig_receive_helper(Process *c_p,
max_reds, !0);
consumed_reds += reds;
left_reds -= reds;
- /* we may have exited by an incoming signal... */
- if (state & ERTS_PSFLG_EXITING) {
+
+ /* we may have exited or suspended by an incoming signal... */
+
+ if (state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_SUSPENDED)) {
+ if (state & ERTS_PSFLG_SUSPENDED)
+ break; /* Yield */
+
/*
* Process need to schedule out in order
* to terminate. Prepare this a bit...
*/
+ ASSERT(state & ERTS_PSFLG_EXITING);
ASSERT(c_p->flags & F_DELAY_GC);
c_p->flags &= ~F_DELAY_GC;
c_p->arity = 0;
c_p->current = NULL;
+
*get_outp = 1;
*msgpp = NULL;
+
return consumed_reds;
}
@@ -3652,17 +4052,20 @@ erts_proc_sig_receive_helper(Process *c_p,
return consumed_reds;
}
- if (left_reds <= 0) {
- *get_outp = -1; /* yield */
- *msgpp = NULL;
-
- ASSERT(consumed_reds >= (fcalls - neg_o_reds));
- return consumed_reds;
- }
+ if (left_reds <= 0)
+ break; /* yield */
ASSERT(!c_p->sig_qs.cont);
/* Go fetch again... */
}
+
+ /* Yield... */
+
+ *get_outp = -1;
+ *msgpp = NULL;
+
+ ASSERT(consumed_reds >= (fcalls - neg_o_reds));
+ return consumed_reds;
}
static int
diff --git a/erts/emulator/beam/erl_proc_sig_queue.h b/erts/emulator/beam/erl_proc_sig_queue.h
index 8b7cd35f61..3fc2d06b2d 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.h
+++ b/erts/emulator/beam/erl_proc_sig_queue.h
@@ -33,6 +33,11 @@
* - Group leader
* - Is process alive
* - Process info request
+ * - Suspend request (monitor of suspend type)
+ * - Resume request (demonitor of suspend type)
+ * - Suspend cleanup (monitor down of suspend type)
+ * - Sync suspend
+ * - RPC request
* - Trace change
*
* The signal queue consists of three parts:
@@ -557,6 +562,102 @@ erts_proc_sig_send_process_info_request(Process *c_p,
Uint reserve_size,
Eterm ref);
+/**
+ *
+ * @brief Send a 'sync suspend' signal to a process.
+ *
+ * A response message '{Tag, Reply}' is sent to the
+ * sender when performed where Tag is the term passed
+ * as 'tag' argument. Reply is either 'suspended',
+ * 'not_suspended', 'exited' if the operation is
+ * asynchronous; otherwise, the 'reply' argument or
+ * 'badarg' if process terminated.
+ *
+ * This signal does *not* change the suspend state, only
+ * reads and reply the state. This signal is typically
+ * sent after a suspend request (monitor of suspend type)
+ * signal has been sent to the process in order to get a
+ * response when the suspend monitor has been processed.
+ *
+ * @param[in] c_p Pointer to process struct of
+ * currently executing process.
+ *
+ * @param[in] to Identifier of receiver.
+ *
+ * @param[in] tag Tag to use in response
+ * message to the sending
+ * process (i.e., c_p).
+ *
+ * @param[in] reply Reply to send if this
+ * is a synchronous operation;
+ * otherwise, THE_NON_VALUE.
+ */
+void
+erts_proc_sig_send_sync_suspend(Process *c_p, Eterm to,
+ Eterm tag, Eterm reply);
+
+/**
+ *
+ * @brief Send an 'rpc' signal to a process.
+ *
+ * The function 'func' will be executed in the
+ * context of the receiving process. A response
+ * message '{Ref, Result}' is sent to the sender
+ * when 'func' has been called. 'Ref' is the reference
+ * returned by this function and 'Result' is the
+ * term returned by 'func'. If the return value of
+ * 'func' is not an immediate term, 'func' has to
+ * allocate a heap fragment where the result is stored
+ * and update the the heap fragment pointer pointer
+ * passed as third argument to point to it.
+ *
+ * If this function returns a reference, 'func' will
+ * be called in the context of the receiver. However,
+ * note that this might happen when the receiver is in
+ * an exiting state. The caller of this function
+ * *unconditionally* has to enter a receive that match
+ * on the returned reference in all clauses as next
+ * receive; otherwise, bad things will happen!
+ *
+ * If THE_NON_VALUE is returned, the receiver did not
+ * exist. The signal was not sent, and no specific
+ * receive has to be entered by the caller.
+ *
+ * @param[in] c_p Pointer to process struct of
+ * currently executing process.
+ *
+ * @param[in] to Identifier of receiver process.
+ *
+ * @param[in] reply Non-zero if a reply is wanted.
+ *
+ * @param[in] func Function to execute in the
+ * context of the receiver.
+ * First argument will be a
+ * pointer to the process struct
+ * of the receiver process.
+ * Second argument will be 'arg'
+ * (see below). Third argument
+ * will be a pointer to a pointer
+ * to a heap fragment for storage
+ * of result returned from 'func'
+ * (i.e. an 'out' parameter).
+ *
+ * @param[in] arg Void pointer to argument
+ * to pass as second argument
+ * in call of 'func'.
+ *
+ * @returns If the request was sent,
+ * an internal ordinary
+ * reference; otherwise,
+ * THE_NON_VALUE (non-existing
+ * receiver).
+ */
+Eterm
+erts_proc_sig_send_rpc_request(Process *c_p,
+ Eterm to,
+ int reply,
+ Eterm (*func)(Process *, void *, int *, ErlHeapFragment **),
+ void *arg);
/*
* End of send operations of currently supported process signals.
@@ -733,17 +834,50 @@ Sint
erts_proc_sig_privqs_len(Process *c_p);
-/* SVERK: Doc me up! */
+/**
+ * @brief Enqueue list of signals on process.
+ *
+ * Message queue must be locked on receiving process.
+ *
+ * @param rp Receiving process.
+ * @param first First signal in list.
+ * @param last Last signal in list.
+ * @param last_next Pointer to next-pointer to last non-message signal
+ * or NULL if no non-message signal after 'first'.
+ * @param msg_cnt Number of message signals in list.
+ * @param in_state 'state' of rp.
+ *
+ * @return 'state' of rp.
+ */
erts_aint32_t
erts_enqueue_signals(Process *rp, ErtsMessage *first,
ErtsMessage **last, ErtsMessage **last_next,
Uint msg_cnt,
erts_aint32_t in_state);
-/* SVERK: Doc me up! */
+/**
+ *
+ * @brief Flush pending signal.
+ *
+ */
void
erts_proc_sig_send_pending(ErtsSchedulerData* esdp);
+/**
+ *
+ * @brief Schedule process to handle enqueued signal(s).
+ *
+ * @param rp Receiving process.
+ * @param state 'state' of rp.
+ * @param enable_flag Additional state flags to enable, like
+ * ERTS_PSFLG_ACTIVE if message has been enqueued.
+ */
+ERTS_GLB_INLINE void erts_proc_notify_new_sig(Process* rp, erts_aint32_t state,
+ erts_aint32_t enable_flag);
+
+void erts_make_dirty_proc_handled(Eterm pid, erts_aint32_t state,
+ erts_aint32_t prio);
+
typedef struct {
Uint size;
@@ -813,6 +947,21 @@ void
erts_proc_sig_clear_seq_trace_tokens(Process *c_p);
/**
+ *
+ * @brief Handle pending suspend requests
+ *
+ * Should be called by processes when they stop
+ * execution on a dirty scheduler if they have
+ * pending suspend requests (i.e. when
+ * ERTS_PROC_GET_PENDING_SUSPEND(c_p) != NULL).
+ *
+ * @param[in] c_p Pointer to executing
+ * process
+ */
+void
+erts_proc_sig_handle_pending_suspend(Process *c_p);
+
+/**
* @brief Initialize this functionality
*/
void erts_proc_sig_queue_init(void);
@@ -879,6 +1028,24 @@ erts_proc_sig_fetch(Process *proc)
return res;
}
+ERTS_GLB_INLINE void
+erts_proc_notify_new_sig(Process* rp, erts_aint32_t state,
+ erts_aint32_t enable_flag)
+{
+ if (~(state & (ERTS_PSFLG_EXITING
+ | ERTS_PSFLG_ACTIVE_SYS
+ | ERTS_PSFLG_SIG_IN_Q))
+ | (~state & enable_flag)) {
+ /* Schedule process... */
+ state = erts_proc_sys_schedule(rp, state, enable_flag);
+ }
+
+ if (state & (ERTS_PSFLG_DIRTY_RUNNING
+ | ERTS_PSFLG_DIRTY_RUNNING_SYS)) {
+ erts_make_dirty_proc_handled(rp->common.id, state, -1);
+ }
+}
+
#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */
#endif /* ERTS_PROC_SIG_QUEUE_H__ */
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index ad7ac27ac3..9386f79b56 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -185,8 +185,6 @@ sched_get_busy_wait_params(ErtsSchedulerData *esdp)
return &sched_busy_wait_params[esdp->type];
}
-int erts_disable_proc_not_running_opt;
-
static ErtsAuxWorkData *aux_thread_aux_work_data;
static ErtsAuxWorkData *poll_thread_aux_work_data;
@@ -730,6 +728,11 @@ erts_pre_init_process(void)
= ERTS_PSD_DIST_ENTRY_GET_LOCKS;
erts_psd_required_locks[ERTS_PSD_DIST_ENTRY].set_locks
= ERTS_PSD_DIST_ENTRY_SET_LOCKS;
+
+ erts_psd_required_locks[ERTS_PSD_PENDING_SUSPEND].get_locks
+ = ERTS_PSD_PENDING_SUSPEND_GET_LOCKS;
+ erts_psd_required_locks[ERTS_PSD_PENDING_SUSPEND].set_locks
+ = ERTS_PSD_PENDING_SUSPEND_SET_LOCKS;
#endif
}
@@ -744,7 +747,6 @@ void
erts_init_process(int ncpu, int proc_tab_size, int legacy_proc_tab)
{
- erts_disable_proc_not_running_opt = 0;
erts_init_proc_lock(ncpu);
init_proclist_alloc();
@@ -3759,6 +3761,8 @@ dequeue_process(ErtsRunQueue *runq, int prio_q, erts_aint32_t *statep)
ERTS_THR_DATA_DEPENDENCY_READ_MEMORY_BARRIER;
state = erts_atomic32_read_nob(&p->state);
+ ASSERT(state & ERTS_PSFLG_IN_RUNQ);
+
if (statep)
*statep = state;
@@ -3766,8 +3770,7 @@ dequeue_process(ErtsRunQueue *runq, int prio_q, erts_aint32_t *statep)
rqi = &runq->procs.prio_info[prio];
- if (p)
- unqueue_process(runq, rpq, rqi, prio, NULL, p);
+ unqueue_process(runq, rpq, rqi, prio, NULL, p);
return p;
}
@@ -4086,7 +4089,7 @@ evacuate_run_queue(ErtsRunQueue *rq,
erts_runq_unlock(to_rq);
smp_notify_inc_runq(to_rq);
- erts_runq_lock(to_rq);
+ erts_runq_lock(rq);
}
if (rq->ports.start) {
@@ -4155,22 +4158,17 @@ evacuate_run_queue(ErtsRunQueue *rq,
free_proxy_proc(proc);
else {
erts_aint32_t clr_bits;
-#ifdef DEBUG
- erts_aint32_t old;
-#endif
clr_bits = ERTS_PSFLG_IN_RUNQ;
clr_bits |= qbit << ERTS_PSFLGS_IN_PRQ_MASK_OFFSET;
-#ifdef DEBUG
- old =
-#else
- (void)
-#endif
- erts_atomic32_read_band_mb(&proc->state,
- ~clr_bits);
- ASSERT((old & clr_bits) == clr_bits);
+ state = erts_atomic32_read_band_mb(&proc->state, ~clr_bits);
+ ASSERT((state & clr_bits) == clr_bits);
+ if (state & ERTS_PSFLG_FREE) {
+ /* free and not queued by proxy */
+ erts_proc_dec_refc(proc);
+ }
}
goto handle_next_proc;
@@ -6206,13 +6204,14 @@ fin_dirty_enq_s_change(Process *p,
/* Already enqueue by someone else... */
if (pstruct_reserved) {
/* We reserved process struct for enqueue; clear it... */
-#ifdef DEBUG
- erts_aint32_t old =
-#else
- (void)
-#endif
- erts_atomic32_read_band_nob(&p->state, ~ERTS_PSFLG_IN_RUNQ);
- ASSERT(old & ERTS_PSFLG_IN_RUNQ);
+ erts_aint32_t state;
+
+ state = erts_atomic32_read_band_nob(&p->state, ~ERTS_PSFLG_IN_RUNQ);
+ ASSERT(state & ERTS_PSFLG_IN_RUNQ);
+
+ if (state & ERTS_PSFLG_FREE) {
+ erts_proc_dec_refc(p);
+ }
}
return 0;
}
@@ -6405,8 +6404,9 @@ schedule_out_process(ErtsRunQueue *c_rq, erts_aint32_t state, Process *p,
== ERTS_PSFLG_ACTIVE));
n &= ~running_flgs;
- if ((a & (ERTS_PSFLG_ACTIVE_SYS|ERTS_PSFLG_DIRTY_ACTIVE_SYS))
- || (a & (ERTS_PSFLG_ACTIVE|ERTS_PSFLG_SUSPENDED)) == ERTS_PSFLG_ACTIVE) {
+ if ((!!(a & (ERTS_PSFLG_ACTIVE_SYS|ERTS_PSFLG_DIRTY_ACTIVE_SYS))
+ | ((a & (ERTS_PSFLG_ACTIVE|ERTS_PSFLG_SUSPENDED)) == ERTS_PSFLG_ACTIVE))
+ & !(a & ERTS_PSFLG_FREE)) {
enqueue = check_enqueue_in_prio_queue(p, &enq_prio, &n, a);
}
a = erts_atomic32_cmpxchg_mb(&p->state, n, e);
@@ -6612,13 +6612,13 @@ change_proc_schedule_state(Process *p,
if (((n & (ERTS_PSFLG_SUSPENDED
| ERTS_PSFLG_ACTIVE)) == ERTS_PSFLG_ACTIVE)
- && (!(a & (ERTS_PSFLG_ACTIVE_SYS
- | ERTS_PSFLG_RUNNING
- | ERTS_PSFLG_RUNNING_SYS
- | ERTS_PSFLG_DIRTY_RUNNING
- | ERTS_PSFLG_DIRTY_RUNNING_SYS)
- && (!(a & ERTS_PSFLG_ACTIVE)
- || (a & ERTS_PSFLG_SUSPENDED))))) {
+ & ((a & (ERTS_PSFLG_SUSPENDED
+ | ERTS_PSFLG_ACTIVE)) != ERTS_PSFLG_ACTIVE)
+ & !(a & (ERTS_PSFLG_ACTIVE_SYS
+ | ERTS_PSFLG_RUNNING
+ | ERTS_PSFLG_RUNNING_SYS
+ | ERTS_PSFLG_DIRTY_RUNNING
+ | ERTS_PSFLG_DIRTY_RUNNING_SYS))) {
/* We activated a prevously inactive process */
profile_runnable_proc(p, am_active);
}
@@ -6653,62 +6653,72 @@ erts_schedule_process(Process *p, erts_aint32_t state, ErtsProcLocks locks)
schedule_process(p, state, locks);
}
+/* Enqueues the given sys task on the process and schedules it. The task may be
+ * NULL if only scheduling is desired. */
static ERTS_INLINE erts_aint32_t
-active_sys_enqueue(Process *p, erts_aint32_t state,
- erts_aint32_t enable_flags, int status_locked)
-{
- /*
- * This function may or may not be called with status locke held.
- * It always returns without the status lock held!
- */
- unsigned int prof_runnable_procs = erts_system_profile_flags.runnable_procs;
- erts_aint32_t n, a = state, enq_prio = -1;
- int slocked = status_locked;
+active_sys_enqueue(Process *p, ErtsProcSysTask *sys_task,
+ erts_aint32_t task_prio, erts_aint32_t enable_flags,
+ erts_aint32_t state, erts_aint32_t *fail_state_p)
+{
+ int runnable_procs = erts_system_profile_flags.runnable_procs;
+ erts_aint32_t n, a, enq_prio, fail_state;
+ int already_scheduled;
+ int status_locked;
int enqueue; /* < 0 -> use proxy */
- /* Status lock prevents out of order "runnable proc" trace msgs */
- ERTS_LC_ASSERT(slocked || !(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p)));
- ERTS_LC_ASSERT(!slocked || (ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p)));
-
- if (!prof_runnable_procs) {
- if (slocked) {
- erts_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
- slocked = 0;
- }
- }
- else {
- if (!slocked) {
- erts_proc_lock(p, ERTS_PROC_LOCK_STATUS);
- slocked = !0;
- }
- }
+ enable_flags |= ERTS_PSFLG_ACTIVE_SYS;
+ fail_state = *fail_state_p;
+ already_scheduled = 0;
+ status_locked = 0;
+ enq_prio = -1;
+ a = state;
+ ERTS_LC_ASSERT(!(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p)));
+ ASSERT(fail_state & (ERTS_PSFLG_EXITING | ERTS_PSFLG_FREE));
+ ASSERT(!(fail_state & enable_flags));
ASSERT(!(state & ERTS_PSFLG_PROXY));
+ /* When runnable_procs is enabled, we need to take the status lock to
+ * prevent trace messages from being sent in the wrong order. The lock must
+ * be held over the call to add2runq.
+ *
+ * Otherwise, we only need to take it when we're enqueuing a task and can
+ * safely release it before add2runq. */
+ if (sys_task || runnable_procs) {
+ erts_proc_lock(p, ERTS_PROC_LOCK_STATUS);
+ status_locked = 1;
+ }
+
while (1) {
erts_aint32_t e;
n = e = a;
- if (a & ERTS_PSFLG_FREE)
- goto cleanup; /* We don't want to schedule free processes... */
+ if (a & fail_state) {
+ *fail_state_p = a & fail_state;
+ goto cleanup;
+ }
enqueue = ERTS_ENQUEUE_NOT;
- n |= enable_flags;
- n |= ERTS_PSFLG_ACTIVE_SYS;
+ n |= enable_flags;
+
if (!(a & (ERTS_PSFLG_RUNNING
| ERTS_PSFLG_RUNNING_SYS
| ERTS_PSFLG_DIRTY_RUNNING
- | ERTS_PSFLG_DIRTY_RUNNING_SYS)))
+ | ERTS_PSFLG_DIRTY_RUNNING_SYS))) {
enqueue = check_enqueue_in_prio_queue(p, &enq_prio, &n, a);
+ }
+
a = erts_atomic32_cmpxchg_mb(&p->state, n, e);
- if (a == e)
+ if (a == e) {
break;
- if (a == n && enqueue == ERTS_ENQUEUE_NOT)
- goto cleanup;
+ }
+ else if (a == n && enqueue == ERTS_ENQUEUE_NOT) {
+ already_scheduled = 1;
+ break;
+ }
}
- if (prof_runnable_procs) {
-
+ if (!already_scheduled && runnable_procs) {
if (!(a & (ERTS_PSFLG_ACTIVE_SYS
| ERTS_PSFLG_RUNNING
| ERTS_PSFLG_RUNNING_SYS
@@ -6718,19 +6728,56 @@ active_sys_enqueue(Process *p, erts_aint32_t state,
/* We activated a prevously inactive process */
profile_runnable_proc(p, am_active);
}
-
- erts_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
- slocked = 0;
}
- add2runq(enqueue, enq_prio, p, n, NULL);
+ if (sys_task) {
+ ErtsProcSysTaskQs *stqs = p->sys_task_qs;
-cleanup:
+ if (!stqs) {
+ sys_task->next = sys_task->prev = sys_task;
- if (slocked)
- erts_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
+ stqs = proc_sys_task_queues_alloc();
- ERTS_LC_ASSERT(!(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p)));
+ stqs->qmask = 1 << task_prio;
+ stqs->ncount = 0;
+ stqs->q[PRIORITY_MAX] = NULL;
+ stqs->q[PRIORITY_HIGH] = NULL;
+ stqs->q[PRIORITY_NORMAL] = NULL;
+ stqs->q[PRIORITY_LOW] = NULL;
+ stqs->q[task_prio] = sys_task;
+
+ p->sys_task_qs = stqs;
+ }
+ else {
+ if (!stqs->q[task_prio]) {
+ sys_task->next = sys_task->prev = sys_task;
+
+ stqs->q[task_prio] = sys_task;
+ stqs->qmask |= 1 << task_prio;
+ }
+ else {
+ sys_task->next = stqs->q[task_prio];
+ sys_task->prev = stqs->q[task_prio]->prev;
+ sys_task->next->prev = sys_task;
+ sys_task->prev->next = sys_task;
+ ASSERT(stqs->qmask & (1 << task_prio));
+ }
+ }
+ }
+
+ if (status_locked && !runnable_procs) {
+ erts_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
+ status_locked = 0;
+ }
+
+ if (!already_scheduled) {
+ add2runq(enqueue, enq_prio, p, n, NULL);
+ }
+
+cleanup:
+ if (status_locked) {
+ erts_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
+ }
return n;
}
@@ -6738,103 +6785,41 @@ cleanup:
erts_aint32_t
erts_proc_sys_schedule(Process *p, erts_aint32_t state, erts_aint32_t enable_flag)
{
- /* We are not allowed to call this function with status lock held... */
- return active_sys_enqueue(p, state, enable_flag, 0);
+ erts_aint32_t fail_state = ERTS_PSFLG_FREE;
+
+ return active_sys_enqueue(p, NULL, 0, enable_flag, state, &fail_state);
}
static int
schedule_process_sys_task(Process *p, erts_aint32_t prio, ErtsProcSysTask *st,
erts_aint32_t *fail_state_p)
{
- int res;
- int locked;
- ErtsProcSysTaskQs *stqs, *free_stqs;
erts_aint32_t fail_state, state;
- fail_state = *fail_state_p;
-
- res = 1; /* prepare for success */
- st->next = st->prev = st; /* Prep for empty prio queue */
+ /* Elevate priority if needed. */
state = erts_atomic32_read_nob(&p->state);
- locked = 0;
- free_stqs = NULL;
- if (state & ERTS_PSFLG_SYS_TASKS)
- stqs = NULL;
- else {
- alloc_qs:
- stqs = proc_sys_task_queues_alloc();
- stqs->qmask = 1 << prio;
- stqs->ncount = 0;
- stqs->q[PRIORITY_MAX] = NULL;
- stqs->q[PRIORITY_HIGH] = NULL;
- stqs->q[PRIORITY_NORMAL] = NULL;
- stqs->q[PRIORITY_LOW] = NULL;
- stqs->q[prio] = st;
- }
-
- if (!locked) {
- locked = 1;
- erts_proc_lock(p, ERTS_PROC_LOCK_STATUS);
-
- state = erts_atomic32_read_nob(&p->state);
- if (state & fail_state) {
- erts_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
- *fail_state_p = (state & fail_state);
- free_stqs = stqs;
- res = 0;
- goto cleanup;
- }
- }
-
- if (!p->sys_task_qs) {
- if (stqs)
- p->sys_task_qs = stqs;
- else
- goto alloc_qs;
- }
- else {
- free_stqs = stqs;
- stqs = p->sys_task_qs;
- if (!stqs->q[prio]) {
- stqs->q[prio] = st;
- stqs->qmask |= 1 << prio;
- }
- else {
- st->next = stqs->q[prio];
- st->prev = stqs->q[prio]->prev;
- st->next->prev = st;
- st->prev->next = st;
- ASSERT(stqs->qmask & (1 << prio));
- }
- }
-
if (ERTS_PSFLGS_GET_ACT_PRIO(state) > prio) {
- erts_aint32_t n, a, e;
- /* Need to elevate actual prio */
+ erts_aint32_t n, a, e;
- a = state;
- do {
- if (ERTS_PSFLGS_GET_ACT_PRIO(a) <= prio) {
- n = a;
- break;
- }
- n = e = a;
- n &= ~ERTS_PSFLGS_ACT_PRIO_MASK;
- n |= (prio << ERTS_PSFLGS_ACT_PRIO_OFFSET);
- a = erts_atomic32_cmpxchg_nob(&p->state, n, e);
- } while (a != e);
- state = n;
- }
-
- /* active_sys_enqueue() always return with status lock unlocked */
- (void) active_sys_enqueue(p, state, ERTS_PSFLG_SYS_TASKS, locked);
+ a = state;
+ do {
+ if (ERTS_PSFLGS_GET_ACT_PRIO(a) <= prio) {
+ n = a;
+ break;
+ }
+ n = e = a;
+ n &= ~ERTS_PSFLGS_ACT_PRIO_MASK;
+ n |= (prio << ERTS_PSFLGS_ACT_PRIO_OFFSET);
+ a = erts_atomic32_cmpxchg_nob(&p->state, n, e);
+ } while (a != e);
-cleanup:
+ state = n;
+ }
- if (free_stqs)
- proc_sys_task_queues_free(free_stqs);
+ fail_state = *fail_state_p;
- return res;
+ return !(active_sys_enqueue(p, st, prio, ERTS_PSFLG_SYS_TASKS,
+ state, fail_state_p) & fail_state);
}
static ERTS_INLINE int
@@ -8553,427 +8538,22 @@ erts_start_schedulers(void)
}
}
-
-
-static void
-add_pend_suspend(Process *suspendee,
- Eterm originator_pid,
- void (*handle_func)(Process *,
- ErtsProcLocks,
- int,
- Eterm))
-{
- ErtsPendingSuspend *psp = erts_alloc(ERTS_ALC_T_PEND_SUSPEND,
- sizeof(ErtsPendingSuspend));
- psp->next = NULL;
-#ifdef DEBUG
-#if defined(ARCH_64)
- psp->end = (ErtsPendingSuspend *) 0xdeaddeaddeaddead;
-#else
- psp->end = (ErtsPendingSuspend *) 0xdeaddead;
-#endif
-#endif
- psp->pid = originator_pid;
- psp->handle_func = handle_func;
-
- if (suspendee->pending_suspenders)
- suspendee->pending_suspenders->end->next = psp;
- else
- suspendee->pending_suspenders = psp;
- suspendee->pending_suspenders->end = psp;
-}
-
-static void
-handle_pending_suspend(Process *p, ErtsProcLocks p_locks)
-{
- ErtsPendingSuspend *psp;
- int is_alive = !ERTS_PROC_IS_EXITING(p);
-
- ERTS_LC_ASSERT(p_locks & ERTS_PROC_LOCK_STATUS);
-
- /*
- * New pending suspenders might appear while we are processing
- * (since we may release the status lock on p while processing).
- */
- while (p->pending_suspenders) {
- psp = p->pending_suspenders;
- p->pending_suspenders = NULL;
- while (psp) {
- ErtsPendingSuspend *free_psp;
- (*psp->handle_func)(p, p_locks, is_alive, psp->pid);
- free_psp = psp;
- psp = psp->next;
- erts_free(ERTS_ALC_T_PEND_SUSPEND, (void *) free_psp);
- }
- }
-
-}
-
-static ERTS_INLINE void
-cancel_suspend_of_suspendee(Process *p, ErtsProcLocks p_locks)
-{
- if (is_not_nil(p->suspendee)) {
- ErtsMonitor *mon;
- Eterm suspendee = p->suspendee;
- Process *rp;
- if (!(p_locks & ERTS_PROC_LOCK_STATUS))
- erts_proc_lock(p, ERTS_PROC_LOCK_STATUS);
- rp = erts_pid2proc(p, p_locks|ERTS_PROC_LOCK_STATUS,
- suspendee, ERTS_PROC_LOCK_STATUS);
- if (rp) {
- erts_resume(rp, ERTS_PROC_LOCK_STATUS);
- erts_proc_unlock(rp, ERTS_PROC_LOCK_STATUS);
- }
- if (!(p_locks & ERTS_PROC_LOCK_STATUS))
- erts_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
- p->suspendee = NIL;
-
- mon = erts_monitor_tree_lookup(p->suspend_monitors,
- suspendee);
- if (mon) {
- erts_monitor_tree_delete(&p->suspend_monitors,
- mon);
- erts_monitor_suspend_destroy(erts_monitor_suspend(mon));
- }
- }
-}
-
-static void
-handle_pend_sync_suspend(Process *suspendee,
- ErtsProcLocks suspendee_locks,
- int suspendee_alive,
- Eterm suspender_pid)
-{
- Process *suspender;
-
- ERTS_LC_ASSERT(suspendee_locks & ERTS_PROC_LOCK_STATUS);
-
- suspender = erts_pid2proc(suspendee,
- suspendee_locks,
- suspender_pid,
- ERTS_PROC_LOCK_STATUS);
- if (suspender) {
- ASSERT(is_nil(suspender->suspendee));
- if (suspendee_alive) {
- erts_suspend(suspendee, suspendee_locks, NULL);
- suspender->suspendee = suspendee->common.id;
- }
- /* suspender is suspended waiting for suspendee to suspend;
- resume suspender */
- ASSERT(suspendee != suspender);
- resume_process(suspender, ERTS_PROC_LOCK_STATUS);
- erts_proc_unlock(suspender, ERTS_PROC_LOCK_STATUS);
- }
-}
-
-static Process *
-pid2proc_not_running(Process *c_p, ErtsProcLocks c_p_locks,
- Eterm pid, ErtsProcLocks pid_locks, int suspend)
-{
- Process *rp;
- int unlock_c_p_status;
-
- ERTS_LC_ASSERT(c_p_locks == erts_proc_lc_my_proc_locks(c_p));
-
- ERTS_LC_ASSERT(c_p_locks & ERTS_PROC_LOCK_MAIN);
- ERTS_LC_ASSERT(pid_locks & (ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS));
-
- if (c_p->common.id == pid)
- return erts_pid2proc(c_p, c_p_locks, pid, pid_locks);
-
- if (c_p_locks & ERTS_PROC_LOCK_STATUS)
- unlock_c_p_status = 0;
- else {
- unlock_c_p_status = 1;
- erts_proc_lock(c_p, ERTS_PROC_LOCK_STATUS);
- }
-
- if (c_p->suspendee == pid) {
- /* Process previously suspended by c_p (below)... */
- ErtsProcLocks rp_locks = pid_locks|ERTS_PROC_LOCK_STATUS;
- rp = erts_pid2proc(c_p, c_p_locks|ERTS_PROC_LOCK_STATUS, pid, rp_locks);
- c_p->suspendee = NIL;
- ASSERT(c_p->flags & F_P2PNR_RESCHED);
- c_p->flags &= ~F_P2PNR_RESCHED;
- if (!suspend && rp)
- resume_process(rp, rp_locks);
- }
- else {
- rp = erts_pid2proc(c_p, c_p_locks|ERTS_PROC_LOCK_STATUS,
- pid, ERTS_PROC_LOCK_STATUS);
-
- if (!rp) {
- c_p->flags &= ~F_P2PNR_RESCHED;
- goto done;
- }
-
- ASSERT(!(c_p->flags & F_P2PNR_RESCHED));
-
- /*
- * Suspend the other process in order to prevent
- * it from being selected for normal execution.
- * This will however not prevent it from being
- * selected for execution of a system task. If
- * it is selected for execution of a system task
- * we might be blocked for quite a while if the
- * try-lock below fails. That is, there is room
- * for improvement here...
- */
-
- if (!suspend_process(c_p, rp)) {
- /* Other process running */
-
- ASSERT((ERTS_PSFLG_RUNNING | ERTS_PSFLG_DIRTY_RUNNING)
- & erts_atomic32_read_nob(&rp->state));
-
- if (!suspend
- && (erts_atomic32_read_nob(&rp->state)
- & ERTS_PSFLG_DIRTY_RUNNING)) {
- ErtsProcLocks need_locks = pid_locks & ~ERTS_PROC_LOCK_STATUS;
- if (need_locks && erts_proc_trylock(rp, need_locks) == EBUSY) {
- erts_proc_unlock(rp, ERTS_PROC_LOCK_STATUS);
- rp = erts_pid2proc(c_p, c_p_locks|ERTS_PROC_LOCK_STATUS,
- pid, pid_locks|ERTS_PROC_LOCK_STATUS);
- }
- goto done;
- }
-
- running:
-
- /*
- * If we got pending suspenders and suspend ourselves waiting
- * to suspend another process we might deadlock.
- * In this case we have to yield, be suspended by
- * someone else and then do it all over again.
- */
- if (!c_p->pending_suspenders) {
- /* Mark rp pending for suspend by c_p */
- add_pend_suspend(rp, c_p->common.id, handle_pend_sync_suspend);
- ASSERT(is_nil(c_p->suspendee));
-
- /* Suspend c_p; when rp is suspended c_p will be resumed. */
- suspend_process(c_p, c_p);
- c_p->flags |= F_P2PNR_RESCHED;
- }
- /* Yield (caller is assumed to yield immediately in bif). */
- erts_proc_unlock(rp, ERTS_PROC_LOCK_STATUS);
- rp = ERTS_PROC_LOCK_BUSY;
- }
- else {
- ErtsProcLocks need_locks = pid_locks & ~ERTS_PROC_LOCK_STATUS;
- if (need_locks && erts_proc_trylock(rp, need_locks) == EBUSY) {
- if ((ERTS_PSFLG_RUNNING_SYS|ERTS_PSFLG_DIRTY_RUNNING_SYS)
- & erts_atomic32_read_nob(&rp->state)) {
- /* Executing system task... */
- resume_process(rp, ERTS_PROC_LOCK_STATUS);
- goto running;
- }
- erts_proc_unlock(rp, ERTS_PROC_LOCK_STATUS);
- /*
- * If we are unlucky, the process just got selected for
- * execution of a system task. In this case we may be
- * blocked here for quite a while... Execution of system
- * tasks are fortunately quite rare events. We try to
- * avoid this by checking if it is in a state executing
- * system tasks (above), but it will not prevent all
- * scenarios for a long block here...
- */
- rp = erts_pid2proc(c_p, c_p_locks|ERTS_PROC_LOCK_STATUS,
- pid, pid_locks|ERTS_PROC_LOCK_STATUS);
- if (!rp)
- goto done;
- }
-
- /*
- * The previous suspend has prevented the process
- * from being selected for normal execution regardless
- * of locks held or not held on it...
- */
-#ifdef DEBUG
- {
- erts_aint32_t state;
- state = erts_atomic32_read_nob(&rp->state);
- ASSERT(!(state & ERTS_PSFLG_RUNNING));
- }
-#endif
-
- if (!suspend)
- resume_process(rp, pid_locks|ERTS_PROC_LOCK_STATUS);
- }
- }
-
- done:
-
- if (rp && rp != ERTS_PROC_LOCK_BUSY && !(pid_locks & ERTS_PROC_LOCK_STATUS))
- erts_proc_unlock(rp, ERTS_PROC_LOCK_STATUS);
- if (unlock_c_p_status)
- erts_proc_unlock(c_p, ERTS_PROC_LOCK_STATUS);
- return rp;
-}
-
-
-/*
- * Like erts_pid2proc() but:
- *
- * * At least ERTS_PROC_LOCK_MAIN have to be held on c_p.
- * * At least ERTS_PROC_LOCK_MAIN have to be taken on pid.
- * * It also waits for proc to be in a state != running and garbing.
- * * If ERTS_PROC_LOCK_BUSY is returned, the calling process has to
- * yield (ERTS_BIF_YIELD[0-3]()). c_p might in this case have been
- * suspended.
- */
-Process *
-erts_pid2proc_not_running(Process *c_p, ErtsProcLocks c_p_locks,
- Eterm pid, ErtsProcLocks pid_locks)
-{
- return pid2proc_not_running(c_p, c_p_locks, pid, pid_locks, 0);
-}
-
-/*
- * erts_pid2proc_nropt() is normally the same as
- * erts_pid2proc_not_running(). However it is only
- * to be used when 'not running' is a pure optimization,
- * not a requirement.
- */
-
-Process *
-erts_pid2proc_nropt(Process *c_p, ErtsProcLocks c_p_locks,
- Eterm pid, ErtsProcLocks pid_locks)
-{
- if (erts_disable_proc_not_running_opt)
- return erts_pid2proc(c_p, c_p_locks, pid, pid_locks);
- else
- return erts_pid2proc_not_running(c_p, c_p_locks, pid, pid_locks);
-}
-
-static ERTS_INLINE int
-do_bif_suspend_process(Process *c_p,
- ErtsMonitorSuspend *smon,
- Process *suspendee)
-{
- ASSERT(suspendee);
- ASSERT(!ERTS_PROC_IS_EXITING(suspendee));
- ERTS_LC_ASSERT(ERTS_PROC_LOCK_STATUS
- & erts_proc_lc_my_proc_locks(suspendee));
- if (smon) {
- if (!smon->active) {
- if (!suspend_process(c_p, suspendee))
- return 0;
- }
- smon->active += smon->pending;
- ASSERT(smon->active);
- smon->pending = 0;
- return 1;
- }
- return 0;
-}
-
-static void
-handle_pend_bif_sync_suspend(Process *suspendee,
- ErtsProcLocks suspendee_locks,
- int suspendee_alive,
- Eterm suspender_pid)
-{
- Process *suspender;
-
- ERTS_LC_ASSERT(suspendee_locks & ERTS_PROC_LOCK_STATUS);
-
- suspender = erts_pid2proc(suspendee,
- suspendee_locks,
- suspender_pid,
- ERTS_PROC_LOCK_STATUS);
- if (suspender) {
- ErtsMonitorSuspend *smon;
- ErtsMonitor *mon;
- mon = erts_monitor_tree_lookup(suspender->suspend_monitors,
- suspendee->common.id);
- smon = erts_monitor_suspend(mon);
-
- ASSERT(is_nil(suspender->suspendee));
- if (!suspendee_alive) {
- if (mon) {
- erts_monitor_tree_delete(&suspender->suspend_monitors,
- mon);
- erts_monitor_suspend_destroy(smon);
- }
- }
- else {
-#ifdef DEBUG
- int res =
-#endif
- do_bif_suspend_process(suspendee, smon, suspendee);
- ASSERT(!smon || res != 0);
- suspender->suspendee = suspendee->common.id;
- }
- /* suspender is suspended waiting for suspendee to suspend;
- resume suspender */
- ASSERT(suspender != suspendee);
- resume_process(suspender, ERTS_PROC_LOCK_STATUS);
- erts_proc_unlock(suspender, ERTS_PROC_LOCK_STATUS);
- }
-}
-
-static void
-handle_pend_bif_async_suspend(Process *suspendee,
- ErtsProcLocks suspendee_locks,
- int suspendee_alive,
- Eterm suspender_pid)
-{
-
- Process *suspender;
-
- ERTS_LC_ASSERT(suspendee_locks & ERTS_PROC_LOCK_STATUS);
-
- suspender = erts_pid2proc(suspendee,
- suspendee_locks,
- suspender_pid,
- ERTS_PROC_LOCK_STATUS);
- if (suspender) {
- ErtsMonitorSuspend *smon;
- ErtsMonitor *mon;
- mon = erts_monitor_tree_lookup(suspender->suspend_monitors,
- suspendee->common.id);
- smon = erts_monitor_suspend(mon);
- ASSERT(is_nil(suspender->suspendee));
- if (!suspendee_alive) {
- if (mon) {
- erts_monitor_tree_delete(&suspender->suspend_monitors,
- mon);
- erts_monitor_suspend_destroy(smon);
- }
- }
- else {
-#ifdef DEBUG
- int res =
-#endif
- do_bif_suspend_process(suspendee, smon, suspendee);
- ASSERT(!smon || res != 0);
- }
- erts_proc_unlock(suspender, ERTS_PROC_LOCK_STATUS);
- }
-}
-
-
-/*
- * The erlang:suspend_process/2 BIF
- */
-
BIF_RETTYPE
-suspend_process_2(BIF_ALIST_2)
+erts_internal_suspend_process_2(BIF_ALIST_2)
{
Eterm res;
- Process* suspendee = NULL;
- ErtsMonitorSuspend *smon;
- ErtsProcLocks xlocks = (ErtsProcLocks) 0;
- int created;
-
- /* Options and default values: */
- int asynchronous = 0;
+ Eterm reply_tag = THE_NON_VALUE;
+ Eterm reply_res = THE_NON_VALUE;
+ int suspend;
+ int sync = 0;
+ int async = 0;
int unless_suspending = 0;
-
+ erts_aint_t mstate;
+ ErtsMonitorSuspend *msp;
+ ErtsMonitorData *mdp;
if (BIF_P->common.id == BIF_ARG_1)
- goto badarg; /* We are not allowed to suspend ourselves */
+ BIF_RET(am_badarg); /* We are not allowed to suspend ourselves */
if (is_not_nil(BIF_ARG_2)) {
/* Parse option list */
@@ -8987,191 +8567,127 @@ suspend_process_2(BIF_ALIST_2)
unless_suspending = 1;
break;
case am_asynchronous:
- asynchronous = 1;
+ async = 1;
break;
- default:
- goto badarg;
+ default: {
+ if (is_tuple_arity(arg, 2)) {
+ Eterm *tp = tuple_val(arg);
+ if (tp[1] == am_asynchronous) {
+ async = 1;
+ reply_tag = tp[2];
+ break;
+ }
+ }
+ BIF_RET(am_badarg);
}
+ }
arg = CDR(lp);
- }
+ }
if (is_not_nil(arg))
- goto badarg;
- }
-
- xlocks = ERTS_PROC_LOCK_STATUS;
-
- erts_proc_lock(BIF_P, xlocks);
-
- suspendee = erts_pid2proc(BIF_P,
- ERTS_PROC_LOCK_MAIN|xlocks,
- BIF_ARG_1,
- ERTS_PROC_LOCK_STATUS);
- if (!suspendee)
- goto no_suspendee;
-
- smon = erts_monitor_suspend_tree_lookup_create(&BIF_P->suspend_monitors,
- &created,
- BIF_ARG_1);
-
- if (asynchronous) {
- /* --- Asynchronous suspend begin ---------------------------------- */
-
- ERTS_LC_ASSERT(ERTS_PROC_LOCK_STATUS
- & erts_proc_lc_my_proc_locks(BIF_P));
- ERTS_LC_ASSERT(ERTS_PROC_LOCK_STATUS
- == erts_proc_lc_my_proc_locks(suspendee));
-
- if (smon->active) {
- smon->active += smon->pending;
- smon->pending = 0;
- if (unless_suspending)
- res = am_false;
- else if (smon->active == INT_MAX)
- goto system_limit;
- else {
- smon->active++;
- res = am_true;
- }
- /* done */
- }
- else {
- /* We havn't got any active suspends on the suspendee */
- if (smon->pending && unless_suspending)
- res = am_false;
- else {
- if (smon->pending == INT_MAX)
- goto system_limit;
-
- smon->pending++;
-
- if (!do_bif_suspend_process(BIF_P, smon, suspendee))
- add_pend_suspend(suspendee,
- BIF_P->common.id,
- handle_pend_bif_async_suspend);
-
- res = am_true;
- }
- /* done */
- }
- /* --- Asynchronous suspend end ------------------------------------ */
- }
- else /* if (!asynchronous) */ {
- /* --- Synchronous suspend begin ----------------------------------- */
-
- ERTS_LC_ASSERT(((ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_STATUS)
- & erts_proc_lc_my_proc_locks(BIF_P))
- == (ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_STATUS));
- ERTS_LC_ASSERT(ERTS_PROC_LOCK_STATUS
- == erts_proc_lc_my_proc_locks(suspendee));
-
- if (BIF_P->suspendee == BIF_ARG_1) {
- /* We are back after a yield and the suspendee
- has been suspended on behalf of us. */
- ASSERT(smon->active >= 1);
- BIF_P->suspendee = NIL;
- res = (!unless_suspending || smon->active == 1
- ? am_true
- : am_false);
- /* done */
- }
- else if (smon->active) {
- if (unless_suspending)
- res = am_false;
- else {
- smon->active++;
- res = am_true;
- }
- /* done */
- }
- else {
- /* We haven't got any active suspends on the suspendee */
-
- /*
- * If we have pending suspenders and suspend ourselves waiting
- * to suspend another process, or suspend another process
- * we might deadlock. In this case we have to yield,
- * be suspended by someone else, and then do it all over again.
- */
- if (BIF_P->pending_suspenders)
- goto yield;
-
- if (!unless_suspending && smon->pending == INT_MAX)
- goto system_limit;
- if (!unless_suspending || smon->pending == 0)
- smon->pending++;
-
- if (do_bif_suspend_process(BIF_P, smon, suspendee)) {
- res = (!unless_suspending || smon->active == 1
- ? am_true
- : am_false);
- /* done */
- }
- else {
- /* Mark suspendee pending for suspend by BIF_P */
- add_pend_suspend(suspendee,
- BIF_P->common.id,
- handle_pend_bif_sync_suspend);
-
- ASSERT(is_nil(BIF_P->suspendee));
-
- /*
- * Suspend BIF_P; when suspendee is suspended, BIF_P
- * will be resumed and this BIF will be called again.
- * This time with BIF_P->suspendee == BIF_ARG_1 (see
- * above).
- */
- suspend_process(BIF_P, BIF_P);
- goto yield;
- }
- }
- /* --- Synchronous suspend end ------------------------------------- */
+ BIF_RET(am_badarg);
}
-#ifdef DEBUG
- {
- erts_aint32_t state = erts_atomic32_read_acqb(&suspendee->state);
- ASSERT((state & ERTS_PSFLG_SUSPENDED)
- || (asynchronous && smon->pending));
- ASSERT((state & ERTS_PSFLG_SUSPENDED)
- || !smon->active);
+ if (!unless_suspending) {
+ ErtsMonitor *mon;
+ mon = erts_monitor_tree_lookup_create(&ERTS_P_MONITORS(BIF_P),
+ &suspend,
+ ERTS_MON_TYPE_SUSPEND,
+ BIF_P->common.id,
+ BIF_ARG_1);
+ ASSERT(mon->other.item == BIF_ARG_1);
+
+ mdp = erts_monitor_to_data(mon);
+ msp = (ErtsMonitorSuspend *) mdp;
+
+ mstate = erts_atomic_inc_read_relb(&msp->state);
+ ASSERT(suspend || (mstate & ERTS_MSUSPEND_STATE_COUNTER_MASK) > 1);
+ sync = !async & !suspend & !(mstate & ERTS_MSUSPEND_STATE_FLG_ACTIVE);
+ suspend = !!suspend; /* ensure 0|1 */
+ res = am_true;
}
-#endif
-
- erts_proc_unlock(suspendee, ERTS_PROC_LOCK_STATUS);
- erts_proc_unlock(BIF_P, xlocks);
- BIF_RET(res);
-
- system_limit:
- ERTS_BIF_PREP_ERROR(res, BIF_P, SYSTEM_LIMIT);
- goto do_return;
-
- no_suspendee: {
+ else {
ErtsMonitor *mon;
- BIF_P->suspendee = NIL;
- mon = erts_monitor_tree_lookup(BIF_P->suspend_monitors, BIF_ARG_1);
+ mon = erts_monitor_tree_lookup(ERTS_P_MONITORS(BIF_P),
+ BIF_ARG_1);
if (mon) {
- erts_monitor_tree_delete(&BIF_P->suspend_monitors, mon);
- erts_monitor_suspend_destroy(erts_monitor_suspend(mon));
+ ASSERT(mon->type == ERTS_MON_TYPE_SUSPEND);
+ mdp = erts_monitor_to_data(mon);
+ msp = (ErtsMonitorSuspend *) mdp;
+ mstate = erts_atomic_read_nob(&msp->state);
+ ASSERT((mstate & ERTS_MSUSPEND_STATE_COUNTER_MASK) > 0);
+ mdp = NULL;
+ sync = !async & !(mstate & ERTS_MSUSPEND_STATE_FLG_ACTIVE);
+ suspend = 0;
+ res = am_false;
+ }
+ else {
+ mdp = erts_monitor_create(ERTS_MON_TYPE_SUSPEND, NIL,
+ BIF_P->common.id,
+ BIF_ARG_1, NIL);
+ mon = &mdp->origin;
+ erts_monitor_tree_insert(&ERTS_P_MONITORS(BIF_P), mon);
+ msp = (ErtsMonitorSuspend *) mdp;
+ mstate = erts_atomic_inc_read_relb(&msp->state);
+ ASSERT(!(mstate & ERTS_MSUSPEND_STATE_FLG_ACTIVE));
+ suspend = !0;
+ res = am_true;
}
}
- badarg:
- ERTS_BIF_PREP_ERROR(res, BIF_P, BADARG);
- goto do_return;
+ if (suspend) {
+ erts_aint32_t state;
+ Process *rp;
+ int send_sig = 0;
+
+ /* fail state... */
+ state = (ERTS_PSFLG_EXITING
+ | ERTS_PSFLG_RUNNING
+ | ERTS_PSFLG_RUNNING_SYS
+ | ERTS_PSFLG_DIRTY_RUNNING
+ | ERTS_PSFLG_DIRTY_RUNNING_SYS);
+
+ rp = erts_try_lock_sig_free_proc(BIF_ARG_1,
+ ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS,
+ &state);
+ if (!rp)
+ goto noproc;
+ if (rp == ERTS_PROC_LOCK_BUSY)
+ send_sig = !0;
+ else {
+ send_sig = !suspend_process(BIF_P, rp);
+ if (!send_sig) {
+ erts_monitor_list_insert(&ERTS_P_LT_MONITORS(rp), &mdp->target);
+ erts_atomic_read_bor_relb(&msp->state,
+ ERTS_MSUSPEND_STATE_FLG_ACTIVE);
+ }
+ erts_proc_unlock(rp, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS);
+ }
+ if (send_sig) {
+ if (erts_proc_sig_send_monitor(&mdp->target, BIF_ARG_1))
+ sync = !async;
+ else {
+ noproc:
+ erts_monitor_tree_delete(&ERTS_P_MONITORS(BIF_P), &mdp->origin);
+ erts_monitor_release_both(mdp);
+ if (!async)
+ res = am_badarg;
+ }
+ }
+ }
- yield:
- ERTS_BIF_PREP_YIELD2(res, bif_export[BIF_suspend_process_2],
- BIF_P, BIF_ARG_1, BIF_ARG_2);
-
- do_return:
- if (suspendee)
- erts_proc_unlock(suspendee, ERTS_PROC_LOCK_STATUS);
- if (xlocks)
- erts_proc_unlock(BIF_P, xlocks);
- return res;
+ if (sync) {
+ ASSERT(is_non_value(reply_tag));
+ reply_res = res;
+ reply_tag = res = erts_make_ref(BIF_P);
+ ERTS_RECV_MARK_SAVE(BIF_P);
+ ERTS_RECV_MARK_SET(BIF_P);
+ }
-}
+ if (is_value(reply_tag))
+ erts_proc_sig_send_sync_suspend(BIF_P, BIF_ARG_1, reply_tag, reply_res);
+ BIF_RET(res);
+}
/*
* The erlang:resume_process/1 BIF
@@ -9181,90 +8697,32 @@ BIF_RETTYPE
resume_process_1(BIF_ALIST_1)
{
ErtsMonitor *mon;
- ErtsMonitorSuspend *smon;
- Process *suspendee;
- int is_active;
+ ErtsMonitorSuspend *msp;
+ erts_aint_t mstate;
if (BIF_P->common.id == BIF_ARG_1)
BIF_ERROR(BIF_P, BADARG);
- erts_proc_lock(BIF_P, ERTS_PROC_LOCK_STATUS);
- mon = erts_monitor_tree_lookup(BIF_P->suspend_monitors, BIF_ARG_1);
- smon = erts_monitor_suspend(mon);
-
- if (!smon) {
- /* No previous suspend or dead suspendee */
- goto error;
- }
- else if (smon->pending) {
- smon->pending--;
- ASSERT(smon->pending >= 0);
- if (smon->active) {
- smon->active += smon->pending;
- smon->pending = 0;
- }
- is_active = smon->active;
- }
- else if (smon->active) {
- smon->active--;
- ASSERT(smon->pending == 0);
- is_active = 1;
- }
- else {
+ mon = erts_monitor_tree_lookup(ERTS_P_MONITORS(BIF_P),
+ BIF_ARG_1);
+ if (!mon) {
/* No previous suspend or dead suspendee */
- goto no_suspendee;
- }
-
- if (smon->active || smon->pending || !is_active) {
- /* Leave the suspendee as it is; just verify that it is still alive */
- suspendee = erts_proc_lookup(BIF_ARG_1);
- if (!suspendee)
- goto no_suspendee;
-
+ BIF_ERROR(BIF_P, BADARG);
}
- else {
- /* Resume */
- suspendee = erts_pid2proc(BIF_P,
- ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS,
- BIF_ARG_1,
- ERTS_PROC_LOCK_STATUS);
- if (!suspendee) {
- mon = erts_monitor_tree_lookup(BIF_P->suspend_monitors, BIF_ARG_1);
- smon = erts_monitor_suspend(mon);
- if (!mon)
- goto error;
- goto no_suspendee;
- }
- ASSERT(mon == erts_monitor_tree_lookup(BIF_P->suspend_monitors, BIF_ARG_1));
+ ASSERT(mon->type == ERTS_MON_TYPE_SUSPEND);
+ msp = (ErtsMonitorSuspend *) erts_monitor_to_data(mon);
- ASSERT(ERTS_PSFLG_SUSPENDED
- & erts_atomic32_read_nob(&suspendee->state));
- ASSERT(BIF_P != suspendee);
- resume_process(suspendee, ERTS_PROC_LOCK_STATUS);
+ mstate = erts_atomic_dec_read_relb(&msp->state);
- erts_proc_unlock(suspendee, ERTS_PROC_LOCK_STATUS);
- }
+ ASSERT((mstate & ERTS_MSUSPEND_STATE_COUNTER_MASK) >= 0);
- if (!smon->active && !smon->pending) {
- ASSERT(mon);
- erts_monitor_tree_delete(&BIF_P->suspend_monitors, mon);
- erts_monitor_suspend_destroy(smon);
+ if ((mstate & ERTS_MSUSPEND_STATE_COUNTER_MASK) == 0) {
+ erts_monitor_tree_delete(&ERTS_P_MONITORS(BIF_P), mon);
+ erts_proc_sig_send_demonitor(mon);
}
- erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_STATUS);
-
BIF_RET(am_true);
-
- no_suspendee:
- /* cleanup */
- ASSERT(mon);
- erts_monitor_tree_delete(&BIF_P->suspend_monitors, mon);
- erts_monitor_suspend_destroy(smon);
-
- error:
- erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_STATUS);
- BIF_ERROR(BIF_P, BADARG);
}
BIF_RETTYPE
@@ -9610,6 +9068,17 @@ scheduler_gc_proc(Process *c_p, int reds_left)
return reds;
}
+static void
+unlock_lock_rq(int pre_free, void *vrq)
+{
+ ErtsRunQueue *rq = vrq;
+ if (pre_free)
+ erts_runq_unlock(rq);
+ else
+ erts_runq_lock(rq);
+}
+
+
/*
* schedule() is called from BEAM (process_main()) or HiPE
* (hipe_mode_switch()) when the current process is to be
@@ -9694,12 +9163,14 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
ASSERT(esdp->current_process == p
|| esdp->free_process == p);
- sched_out_proc:
-
- ERTS_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p);
reds = actual_reds = calls - esdp->virtual_reds;
+ internal_sched_out_proc:
+
+ ERTS_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p);
+ ASSERT(p->scheduler_data || ERTS_SCHEDULER_IS_DIRTY(esdp));
+
ASSERT(actual_reds >= 0);
if (reds < ERTS_PROC_MIN_CONTEXT_SWITCH_REDS_COST)
reds = ERTS_PROC_MIN_CONTEXT_SWITCH_REDS_COST;
@@ -9741,11 +9212,6 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
/* have to re-read state after taking lock */
state = erts_atomic32_read_nob(&p->state);
- if (p->pending_suspenders)
- handle_pending_suspend(p, (ERTS_PROC_LOCK_MAIN
- | ERTS_PROC_LOCK_TRACE
- | ERTS_PROC_LOCK_STATUS));
-
esdp->reductions += reds;
{
@@ -9782,7 +9248,9 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
}
if (dec_refc)
- erts_proc_dec_refc(p);
+ erts_proc_dec_refc_free_func(p,
+ unlock_lock_rq,
+ (void *) rq);
}
ASSERT(!esdp->free_process);
@@ -10078,6 +9546,7 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
}
else if (state & ERTS_PSFLG_FREE) {
/* free and not queued by proxy */
+ ASSERT(state & ERTS_PSFLG_IN_RUNQ);
erts_proc_dec_refc(p);
}
if (!is_normal_sched)
@@ -10134,15 +9603,15 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
state = erts_atomic32_read_nob(&p->state);
if (is_normal_sched) {
+ ASSERT(!p->scheduler_data);
+ p->scheduler_data = esdp;
if ((!!(state & ERTS_PSFLGS_DIRTY_WORK))
- & (!(state & ERTS_PSFLG_ACTIVE_SYS))) {
+ & (!(state & ERTS_PSFLG_RUNNING_SYS))) {
/* Migrate to dirty scheduler... */
sunlock_sched_out_proc:
erts_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
goto sched_out_proc;
}
- ASSERT(!p->scheduler_data);
- p->scheduler_data = esdp;
}
else {
if (!(state & ERTS_PSFLGS_DIRTY_WORK)) {
@@ -10195,8 +9664,9 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
if (is_normal_sched) {
if (state & ERTS_PSFLG_RUNNING_SYS) {
if (state & (ERTS_PSFLG_SIG_Q|ERTS_PSFLG_SIG_IN_Q)) {
- int local_only = !!(p->flags & F_LOCAL_SIGS_ONLY);
- if (!local_only || (state & ERTS_PSFLG_SIG_Q)) {
+ int local_only = (!!(p->flags & F_LOCAL_SIGS_ONLY)
+ & !(state & ERTS_PSFLG_SUSPENDED));
+ if (!local_only | !!(state & ERTS_PSFLG_SIG_Q)) {
int sig_reds;
/*
* If we have dirty work scheduled we allow
@@ -10282,7 +9752,17 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
}
p->fcalls = reds;
-
+ if (reds != context_reds) {
+ actual_reds = context_reds - reds - esdp->virtual_reds;
+ ASSERT(actual_reds >= 0);
+ esdp->virtual_reds = 0;
+ p->reds += actual_reds;
+ ERTS_PROC_REDUCTIONS_EXECUTED(esdp, rq,
+ (int) ERTS_PSFLGS_GET_USR_PRIO(state),
+ reds,
+ actual_reds);
+ }
+
ERTS_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p);
ASSERT(erts_proc_read_refc(p) > 0);
@@ -10332,6 +9812,14 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
#endif
return p;
+
+ sched_out_proc:
+ actual_reds = context_reds;
+ actual_reds -= reds;
+ actual_reds -= esdp->virtual_reds;
+ reds = actual_reds;
+ goto internal_sched_out_proc;
+
}
}
@@ -10386,6 +9874,7 @@ notify_sys_task_executed(Process *c_p, ErtsProcSysTask *st,
ASSERT(hp_start + hsz == hp);
#endif
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
erts_queue_proc_message(c_p, rp, rp_locks, mp, msg);
if (c_p == rp)
@@ -11844,7 +11333,6 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
#ifdef HIPE
hipe_init_process(&p->hipe);
- hipe_init_process_smp(&p->hipe_smp);
#endif
p->heap = (Eterm *) ERTS_HEAP_ALLOC(ERTS_ALC_T_HEAP, sizeof(Eterm)*sz);
p->old_hend = p->old_htop = p->old_heap = NULL;
@@ -11893,7 +11381,6 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
ERTS_P_LINKS(p) = NULL;
ERTS_P_MONITORS(p) = NULL;
ERTS_P_LT_MONITORS(p) = NULL;
- p->suspend_monitors = NULL;
ASSERT(is_pid(parent->group_leader));
@@ -11950,8 +11437,6 @@ erl_create_process(Process* parent, /* Parent of process (default group leader).
p->trace_msg_q = NULL;
p->scheduler_data = NULL;
- p->suspendee = NIL;
- p->pending_suspenders = NULL;
#if !defined(NO_FPE_SIGNALS) || defined(HIPE)
p->fp_exception = 0;
@@ -12118,7 +11603,6 @@ void erts_init_empty_process(Process *p)
ERTS_P_MONITORS(p) = NULL;
ERTS_P_LT_MONITORS(p) = NULL;
ERTS_P_LINKS(p) = NULL; /* List of links */
- p->suspend_monitors = NULL;
p->sig_qs.first = NULL;
p->sig_qs.last = &p->sig_qs.first;
p->sig_qs.cont = NULL;
@@ -12169,7 +11653,6 @@ void erts_init_empty_process(Process *p)
#ifdef HIPE
hipe_init_process(&p->hipe);
- hipe_init_process_smp(&p->hipe_smp);
#endif
INIT_HOLE_CHECK(p);
@@ -12182,8 +11665,6 @@ void erts_init_empty_process(Process *p)
erts_atomic32_init_nob(&p->state, (erts_aint32_t) PRIORITY_NORMAL);
p->scheduler_data = NULL;
- p->suspendee = NIL;
- p->pending_suspenders = NULL;
erts_proc_lock_init(p);
erts_proc_unlock(p, ERTS_PROC_LOCKS_ALL);
erts_init_runq_proc(p, ERTS_RUNQ_IX(0), 0);
@@ -12221,7 +11702,6 @@ erts_debug_verify_clean_empty_process(Process* p)
ASSERT(ERTS_P_MONITORS(p) == NULL);
ASSERT(ERTS_P_LT_MONITORS(p) == NULL);
ASSERT(ERTS_P_LINKS(p) == NULL);
- ASSERT(p->suspend_monitors == NULL);
ASSERT(p->sig_qs.first == NULL);
ASSERT(p->sig_qs.len == 0);
ASSERT(p->bif_timers == NULL);
@@ -12235,8 +11715,6 @@ erts_debug_verify_clean_empty_process(Process* p)
ASSERT(p->sig_inq.first == NULL);
ASSERT(p->sig_inq.len == 0);
- ASSERT(p->suspendee == NIL);
- ASSERT(p->pending_suspenders == NULL);
/* Thing that erts_cleanup_empty_process() cleans up */
@@ -12342,8 +11820,6 @@ delete_process(Process* p)
erts_cleanup_messages(p->sig_qs.cont);
p->sig_qs.cont = NULL;
- ASSERT(!p->suspend_monitors);
-
p->fvalue = NIL;
}
@@ -12423,6 +11899,7 @@ erts_proc_exit_handle_monitor(ErtsMonitor *mon, void *vctxt)
if (erts_monitor_is_target(mon)) {
/* We are being watched... */
switch (mon->type) {
+ case ERTS_MON_TYPE_SUSPEND:
case ERTS_MON_TYPE_PROC:
erts_proc_sig_send_monitor_down(mon, reason);
mon = NULL;
@@ -12494,6 +11971,7 @@ erts_proc_exit_handle_monitor(ErtsMonitor *mon, void *vctxt)
else { /* Origin monitor */
/* We are watching someone else... */
switch (mon->type) {
+ case ERTS_MON_TYPE_SUSPEND:
case ERTS_MON_TYPE_PROC:
erts_proc_sig_send_demonitor(mon);
mon = NULL;
@@ -12646,21 +12124,6 @@ erts_proc_exit_handle_link(ErtsLink *lnk, void *vctxt)
erts_link_release(lnk);
}
-static void
-resume_suspend_monitor(ErtsMonitor *mon, void *vc_p)
-{
- ErtsMonitorSuspend *smon = erts_monitor_suspend(mon);
- Process *suspendee = erts_pid2proc((Process *) vc_p, ERTS_PROC_LOCK_MAIN,
- smon->mon.other.item, ERTS_PROC_LOCK_STATUS);
- if (suspendee) {
- ASSERT(suspendee != vc_p);
- if (smon->active)
- resume_process(suspendee, ERTS_PROC_LOCK_STATUS);
- erts_proc_unlock(suspendee, ERTS_PROC_LOCK_STATUS);
- }
- erts_monitor_suspend_destroy(smon);
-}
-
/* this function fishishes a process and propagates exit messages - called
by process_main when a process dies */
void
@@ -12692,8 +12155,6 @@ erts_do_exit_process(Process* p, Eterm reason)
set_self_exiting(p, reason, NULL, NULL, NULL);
- cancel_suspend_of_suspendee(p, ERTS_PROC_LOCKS_ALL);
-
if (IS_TRACED(p)) {
if (IS_TRACED_FL(p, F_TRACE_CALLS))
erts_schedule_time_break(p, ERTS_BP_CALL_TIME_SCHEDULE_EXITING);
@@ -12826,11 +12287,6 @@ erts_continue_exit_process(Process *p)
p->flags &= ~F_USING_DDLL;
}
- if (p->suspend_monitors)
- erts_monitor_tree_foreach_delete(&p->suspend_monitors,
- resume_suspend_monitor,
- p);
-
/*
* The registered name *should* be the last "erlang resource" to
* cleanup.
@@ -13038,7 +12494,13 @@ erts_try_lock_sig_free_proc(Eterm pid, ErtsProcLocks locks,
erts_aint32_t *statep)
{
Process *rp = erts_proc_lookup_raw(pid);
+ erts_aint32_t fail_state = ERTS_PSFLG_SIG_IN_Q|ERTS_PSFLG_SIG_Q;
erts_aint32_t state;
+ ErtsProcLocks tmp_locks = ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_MSGQ;
+
+ tmp_locks |= locks;
+ if (statep)
+ fail_state |= *statep;
if (!rp) {
if (statep)
@@ -13055,28 +12517,28 @@ erts_try_lock_sig_free_proc(Eterm pid, ErtsProcLocks locks,
if (state & ERTS_PSFLG_FREE)
return NULL;
- if (state & (ERTS_PSFLG_SIG_IN_Q|ERTS_PSFLG_SIG_Q))
+ if (state & fail_state)
return ERTS_PROC_LOCK_BUSY;
- if (!locks)
- return rp;
-
- if (erts_proc_trylock(rp, locks) == EBUSY)
+ if (erts_proc_trylock(rp, tmp_locks) == EBUSY)
return ERTS_PROC_LOCK_BUSY;
state = erts_atomic32_read_nob(&rp->state);
if (statep)
*statep = state;
- if (state & ERTS_PSFLG_FREE) {
- erts_proc_unlock(rp, locks);
- return NULL;
+ if ((state & fail_state)
+ || rp->sig_inq.first
+ || rp->sig_qs.cont) {
+ erts_proc_unlock(rp, tmp_locks);
+ if (state & ERTS_PSFLG_FREE)
+ return NULL;
+ else
+ return ERTS_PROC_LOCK_BUSY;
}
- if (state & (ERTS_PSFLG_SIG_IN_Q|ERTS_PSFLG_SIG_Q)) {
- erts_proc_unlock(rp, locks);
- return ERTS_PROC_LOCK_BUSY;
- }
+ if (tmp_locks != locks)
+ erts_proc_unlock(rp, tmp_locks & ~locks);
return rp;
}
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h
index b66272194c..8d20ccdf90 100644
--- a/erts/emulator/beam/erl_process.h
+++ b/erts/emulator/beam/erl_process.h
@@ -293,7 +293,7 @@ typedef enum {
* highest index...
*
* Remember to update description in erts_pre_init_process()
- * when adding new flags...
+ * and etp-commands when adding new flags...
*/
typedef enum {
@@ -805,14 +805,15 @@ erts_reset_max_len(ErtsRunQueue *rq, ErtsRunQueueInfo *rqi)
#define ERTS_PSD_ETS_OWNED_TABLES 6
#define ERTS_PSD_ETS_FIXED_TABLES 7
#define ERTS_PSD_DIST_ENTRY 8
-#define ERTS_PSD_SUSPENDED_SAVED_CALLS_BUF 9 /* keep last... */
+#define ERTS_PSD_PENDING_SUSPEND 9
+#define ERTS_PSD_SUSPENDED_SAVED_CALLS_BUF 10 /* keep last... */
-#define ERTS_PSD_SIZE 10
+#define ERTS_PSD_SIZE 11
#if !defined(HIPE)
# undef ERTS_PSD_SUSPENDED_SAVED_CALLS_BUF
# undef ERTS_PSD_SIZE
-# define ERTS_PSD_SIZE 9
+# define ERTS_PSD_SIZE 10
#endif
typedef struct {
@@ -849,6 +850,9 @@ typedef struct {
#define ERTS_PSD_DIST_ENTRY_GET_LOCKS ERTS_PROC_LOCK_MAIN
#define ERTS_PSD_DIST_ENTRY_SET_LOCKS ERTS_PROC_LOCK_MAIN
+#define ERTS_PSD_PENDING_SUSPEND_GET_LOCKS ERTS_PROC_LOCK_MAIN
+#define ERTS_PSD_PENDING_SUSPEND_SET_LOCKS ERTS_PROC_LOCK_MAIN
+
typedef struct {
ErtsProcLocks get_locks;
ErtsProcLocks set_locks;
@@ -884,20 +888,6 @@ typedef struct {
typedef struct ErtsProcSysTask_ ErtsProcSysTask;
typedef struct ErtsProcSysTaskQs_ ErtsProcSysTaskQs;
-
-typedef struct ErtsPendingSuspend_ ErtsPendingSuspend;
-struct ErtsPendingSuspend_ {
- ErtsPendingSuspend *next;
- ErtsPendingSuspend *end;
- Eterm pid;
- void (*handle_func)(Process *suspendee,
- ErtsProcLocks suspendee_locks,
- int suspendee_alive,
- Eterm pid);
-};
-
-
-
/* Defines to ease the change of memory architecture */
# define HEAP_START(p) (p)->heap
# define HEAP_TOP(p) (p)->htop
@@ -992,9 +982,6 @@ struct process {
Process *next; /* Pointer to next process in run queue */
- ErtsMonitor *suspend_monitors; /* Processes suspended by this process via
- erlang:suspend_process/1 */
-
ErtsSignalPrivQueues sig_qs; /* Signal queues */
ErtsBifTimers *bif_timers; /* Bif timers aiming at this process */
@@ -1058,12 +1045,7 @@ struct process {
ErlTraceMessageQueue *trace_msg_q;
erts_proc_lock_t lock;
ErtsSchedulerData *scheduler_data;
- Eterm suspendee;
- ErtsPendingSuspend *pending_suspenders;
erts_atomic_t run_queue;
-#ifdef HIPE
- struct hipe_process_state_smp hipe_smp;
-#endif
#ifdef CHECK_FOR_HOLES
Eterm* last_htop; /* No need to scan the heap below this point. */
@@ -1380,7 +1362,7 @@ extern int erts_system_profile_ts_type;
#define F_DISTRIBUTION (1 << 6) /* Process used in distribution */
#define F_USING_DDLL (1 << 7) /* Process has used the DDLL interface */
#define F_HAVE_BLCKD_MSCHED (1 << 8) /* Process has blocked multi-scheduling */
-#define F_P2PNR_RESCHED (1 << 9) /* Process has been rescheduled via erts_pid2proc_not_running() */
+#define F_UNUSED (1 << 9)
#define F_FORCE_GC (1 << 10) /* Force gc at process in-scheduling */
#define F_DISABLE_GC (1 << 11) /* Disable GC (see below) */
#define F_OFF_HEAP_MSGQ (1 << 12) /* Off heap msg queue */
@@ -1397,10 +1379,12 @@ extern int erts_system_profile_ts_type;
#define F_DIRTY_MAJOR_GC (1 << 23) /* Dirty major GC scheduled */
#define F_DIRTY_MINOR_GC (1 << 24) /* Dirty minor GC scheduled */
#define F_HIBERNATED (1 << 25) /* Hibernated */
-#define F_LOCAL_SIGS_ONLY (1 << 26)
+#define F_LOCAL_SIGS_ONLY (1 << 26) /* Handle privq sigs only */
#define F_TRAP_EXIT (1 << 27) /* Trapping exit */
-#define F_DEFERRED_SAVED_LAST (1 << 28)
-#define F_DELAYED_PSIGQS_LEN (1 << 29)
+#define F_DEFERRED_SAVED_LAST (1 << 28) /* Deferred sig_qs.saved_last */
+#define F_DELAYED_PSIGQS_LEN (1 << 29) /* Delayed update of sig_qs.len */
+#define F_HIPE_RECV_LOCKED (1 << 30) /* HiPE message queue locked */
+#define F_HIPE_RECV_YIELD (1 << 31) /* HiPE receive yield */
/*
* F_DISABLE_GC and F_DELAY_GC are similar. Both will prevent
@@ -2048,6 +2032,11 @@ erts_psd_set(Process *p, int ix, void *data)
#define ERTS_PROC_SET_DIST_ENTRY(P, DE) \
((DistEntry *) erts_psd_set((P), ERTS_PSD_DIST_ENTRY, (void *) (DE)))
+#define ERTS_PROC_GET_PENDING_SUSPEND(P) \
+ ((void *) erts_psd_get((P), ERTS_PSD_PENDING_SUSPEND))
+#define ERTS_PROC_SET_PENDING_SUSPEND(P, PS) \
+ ((void *) erts_psd_set((P), ERTS_PSD_PENDING_SUSPEND, (void *) (PS)))
+
#ifdef HIPE
#define ERTS_PROC_GET_SUSPENDED_SAVED_CALLS_BUF(P) \
((struct saved_calls *) erts_psd_get((P), ERTS_PSD_SUSPENDED_SAVED_CALLS_BUF))
@@ -2612,16 +2601,6 @@ Process *erts_try_lock_sig_free_proc(Eterm pid,
ErtsProcLocks locks,
erts_aint32_t *statep);
-Process *erts_pid2proc_not_running(Process *,
- ErtsProcLocks,
- Eterm,
- ErtsProcLocks);
-Process *erts_pid2proc_nropt(Process *c_p,
- ErtsProcLocks c_p_locks,
- Eterm pid,
- ErtsProcLocks pid_locks);
-extern int erts_disable_proc_not_running_opt;
-
#ifdef DEBUG
#define ERTS_ASSERT_IS_NOT_EXITING(P) \
do { ASSERT(!ERTS_PROC_IS_EXITING((P))); } while (0)
diff --git a/erts/emulator/beam/erl_process_dict.c b/erts/emulator/beam/erl_process_dict.c
index 38be3938cd..64ee483079 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1999-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_process_dict.h b/erts/emulator/beam/erl_process_dict.h
index b89b387f5a..3ff2354f91 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1999-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c
index 243db4c734..706530023b 100644
--- a/erts/emulator/beam/erl_process_dump.c
+++ b/erts/emulator/beam/erl_process_dump.c
@@ -963,12 +963,16 @@ dump_module_literals(fmtfn_t to, void *to_arg, ErtsLiteralArea* lit_area)
}
erts_putc(to, to_arg, '\n');
}
- } else if (is_export_header(w)) {
+ } else if (is_export_header(w) || is_fun_header(w)) {
dump_externally(to, to_arg, term);
erts_putc(to, to_arg, '\n');
}
size = 1 + header_arity(w);
switch (w & _HEADER_SUBTAG_MASK) {
+ case FUN_SUBTAG:
+ ASSERT(((ErlFunThing*)(htop))->num_free == 0);
+ size += 1;
+ break;
case MAP_SUBTAG:
if (is_flatmap_header(w)) {
size += 1 + flatmap_get_size(htop);
diff --git a/erts/emulator/beam/erl_process_lock.h b/erts/emulator/beam/erl_process_lock.h
index 43f396c547..bd38eca4dc 100644
--- a/erts/emulator/beam/erl_process_lock.h
+++ b/erts/emulator/beam/erl_process_lock.h
@@ -921,6 +921,9 @@ ERTS_GLB_INLINE int erts_proc_trylock(Process *, ErtsProcLocks);
ERTS_GLB_INLINE void erts_proc_inc_refc(Process *);
ERTS_GLB_INLINE void erts_proc_dec_refc(Process *);
+ERTS_GLB_INLINE void erts_proc_dec_refc_free_func(Process *p,
+ void (*func)(int, void *),
+ void *arg);
ERTS_GLB_INLINE void erts_proc_add_refc(Process *, Sint);
ERTS_GLB_INLINE Sint erts_proc_read_refc(Process *);
@@ -993,6 +996,21 @@ ERTS_GLB_INLINE void erts_proc_dec_refc(Process *p)
}
}
+ERTS_GLB_INLINE void erts_proc_dec_refc_free_func(Process *p,
+ void (*func)(int, void *),
+ void *arg)
+{
+ Sint referred;
+ ASSERT(!(erts_atomic32_read_nob(&p->state) & ERTS_PSFLG_PROXY));
+ referred = erts_ptab_atmc_dec_test_refc(&p->common);
+ if (!referred) {
+ ASSERT(ERTS_PROC_IS_EXITING(p));
+ (*func)(!0, arg);
+ erts_free_proc(p);
+ (*func)(0, arg);
+ }
+}
+
ERTS_GLB_INLINE void erts_proc_add_refc(Process *p, Sint add_refc)
{
Sint referred;
diff --git a/erts/emulator/beam/erl_sched_spec_pre_alloc.c b/erts/emulator/beam/erl_sched_spec_pre_alloc.c
index 4a6e02281a..9766e76a83 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2011-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_sched_spec_pre_alloc.h b/erts/emulator/beam/erl_sched_spec_pre_alloc.h
index d232db0e69..b119c59ab3 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2011-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_thr_progress.c b/erts/emulator/beam/erl_thr_progress.c
index 96824dc06e..aa08eb40ec 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2011-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_thr_progress.h b/erts/emulator/beam/erl_thr_progress.h
index 8c029bcf99..8329995b24 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2011-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_thr_queue.c b/erts/emulator/beam/erl_thr_queue.c
index 548c2768e5..aab7c199d2 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2011-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_thr_queue.h b/erts/emulator/beam/erl_thr_queue.h
index 163a25318d..29b58063ac 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2011-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c
index 4f91d9ad07..29c698e34f 100644
--- a/erts/emulator/beam/erl_time_sup.c
+++ b/erts/emulator/beam/erl_time_sup.c
@@ -1860,7 +1860,7 @@ void erts_get_now_cpu(Uint* megasec, Uint* sec, Uint* microsec) {
SysCpuTime t;
SysTimespec tp;
- sys_get_proc_cputime(t, tp);
+ sys_get_cputime(t, tp);
*microsec = (Uint)(tp.tv_nsec / 1000);
t = (tp.tv_sec / 1000000);
*megasec = (Uint)(t % 1000000);
diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c
index 065a560b52..53a020e7a5 100644
--- a/erts/emulator/beam/erl_trace.c
+++ b/erts/emulator/beam/erl_trace.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1999-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -625,20 +625,6 @@ erts_get_system_profile(void) {
return profile;
}
-
-#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 GET_NOW(m, s, u) do {get_now(m, s, u);} while (0)
-#endif
-
-
static void
write_sys_msg_to_port(Eterm unused_to,
Port* trace_port,
@@ -2629,6 +2615,38 @@ erts_tracer_to_term(Process *p, ErtsTracer tracer)
}
}
+Eterm
+erts_build_tracer_to_term(Eterm **hpp, ErlOffHeap *ohp, Uint *szp, ErtsTracer tracer)
+{
+ Eterm res;
+ Eterm state;
+ Uint sz;
+
+ if (ERTS_TRACER_IS_NIL(tracer))
+ return am_false;
+
+ state = ERTS_TRACER_STATE(tracer);
+ sz = is_immed(state) ? 0 : size_object(state);
+
+ if (szp)
+ *szp += sz;
+
+ if (hpp)
+ res = is_immed(state) ? state : copy_struct(state, sz, hpp, ohp);
+ else
+ res = THE_NON_VALUE;
+
+ if (ERTS_TRACER_MODULE(tracer) != am_erl_tracer) {
+ if (szp)
+ *szp += 3;
+ if (hpp) {
+ res = TUPLE2(*hpp, ERTS_TRACER_MODULE(tracer), res);
+ *hpp += 3;
+ }
+ }
+
+ return res;
+}
static ERTS_INLINE int
send_to_tracer_nif_raw(Process *c_p, Process *tracee,
diff --git a/erts/emulator/beam/erl_trace.h b/erts/emulator/beam/erl_trace.h
index dbf7ebd2a1..bccf31606e 100644
--- a/erts/emulator/beam/erl_trace.h
+++ b/erts/emulator/beam/erl_trace.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2012-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2012-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -198,6 +198,8 @@ int erts_is_tracer_proc_enabled_send(Process* c_p, ErtsProcLocks c_p_locks,
ErtsPTabElementCommon *t_p);
int erts_is_tracer_enabled(const ErtsTracer tracer, ErtsPTabElementCommon *t_p);
Eterm erts_tracer_to_term(Process *p, ErtsTracer tracer);
+Eterm erts_build_tracer_to_term(Eterm **hpp, ErlOffHeap *ohp, Uint *szp, ErtsTracer tracer);
+
ErtsTracer erts_term_to_tracer(Eterm prefix, Eterm term);
void erts_tracer_replace(ErtsPTabElementCommon *t_p,
const ErtsTracer new_tracer);
diff --git a/erts/emulator/beam/erl_unicode.c b/erts/emulator/beam/erl_unicode.c
index 8673e029e6..d225916ac5 100644
--- a/erts/emulator/beam/erl_unicode.c
+++ b/erts/emulator/beam/erl_unicode.c
@@ -79,23 +79,23 @@ void erts_init_unicode(void)
max_loop_limit = CONTEXT_REDS * LOOP_FACTOR;
/* Non visual BIFs to trap to. */
erts_init_trap_export(&characters_to_utf8_trap_exp,
- am_erlang, am_atom_put("characters_to_utf8_trap",23), 3,
+ am_erlang, ERTS_MAKE_AM("characters_to_utf8_trap"), 3,
&characters_to_utf8_trap);
erts_init_trap_export(&characters_to_list_trap_1_exp,
- am_erlang, am_atom_put("characters_to_list_trap_1",25), 3,
+ am_erlang, ERTS_MAKE_AM("characters_to_list_trap_1"), 3,
&characters_to_list_trap_1);
erts_init_trap_export(&characters_to_list_trap_2_exp,
- am_erlang, am_atom_put("characters_to_list_trap_2",25), 3,
+ am_erlang, ERTS_MAKE_AM("characters_to_list_trap_2"), 3,
&characters_to_list_trap_2);
erts_init_trap_export(&characters_to_list_trap_3_exp,
- am_erlang, am_atom_put("characters_to_list_trap_3",25), 3,
+ am_erlang, ERTS_MAKE_AM("characters_to_list_trap_3"), 3,
&characters_to_list_trap_3);
erts_init_trap_export(&characters_to_list_trap_4_exp,
- am_erlang, am_atom_put("characters_to_list_trap_4",25), 1,
+ am_erlang, ERTS_MAKE_AM("characters_to_list_trap_4"), 1,
&characters_to_list_trap_4);
c_to_b_int_trap_exportp = erts_export_put(am_unicode,am_characters_to_binary_int,2);
diff --git a/erts/emulator/beam/erl_utils.h b/erts/emulator/beam/erl_utils.h
index e4087e0ac8..b3bfa69052 100644
--- a/erts/emulator/beam/erl_utils.h
+++ b/erts/emulator/beam/erl_utils.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2012-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2012-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erl_vm.h b/erts/emulator/beam/erl_vm.h
index f8391fb665..4089fac48e 100644
--- a/erts/emulator/beam/erl_vm.h
+++ b/erts/emulator/beam/erl_vm.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/erlang_dtrace.d b/erts/emulator/beam/erlang_dtrace.d
index c47a37eb62..8792138d53 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-2016.
+ * Copyright Dustin Sallings, Michal Ptaszek, Scott Lystig Fritchie 2011-2018.
* All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/erts/emulator/beam/erlang_lttng.h b/erts/emulator/beam/erlang_lttng.h
index feb05f4f4c..9b93d77f6e 100644
--- a/erts/emulator/beam/erlang_lttng.h
+++ b/erts/emulator/beam/erlang_lttng.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/export.h b/erts/emulator/beam/export.h
index 194e514b12..ae8dfa4cf8 100644
--- a/erts/emulator/beam/export.h
+++ b/erts/emulator/beam/export.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c
index fb42969a8f..904993ceb6 100644
--- a/erts/emulator/beam/external.c
+++ b/erts/emulator/beam/external.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/hash.c b/erts/emulator/beam/hash.c
index 6a31489473..8954dbb06c 100644
--- a/erts/emulator/beam/hash.c
+++ b/erts/emulator/beam/hash.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/instrs.tab b/erts/emulator/beam/instrs.tab
index 6a531fcc09..42c1168f85 100644
--- a/erts/emulator/beam/instrs.tab
+++ b/erts/emulator/beam/instrs.tab
@@ -2,7 +2,7 @@
//
// %CopyrightBegin%
//
-// Copyright Ericsson AB 2017. All Rights Reserved.
+// Copyright Ericsson AB 2017-2018. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index 2446b3c074..133ab485d9 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -3287,7 +3287,6 @@ static void deliver_read_message(Port* prt, erts_aint32_t state, Eterm to,
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_proc_unlock(rp, rp_locks);
@@ -3459,7 +3458,6 @@ deliver_vec_message(Port* prt, /* Port */
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_proc_unlock(rp, rp_locks);
if (!scheduler)
@@ -5382,7 +5380,6 @@ void driver_report_exit(ErlDrvPort ix, int status)
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_proc_unlock(rp, rp_locks);
@@ -5988,8 +5985,6 @@ driver_deliver_term(Port *prt, Eterm to, ErlDrvTermData* data, int len)
from = prt->common.id;
}
- /* send message */
- ERL_MESSAGE_TOKEN(factory.message) = am_undefined;
erts_queue_message(rp, rp_locks, factory.message, mess, from);
}
else if (res == -2) {
diff --git a/erts/emulator/beam/lttng-wrapper.h b/erts/emulator/beam/lttng-wrapper.h
index e7f2971bf7..ad4852374a 100644
--- a/erts/emulator/beam/lttng-wrapper.h
+++ b/erts/emulator/beam/lttng-wrapper.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/module.c b/erts/emulator/beam/module.c
index 1712dc803c..0642a06123 100644
--- a/erts/emulator/beam/module.c
+++ b/erts/emulator/beam/module.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/module.h b/erts/emulator/beam/module.h
index a3f1ce1705..00efd129ff 100644
--- a/erts/emulator/beam/module.h
+++ b/erts/emulator/beam/module.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab
index 8b2d9098a8..c51e4ef784 100644
--- a/erts/emulator/beam/ops.tab
+++ b/erts/emulator/beam/ops.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2017. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -1421,16 +1421,13 @@ get_map_elements Fail Src Size Rest=* | map_key_sort(Size, Rest) => \
i_get_map_elements f? s I
-i_get_map_element Fail Src=xy Key=y Dst => \
- move Key x | i_get_map_element Fail Src x Dst
-
i_get_map_element_hash Fail Src=c Key Hash Dst => \
move Src x | i_get_map_element_hash Fail x Key Hash Dst
i_get_map_element_hash f? xy c I xy
i_get_map_element Fail Src=c Key Dst => \
move Src x | i_get_map_element Fail x Key Dst
-i_get_map_element f? xy x xy
+i_get_map_element f? xy xy xy
#
# Convert the plus operations to a generic plus instruction.
diff --git a/erts/emulator/beam/packet_parser.c b/erts/emulator/beam/packet_parser.c
index de1d481105..4b526887b5 100644
--- a/erts/emulator/beam/packet_parser.c
+++ b/erts/emulator/beam/packet_parser.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/register.c b/erts/emulator/beam/register.c
index 92a0854ad3..c7e02c6d48 100644
--- a/erts/emulator/beam/register.c
+++ b/erts/emulator/beam/register.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/safe_hash.c b/erts/emulator/beam/safe_hash.c
index 73306030ae..0d816a81a9 100644
--- a/erts/emulator/beam/safe_hash.c
+++ b/erts/emulator/beam/safe_hash.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/safe_hash.h b/erts/emulator/beam/safe_hash.h
index af97b4cb4d..bd81e3022b 100644
--- a/erts/emulator/beam/safe_hash.h
+++ b/erts/emulator/beam/safe_hash.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h
index be6ab57eeb..bb22548587 100644
--- a/erts/emulator/beam/sys.h
+++ b/erts/emulator/beam/sys.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index d74052d8b2..996757ef43 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1569,7 +1569,7 @@ make_hash2(Eterm term)
* MUST BE USED AS INPUT FOR THE HASH. Two different terms must always have a
* chance of hashing different when salted: hash([Salt|A]) vs hash([Salt|B]).
*
- * This is why we can not use cached hash values for atoms for example.
+ * This is why we cannot use cached hash values for atoms for example.
*
*/
@@ -1946,7 +1946,7 @@ do_allocate_logger_message(Eterm gleader, ErtsMonotonicTime *ts, Eterm *pid,
else
sz += MAP4_SZ /* metadata map w gl w pid*/;
- *ts = ERTS_MONOTONIC_TO_USEC(erts_get_monotonic_time(NULL)) + ERTS_MONOTONIC_OFFSET_USEC;
+ *ts = ERTS_MONOTONIC_TO_USEC(erts_get_monotonic_time(NULL) + erts_get_time_offset());
erts_bld_sint64(NULL, &sz, *ts);
*bp = new_message_buffer(sz);
@@ -1972,8 +1972,7 @@ static void do_send_logger_message(Eterm gl, Eterm tag, Eterm format, Eterm args
break;
}
- md = MAP2(hp, am_emulator, am_true,
- am_atom_put("tag", 3), el_tag);
+ md = MAP2(hp, am_emulator, am_true, ERTS_MAKE_AM("tag"), el_tag);
hp += MAP2_SZ;
if (is_nil(gl) && is_non_value(pid)) {
@@ -1994,14 +1993,14 @@ static void do_send_logger_message(Eterm gl, Eterm tag, Eterm format, Eterm args
/* no gl */
md = MAP3(hp,
am_error_logger, md,
- am_atom_put("gl", 2), gl,
+ ERTS_MAKE_AM("gl"), gl,
am_time, time);
hp += MAP3_SZ;
pid = NIL;
} else {
md = MAP4(hp,
am_error_logger, md,
- am_atom_put("gl", 2), gl,
+ ERTS_MAKE_AM("gl"), gl,
am_pid, pid,
am_time, time);
hp += MAP4_SZ;
@@ -3123,7 +3122,7 @@ tailrecur_ne:
ASSERT(alen == blen);
for (i = (Sint) alen - 1; i >= 0; i--)
if (anum[i] != bnum[i])
- RETURN_NEQ((Sint32) (anum[i] - bnum[i]));
+ RETURN_NEQ(anum[i] < bnum[i] ? -1 : 1);
goto pop_next;
case (_TAG_HEADER_EXTERNAL_REF >> _TAG_PRIMARY_SIZE):
if (is_internal_ref(b)) {
diff --git a/erts/emulator/drivers/common/gzio.h b/erts/emulator/drivers/common/gzio.h
index e331b5208b..20433a1a17 100644
--- a/erts/emulator/drivers/common/gzio.h
+++ b/erts/emulator/drivers/common/gzio.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1999-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index 1a68f65b52..91381bd60d 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1997-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1034,6 +1034,7 @@ typedef struct {
inet_async_op* oph; /* queue head or NULL */
inet_async_op* opt; /* queue tail or NULL */
inet_async_op op_queue[INET_MAX_ASYNC]; /* call queue */
+ int op_ref; /* queue reference generator */
int active; /* 0 = passive, 1 = active, 2 = active once */
Sint16 active_count; /* counter for {active,N} */
@@ -1299,8 +1300,7 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event);
/* convert descriptor pointer to inet_descriptor pointer */
#define INETP(d) (&(d)->inet)
-static int async_ref = 0; /* async reference id generator */
-#define NEW_ASYNC_ID() ((async_ref++) & 0xffff)
+#define NEW_ASYNC_ID(desc) ((desc)->op_ref++ & 0xffff)
/* check for transition from active to passive */
#define INET_CHECK_ACTIVE_TO_PASSIVE(inet) \
@@ -1549,6 +1549,8 @@ static void *realloc_wrapper(void *current, ErlDrvSizeT size){
# define LOAD_ASSOC_ID LOAD_UINT
# define LOAD_ASSOC_ID_CNT LOAD_UINT_CNT
# define SCTP_ANC_BUFF_SIZE INET_DEF_BUFFER/2 /* XXX: not very good... */
+#else
+# define IS_SCTP(desc) 0
#endif
#ifdef HAVE_UDP
@@ -1785,6 +1787,7 @@ static void release_buffer(ErlDrvBinary* buf)
#ifdef HAVE_UDP
static ErlDrvBinary* realloc_buffer(ErlDrvBinary* buf, ErlDrvSizeT newsz)
{
+ DEBUGF(("realloc_buffer: %ld -> %ld\r\n", (buf==NULL) ? 0 : buf->orig_size, newsz));
return driver_realloc_binary(buf, newsz);
}
#endif
@@ -1955,7 +1958,7 @@ static void enq_multi_op(tcp_descriptor *desc, char *buf, int req,
ErlDrvTermData caller, MultiTimerData *timeout,
ErlDrvMonitor *monitorp)
{
- int id = NEW_ASYNC_ID();
+ int id = NEW_ASYNC_ID(INETP(desc));
enq_old_multi_op(desc,id,req,caller,timeout,monitorp);
if (buf != NULL)
put_int16(id, buf);
@@ -2024,7 +2027,7 @@ static int remove_multi_op(tcp_descriptor *desc, int *id_p, int *req_p,
static int enq_async_w_tmo(inet_descriptor* desc, char* buf, int req, unsigned timeout,
ErlDrvMonitor *monitorp)
{
- int id = NEW_ASYNC_ID();
+ int id = NEW_ASYNC_ID(desc);
inet_async_op* opp;
if ((opp = desc->oph) == NULL) /* queue empty */
@@ -4390,7 +4393,7 @@ static void desc_close_read(inet_descriptor* desc)
{
if (desc->s != INVALID_SOCKET) {
#ifdef __WIN32__
- /* This call can not be right???
+ /* This call cannot be right???
* We want to turn off read events but keep any write events.
* But on windows driver_select(...,READ,1) is only used as a
* way to hook into the pollset. sock_select is used to control
@@ -6435,7 +6438,12 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
(long)desc->port, desc->s, res));
if (type == SO_RCVBUF) {
/* make sure we have desc->bufsz >= SO_RCVBUF */
- if (ival > desc->bufsz)
+ if (ival > (1 << 16) && desc->stype == SOCK_DGRAM && !IS_SCTP(desc))
+ /* For UDP we don't want to automatically
+ set the buffer size to be larger than
+ the theoretical max MTU */
+ desc->bufsz = 1 << 16;
+ else if (ival > desc->bufsz)
desc->bufsz = ival;
}
}
@@ -8461,6 +8469,7 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol)
desc->delimiter = '\n'; /* line delimiting char */
desc->oph = NULL;
desc->opt = NULL;
+ desc->op_ref = 0;
desc->peer_ptr = NULL;
desc->name_ptr = NULL;
@@ -12041,15 +12050,11 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
sys_memzero((char *) &other, sizeof(other));
/* udesc->i_buf is only kept between SCTP fragments */
- if (udesc->i_buf == NULL) {
- udesc->i_bufsz = desc->bufsz + len;
- if ((udesc->i_buf = alloc_buffer(udesc->i_bufsz)) == NULL)
- return packet_error(udesc, ENOMEM);
- /* pointer to message start */
- udesc->i_ptr = udesc->i_buf->orig_bytes + len;
- } else {
- ErlDrvBinary* tmp;
+#ifdef HAVE_SCTP
+ if (udesc->i_buf != NULL) {
+ ErlDrvBinary* tmp;
int bufsz;
+ ASSERT(IS_SCTP(desc));
bufsz = desc->bufsz + (udesc->i_ptr - udesc->i_buf->orig_bytes);
if ((tmp = realloc_buffer(udesc->i_buf, bufsz)) == NULL) {
release_buffer(udesc->i_buf);
@@ -12061,6 +12066,15 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
udesc->i_buf = tmp;
udesc->i_bufsz = bufsz;
}
+ } else
+#endif
+ {
+ ASSERT(udesc->i_buf == NULL);
+ udesc->i_bufsz = desc->bufsz + len;
+ if ((udesc->i_buf = alloc_buffer(udesc->i_bufsz)) == NULL)
+ return packet_error(udesc, ENOMEM);
+ /* pointer to message start */
+ udesc->i_ptr = udesc->i_buf->orig_bytes + len;
}
/* Note: On Windows NT, recvfrom() fails if the socket is connected. */
@@ -12119,6 +12133,14 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
) {
sock_select(desc,FD_READ,1);
}
+#ifdef HAVE_SCTP
+ if (!short_recv) {
+#endif
+ release_buffer(udesc->i_buf);
+ udesc->i_buf = NULL;
+#ifdef HAVE_SCTP
+ }
+#endif
return count; /* strange, not ready */
}
diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c
index 7355df6059..11bb4373d8 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,7 +31,7 @@
static int ttysl_init(void);
static ErlDrvData ttysl_start(ErlDrvPort, char*);
-#ifdef HAVE_TERMCAP /* else make an empty driver that can not be opened */
+#ifdef HAVE_TERMCAP /* else make an empty driver that cannot be opened */
#ifndef WANT_NONBLOCKING
#define WANT_NONBLOCKING
diff --git a/erts/emulator/hipe/hipe_amd64.c b/erts/emulator/hipe/hipe_amd64.c
index f23f341e6d..71cbb7c060 100644
--- a/erts/emulator/hipe/hipe_amd64.c
+++ b/erts/emulator/hipe/hipe_amd64.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2004-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/hipe/hipe_amd64_bifs.m4 b/erts/emulator/hipe/hipe_amd64_bifs.m4
index cf4c59c9af..4c866b3b68 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2004-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/hipe/hipe_arm_bifs.m4 b/erts/emulator/hipe/hipe_arm_bifs.m4
index 554faa2567..421915dd72 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2005-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/hipe/hipe_bif2.c b/erts/emulator/hipe/hipe_bif2.c
index df377b2153..7e04f7d9c0 100644
--- a/erts/emulator/hipe/hipe_bif2.c
+++ b/erts/emulator/hipe/hipe_bif2.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/hipe/hipe_bif2.tab b/erts/emulator/hipe/hipe_bif2.tab
index c4da44606a..8925291769 100644
--- a/erts/emulator/hipe/hipe_bif2.tab
+++ b/erts/emulator/hipe/hipe_bif2.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2001-2016. All Rights Reserved.
+# Copyright Ericsson AB 2001-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/erts/emulator/hipe/hipe_bif_list.m4 b/erts/emulator/hipe/hipe_bif_list.m4
index 33b3cc1ee5..7468860c37 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2004-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/hipe/hipe_debug.c b/erts/emulator/hipe/hipe_debug.c
index 929b2a9432..138e4f7da3 100644
--- a/erts/emulator/hipe/hipe_debug.c
+++ b/erts/emulator/hipe/hipe_debug.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/hipe/hipe_gc.c b/erts/emulator/hipe/hipe_gc.c
index aaedba1afd..7bd1de0117 100644
--- a/erts/emulator/hipe/hipe_gc.c
+++ b/erts/emulator/hipe/hipe_gc.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2004-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/hipe/hipe_mode_switch.c b/erts/emulator/hipe/hipe_mode_switch.c
index bc9a700204..052cf9c263 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -490,16 +490,21 @@ Process *hipe_mode_switch(Process *p, unsigned cmd, Eterm reg[])
/* same semantics, different debug trace messages */
/* XXX: BEAM has different entries for the locked and unlocked
cases. HiPE doesn't, so we must check dynamically. */
- if (p->hipe_smp.have_receive_locks)
- p->hipe_smp.have_receive_locks = 0;
+ if (p->flags & F_HIPE_RECV_LOCKED)
+ p->flags &= ~F_HIPE_RECV_LOCKED;
else
erts_proc_lock(p, ERTS_PROC_LOCKS_MSG_RECEIVE);
p->i = hipe_beam_pc_resume;
p->arity = 0;
if (erts_atomic32_read_nob(&p->state) & ERTS_PSFLG_EXITING)
ASSERT(erts_atomic32_read_nob(&p->state) & ERTS_PSFLG_ACTIVE);
- else
+ else if (!(p->flags & F_HIPE_RECV_YIELD))
erts_atomic32_read_band_relb(&p->state, ~ERTS_PSFLG_ACTIVE);
+ else {
+ /* Yielded from receive */
+ ERTS_VBUMP_ALL_REDS(p);
+ p->flags &= ~F_HIPE_RECV_YIELD;
+ }
erts_proc_unlock(p, ERTS_PROC_LOCKS_MSG_RECEIVE);
do_schedule:
{
@@ -522,7 +527,7 @@ Process *hipe_mode_switch(Process *p, unsigned cmd, Eterm reg[])
p = erts_schedule(NULL, p, reds_in - p->fcalls);
ERTS_REQ_PROC_MAIN_LOCK(p);
ASSERT(!(p->flags & F_HIPE_MODE));
- p->hipe_smp.have_receive_locks = 0;
+ p->flags &= ~F_HIPE_RECV_LOCKED;
reg = p->scheduler_data->x_reg_array;
}
{
diff --git a/erts/emulator/hipe/hipe_native_bif.c b/erts/emulator/hipe/hipe_native_bif.c
index 24078af046..211ce0492a 100644
--- a/erts/emulator/hipe/hipe_native_bif.c
+++ b/erts/emulator/hipe/hipe_native_bif.c
@@ -144,8 +144,8 @@ BIF_RETTYPE nbif_impl_hipe_set_timeout(NBIF_ALIST_1)
else {
int tres = erts_set_proc_timer_term(p, timeout_value);
if (tres != 0) { /* Wrong time */
- if (p->hipe_smp.have_receive_locks) {
- p->hipe_smp.have_receive_locks = 0;
+ if (p->flags & F_HIPE_RECV_LOCKED) {
+ p->flags &= ~F_HIPE_RECV_LOCKED;
erts_proc_unlock(p, ERTS_PROC_LOCKS_MSG_RECEIVE);
}
BIF_ERROR(p, EXC_TIMEOUT_VALUE);
@@ -549,19 +549,14 @@ Eterm hipe_check_get_msg(Process *c_p)
c_p->i = NULL;
c_p->arity = 0;
c_p->current = NULL;
- (void) erts_proc_sig_receive_helper(c_p, CONTEXT_REDS, 0,
+ (void) erts_proc_sig_receive_helper(c_p, CONTEXT_REDS/4, 0,
&msgp, &get_out);
/* FIXME: Need to bump reductions... */
if (!msgp) {
if (get_out) {
- if (get_out < 0) {
- /*
- * FIXME: We should get out yielding
- * here...
- */
- goto next_message;
- }
- /* Go exit... */
+ if (get_out < 0)
+ c_p->flags |= F_HIPE_RECV_YIELD; /* yield... */
+ /* else: go exit... */
return THE_NON_VALUE;
}
@@ -573,7 +568,7 @@ Eterm hipe_check_get_msg(Process *c_p)
*/
/* XXX: BEAM doesn't need this */
- c_p->hipe_smp.have_receive_locks = 1;
+ c_p->flags |= F_HIPE_RECV_LOCKED;
c_p->flags &= ~F_DELAY_GC;
return THE_NON_VALUE;
}
@@ -618,8 +613,8 @@ void hipe_clear_timeout(Process *c_p)
*/
/* XXX: BEAM has different entries for the locked and unlocked
cases. HiPE doesn't, so we must check dynamically. */
- if (c_p->hipe_smp.have_receive_locks) {
- c_p->hipe_smp.have_receive_locks = 0;
+ if (c_p->flags & F_HIPE_RECV_LOCKED) {
+ c_p->flags &= ~F_HIPE_RECV_LOCKED;
erts_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE);
}
if (IS_TRACED_FL(c_p, F_TRACE_RECEIVE)) {
diff --git a/erts/emulator/hipe/hipe_native_bif.h b/erts/emulator/hipe/hipe_native_bif.h
index ba42b126be..ce96778dea 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/hipe/hipe_ops.tab b/erts/emulator/hipe/hipe_ops.tab
index 19a3820a6a..8dd81558f2 100644
--- a/erts/emulator/hipe/hipe_ops.tab
+++ b/erts/emulator/hipe/hipe_ops.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2001-2016. All Rights Reserved.
+# Copyright Ericsson AB 2001-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/erts/emulator/hipe/hipe_ppc_bifs.m4 b/erts/emulator/hipe/hipe_ppc_bifs.m4
index 283fbbb200..2ced443ce4 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2004-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/hipe/hipe_primops.h b/erts/emulator/hipe/hipe_primops.h
index c5f10672f3..f4a4b4a07c 100644
--- a/erts/emulator/hipe/hipe_primops.h
+++ b/erts/emulator/hipe/hipe_primops.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2005-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/hipe/hipe_process.h b/erts/emulator/hipe/hipe_process.h
index ef14c75f6c..d412535968 100644
--- a/erts/emulator/hipe/hipe_process.h
+++ b/erts/emulator/hipe/hipe_process.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -82,13 +82,4 @@ static __inline__ void hipe_delete_process(struct hipe_process_state *p)
erts_free(ERTS_ALC_T_HIPE_STK, (void*)p->nstack);
}
-struct hipe_process_state_smp {
- int have_receive_locks;
-};
-
-static __inline__ void hipe_init_process_smp(struct hipe_process_state_smp *p)
-{
- p->have_receive_locks = 0;
-}
-
#endif /* HIPE_PROCESS_H */
diff --git a/erts/emulator/hipe/hipe_risc_stack.c b/erts/emulator/hipe/hipe_risc_stack.c
index bb93a918a2..b64afb1ba5 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/hipe/hipe_signal.h b/erts/emulator/hipe/hipe_signal.h
index 524def11a4..14bc0ef360 100644
--- a/erts/emulator/hipe/hipe_signal.h
+++ b/erts/emulator/hipe/hipe_signal.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2002-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/hipe/hipe_sparc_bifs.m4 b/erts/emulator/hipe/hipe_sparc_bifs.m4
index 1b49fa57fd..54684fbfb9 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/hipe/hipe_x86_bifs.m4 b/erts/emulator/hipe/hipe_x86_bifs.m4
index 9cb343d067..0f6b9a8c8a 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/hipe/hipe_x86_stack.c b/erts/emulator/hipe/hipe_x86_stack.c
index 615e07917a..8cfc541f0d 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/internal_doc/CarrierMigration.md b/erts/emulator/internal_doc/CarrierMigration.md
index 3a796d11b7..bb3d8aac28 100644
--- a/erts/emulator/internal_doc/CarrierMigration.md
+++ b/erts/emulator/internal_doc/CarrierMigration.md
@@ -34,8 +34,7 @@ Solution
--------
In order to prevent scenarios like this we've implemented support for
-migration of multi-block carriers between allocator instances of the
-same type.
+migration of multi-block carriers between allocator instances.
### Management of Free Blocks ###
@@ -130,10 +129,6 @@ threads may have references to it via the pool.
### Migration ###
-There exists one pool for each allocator type enabling migration of
-carriers between scheduler specific allocator instances of the same
-allocator type.
-
Each allocator instance keeps track of the current utilization of its
multi-block carriers. When the total utilization falls below the "abandon
carrier utilization limit" it starts to inspect the utilization of the
@@ -208,8 +203,8 @@ limited. We only inspect a limited number of carriers. If none of
those carriers had a free block large enough to satisfy the allocation
request, the search will fail. A carrier in the pool can also be BUSY
if another thread is currently doing block deallocation work on the
-carrier. A BUSY carrier will also be skipped by the search as it can
-not satisfy the request. The pool is lock-free and we do not want to
+carrier. A BUSY carrier will also be skipped by the search as it cannot
+satisfy the request. The pool is lock-free and we do not want to
block, waiting for the other thread to finish.
### The bad cluster problem ###
@@ -287,11 +282,3 @@ reduced using the `aoffcbf` strategy. A trade off between memory
consumption and performance is however inevitable, and it is up to
the user to decide what is most important.
-Further work
-------------
-
-It would be quite easy to extend this to allow migration of multi-block
-carriers between all allocator types. More or less the only obstacle
-is maintenance of the statistics information.
-
-
diff --git a/erts/emulator/nifs/common/prim_file_nif.c b/erts/emulator/nifs/common/prim_file_nif.c
index bbd9becb47..a05d50b333 100644
--- a/erts/emulator/nifs/common/prim_file_nif.c
+++ b/erts/emulator/nifs/common/prim_file_nif.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson 2017. All Rights Reserved.
+ * Copyright Ericsson 2017-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/nifs/common/prim_file_nif.h b/erts/emulator/nifs/common/prim_file_nif.h
index 4194cdc7d9..099c06c48c 100644
--- a/erts/emulator/nifs/common/prim_file_nif.h
+++ b/erts/emulator/nifs/common/prim_file_nif.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson 2017. All Rights Reserved.
+ * Copyright Ericsson 2017-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/nifs/unix/unix_prim_file.c b/erts/emulator/nifs/unix/unix_prim_file.c
index 2b112dda76..dea73db18a 100644
--- a/erts/emulator/nifs/unix/unix_prim_file.c
+++ b/erts/emulator/nifs/unix/unix_prim_file.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson 2017. All Rights Reserved.
+ * Copyright Ericsson 2017-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/nifs/win32/win_prim_file.c b/erts/emulator/nifs/win32/win_prim_file.c
index 044bee62cf..f7fae3c637 100644
--- a/erts/emulator/nifs/win32/win_prim_file.c
+++ b/erts/emulator/nifs/win32/win_prim_file.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson 2017. All Rights Reserved.
+ * Copyright Ericsson 2017-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c
index 3e77dce1cd..9f115706dc 100644
--- a/erts/emulator/sys/common/erl_check_io.c
+++ b/erts/emulator/sys/common/erl_check_io.c
@@ -1493,7 +1493,6 @@ send_event_tuple(struct erts_nif_select_event* e, ErtsResource* resource,
}
tuple = TUPLE4(hp, am_select, resource_term, ref_term, event_atom);
- ERL_MESSAGE_TOKEN(mp) = am_undefined;
erts_queue_message(rp, rp_locks, mp, tuple, am_system);
if (rp_locks)
diff --git a/erts/emulator/sys/common/erl_mmap.c b/erts/emulator/sys/common/erl_mmap.c
index 5dadd8a5a6..b0d9fc0776 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2002-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -2514,8 +2514,8 @@ Eterm erts_mmap_debug_info(Process* p)
sizeof(values)/sizeof(*values),
tags, values);
- sa_list = TUPLE2(hp, am_atom_put("sa_free_segs",12), sa_list); hp+=3;
- sua_list = TUPLE2(hp, am_atom_put("sua_free_segs",13), sua_list); hp+=3;
+ sa_list = TUPLE2(hp, ERTS_MAKE_AM("sa_free_segs"), sa_list); hp+=3;
+ sua_list = TUPLE2(hp, ERTS_MAKE_AM("sua_free_segs"), sua_list); hp+=3;
list = CONS(hp, sua_list, list); hp+=2;
list = CONS(hp, sa_list, list); hp+=2;
diff --git a/erts/emulator/sys/common/erl_mmap.h b/erts/emulator/sys/common/erl_mmap.h
index c1f9668b18..539daea419 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2013-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/sys/common/erl_mseg.c b/erts/emulator/sys/common/erl_mseg.c
index ced3d61525..030e5b00a7 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2002-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/sys/common/erl_mseg.h b/erts/emulator/sys/common/erl_mseg.h
index af275c18be..ea9060ddac 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2002-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
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 341845cc2a..5844e7eeb7 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2015-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/sys/common/erl_os_monotonic_time_extender.h b/erts/emulator/sys/common/erl_os_monotonic_time_extender.h
index 53c32579d5..f6659fe973 100644
--- a/erts/emulator/sys/common/erl_os_monotonic_time_extender.h
+++ b/erts/emulator/sys/common/erl_os_monotonic_time_extender.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2015. All Rights Reserved.
+ * Copyright Ericsson AB 2015-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/sys/common/erl_osenv.c b/erts/emulator/sys/common/erl_osenv.c
index 9f54d1dff0..487ff87116 100644
--- a/erts/emulator/sys/common/erl_osenv.c
+++ b/erts/emulator/sys/common/erl_osenv.c
@@ -75,7 +75,15 @@ static int compare_env_keys(const erts_osenv_data_t a, const erts_osenv_data_t b
#include "erl_rbtree.h"
static int compare_env_keys(const erts_osenv_data_t a, const erts_osenv_data_t b) {
- int relation = sys_memcmp(a.data, b.data, MIN(a.length, b.length));
+ int relation;
+
+#ifdef __WIN32__
+ /* Environment variables are case-insensitive on Windows. */
+ relation = _wcsnicmp((const WCHAR*)a.data, (const WCHAR*)b.data,
+ MIN(a.length, b.length) / sizeof(WCHAR));
+#else
+ relation = sys_memcmp(a.data, b.data, MIN(a.length, b.length));
+#endif
if(relation != 0) {
return relation;
diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c
index ced8a4a2a7..b4d1575ee5 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2006-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -141,12 +141,26 @@ typedef struct {
size_t sz;
fd_set* ptr;
}ERTS_fd_set;
-# define ERTS_FD_CLR(fd, fds) FD_CLR((fd), (fds)->ptr)
-# define ERTS_FD_SET(fd, fds) FD_SET((fd), (fds)->ptr)
-# define ERTS_FD_ISSET(fd,fds) FD_ISSET((fd), (fds)->ptr)
+
# define ERTS_FD_ZERO(fds) memset((fds)->ptr, 0, (fds)->sz)
# define ERTS_FD_SIZE(n) ((((n)+NFDBITS-1)/NFDBITS)*sizeof(fd_mask))
+static ERTS_INLINE void ERTS_FD_CLR(int fd, ERTS_fd_set *fds)
+{
+ ASSERT(ERTS_FD_SIZE(fd+1) <= fds->sz);
+ FD_CLR(fd, fds->ptr);
+}
+static ERTS_INLINE void ERTS_FD_SET(int fd, ERTS_fd_set *fds)
+{
+ ASSERT(ERTS_FD_SIZE(fd+1) <= fds->sz);
+ FD_SET(fd, fds->ptr);
+}
+static ERTS_INLINE int ERTS_FD_ISSET(int fd, ERTS_fd_set *fds)
+{
+ ASSERT(ERTS_FD_SIZE(fd+1) <= fds->sz);
+ return FD_ISSET(fd, fds->ptr);
+}
+
static void ERTS_FD_COPY(ERTS_fd_set *src, ERTS_fd_set *dst)
{
if (dst->sz != src->sz) {
@@ -626,8 +640,15 @@ ensure_select_fds(int fd, ERTS_fd_set* in, ERTS_fd_set* out)
grow_select_fds(fd, out);
}
}
+static ERTS_INLINE int
+check_select_fds(int fd, ERTS_fd_set* in, ERTS_fd_set* out)
+{
+ ASSERT(in->sz == out->sz);
+ return (ERTS_FD_SIZE(fd+1) <= in->sz);
+}
#else
# define ensure_select_fds(fd, in, out) do {} while(0)
+# define check_select_fds(fd, in, out) (1)
#endif /* _DARWIN_UNLIMITED_SELECT */
#if !ERTS_POLL_USE_CONCURRENT_UPDATE
@@ -782,6 +803,23 @@ update_pollset(ErtsPollSet *ps, int fd, ErtsPollOp op, ErtsPollEvents events)
struct kevent evts[2];
struct timespec ts = {0, 0};
+ if (op == ERTS_POLL_OP_ADD) {
+ /* This is a hack to make the "noshell" option work; kqueue can poll
+ * these fds but will not report EV_EOF, so we return NVAL to use the
+ * fallback instead.
+ *
+ * This may be common to all pipes but we have no way to tell whether
+ * an fd is a pipe or not. */
+ switch (fd) {
+ case STDIN_FILENO:
+ case STDOUT_FILENO:
+ case STDERR_FILENO:
+ return ERTS_POLL_EV_NVAL;
+ default:
+ break;
+ }
+ }
+
#if defined(EV_DISPATCH) && !defined(__OpenBSD__)
/* If we have EV_DISPATCH we use it, unless we are on OpenBSD as the
behavior of EV_EOF seems to be edge triggered there and we need it
@@ -1085,8 +1123,10 @@ static int update_pollset(ErtsPollSet *ps, ErtsPollResFd pr[], int fd)
res++;
}
- ERTS_FD_CLR(fd, &ps->input_fds);
- ERTS_FD_CLR(fd, &ps->output_fds);
+ if (check_select_fds(fd, &ps->input_fds, &ps->output_fds)) {
+ ERTS_FD_CLR(fd, &ps->input_fds);
+ ERTS_FD_CLR(fd, &ps->output_fds);
+ }
if (ps->fds_status[fd].used_events) {
erts_atomic_dec_nob(&ps->no_of_user_fds);
diff --git a/erts/emulator/sys/common/erl_poll.h b/erts/emulator/sys/common/erl_poll.h
index e9a667cac1..e1cea7eb8b 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2006-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/sys/common/erl_poll_api.h b/erts/emulator/sys/common/erl_poll_api.h
index 04beb37d1c..1170a549b9 100644
--- a/erts/emulator/sys/common/erl_poll_api.h
+++ b/erts/emulator/sys/common/erl_poll_api.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2006-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/sys/common/erl_sys_common_misc.c b/erts/emulator/sys/common/erl_sys_common_misc.c
index 41a6fcb7e1..2541ab5d31 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2006-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/sys/unix/erl_child_setup.c b/erts/emulator/sys/unix/erl_child_setup.c
index 10601529a4..221ee2a69d 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2002-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/sys/unix/erl_unix_sys.h b/erts/emulator/sys/unix/erl_unix_sys.h
index 10adf80875..ae7a3ea23e 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1997-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -292,6 +292,8 @@ erts_sys_perf_counter()
/*
* Functions for measuring CPU time
+ *
+ * Note that gethrvtime is time per process and clock_gettime is per thread.
*/
#if (defined(HAVE_GETHRVTIME) || defined(HAVE_CLOCK_GETTIME_CPU_TIME))
@@ -300,15 +302,15 @@ typedef struct timespec SysTimespec;
#if defined(HAVE_GETHRVTIME)
#define sys_gethrvtime() gethrvtime()
-#define sys_get_proc_cputime(t,tp) (t) = sys_gethrvtime(), \
- (tp).tv_sec = (time_t)((t)/1000000000LL), \
- (tp).tv_nsec = (long)((t)%1000000000LL)
+#define sys_get_cputime(t,tp) (t) = sys_gethrvtime(), \
+ (tp).tv_sec = (time_t)((t)/1000000000LL), \
+ (tp).tv_nsec = (long)((t)%1000000000LL)
int sys_start_hrvtime(void);
int sys_stop_hrvtime(void);
#elif defined(HAVE_CLOCK_GETTIME_CPU_TIME)
#define sys_clock_gettime(cid,tp) clock_gettime((cid),&(tp))
-#define sys_get_proc_cputime(t,tp) sys_clock_gettime(CLOCK_PROCESS_CPUTIME_ID,(tp))
+#define sys_get_cputime(t,tp) sys_clock_gettime(CLOCK_THREAD_CPUTIME_ID,(tp))
#endif
#endif
diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c
index 189ca083d7..36579ffdb4 100644
--- a/erts/emulator/sys/unix/sys.c
+++ b/erts/emulator/sys/unix/sys.c
@@ -452,9 +452,9 @@ prepare_crash_dump(int secs)
envsz = sizeof(env);
i = erts_sys_explicit_8bit_getenv("ERL_CRASH_DUMP_NICE", env, &envsz);
- if (i >= 0) {
+ if (i != 0) {
int nice_val;
- nice_val = i != 1 ? 0 : atoi(env);
+ nice_val = (i != 1) ? 0 : atoi(env);
if (nice_val > 39) {
nice_val = 39;
}
diff --git a/erts/emulator/sys/unix/sys_drivers.c b/erts/emulator/sys/unix/sys_drivers.c
index 117855acf0..816bdea9c5 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -685,7 +685,7 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
/* we send the request to do the fork */
if ((res = writev(ofd[1], io_vector, iov_len > MAXIOV ? MAXIOV : iov_len)) < 0) {
- if (errno == ERRNO_BLOCK) {
+ if (errno == ERRNO_BLOCK || errno == EINTR) {
res = 0;
} else {
int err = errno;
@@ -1000,7 +1000,7 @@ static void clear_fd_data(ErtsSysFdData *fdd)
static void nbio_stop_fd(ErlDrvPort prt, ErtsSysFdData *fdd)
{
- driver_select(prt, abs(fdd->fd), DO_READ|DO_WRITE, 0);
+ driver_select(prt, abs(fdd->fd), ERL_DRV_USE_NO_CALLBACK|DO_READ|DO_WRITE, 0);
clear_fd_data(fdd);
SET_BLOCKING(abs(fdd->fd));
@@ -1257,6 +1257,8 @@ static int port_inp_failure(ErtsSysDriverData *dd, int res)
}
driver_failure_eof(dd->port_num);
} else if (dd->ifd) {
+ if (dd->alive == -1)
+ errno = dd->status;
erl_drv_init_ack(dd->port_num, ERL_DRV_ERROR_ERRNO);
} else {
driver_failure_posix(dd->port_num, err);
@@ -1287,10 +1289,10 @@ static void ready_input(ErlDrvData e, ErlDrvEvent ready_fd)
int res;
if((res = read(ready_fd, &proto, sizeof(proto))) <= 0) {
+ if (res < 0 && (errno == ERRNO_BLOCK || errno == EINTR))
+ return;
/* hmm, child setup seems to have closed the pipe too early...
we close the port as there is not much else we can do */
- if (res < 0 && errno == ERRNO_BLOCK)
- return;
driver_select(port_num, ready_fd, ERL_DRV_READ, 0);
if (res == 0)
errno = EPIPE;
@@ -1424,7 +1426,7 @@ static void ready_input(ErlDrvData e, ErlDrvEvent ready_fd)
continue;
}
else { /* The last message we got was split */
- char *buf = erts_alloc_fnf(ERTS_ALC_T_FD_ENTRY_BUF, h);
+ char *buf = erts_alloc_fnf(ERTS_ALC_T_FD_ENTRY_BUF, h);
if (!buf) {
errno = ENOMEM;
port_inp_failure(dd, -1);
@@ -1670,15 +1672,37 @@ static void forker_stop(ErlDrvData e)
the port has been closed by the user. */
}
+static ErlDrvSizeT forker_deq(ErlDrvPort port_num, ErtsSysForkerProto *proto)
+{
+ close(proto->u.start.fds[0]);
+ close(proto->u.start.fds[1]);
+ if (proto->u.start.fds[1] != proto->u.start.fds[2])
+ close(proto->u.start.fds[2]);
+
+ return driver_deq(port_num, sizeof(*proto));
+}
+
+static void forker_sigchld(Eterm port_id, int error)
+{
+ ErtsSysForkerProto *proto = erts_alloc(ERTS_ALC_T_DRV_CTRL_DATA, sizeof(*proto));
+ proto->action = ErtsSysForkerProtoAction_SigChld;
+ proto->u.sigchld.error_number = error;
+ proto->u.sigchld.port_id = port_id;
+
+ /* ideally this would be a port_command call, but as command is
+ already used by the spawn_driver, we use control instead.
+ Note that when using erl_drv_port_control it is an asynchronous
+ control. */
+ erl_drv_port_control(port_id, 'S', (char*)proto, sizeof(*proto));
+}
+
static void forker_ready_input(ErlDrvData e, ErlDrvEvent fd)
{
int res;
- ErtsSysForkerProto *proto;
+ ErtsSysForkerProto proto;
- proto = erts_alloc(ERTS_ALC_T_DRV_CTRL_DATA, sizeof(*proto));
-
- if ((res = read(fd, proto, sizeof(*proto))) < 0) {
- if (errno == ERRNO_BLOCK)
+ if ((res = read(fd, &proto, sizeof(proto))) < 0) {
+ if (errno == ERRNO_BLOCK || errno == EINTR)
return;
erts_exit(ERTS_DUMP_EXIT, "Failed to read from erl_child_setup: %d\n", errno);
}
@@ -1686,10 +1710,10 @@ static void forker_ready_input(ErlDrvData e, ErlDrvEvent fd)
if (res == 0)
erts_exit(ERTS_DUMP_EXIT, "erl_child_setup closed\n");
- ASSERT(res == sizeof(*proto));
+ ASSERT(res == sizeof(proto));
#ifdef FORKER_PROTO_START_ACK
- if (proto->action == ErtsSysForkerProtoAction_StartAck) {
+ if (proto.action == ErtsSysForkerProtoAction_StartAck) {
/* Ideally we would like to not have to ack each Start
command being sent over the uds, but it would seem
that some operating systems (only observed on FreeBSD)
@@ -1699,28 +1723,15 @@ static void forker_ready_input(ErlDrvData e, ErlDrvEvent fd)
ErlDrvPort port_num = (ErlDrvPort)e;
int vlen;
SysIOVec *iov = driver_peekq(port_num, &vlen);
- ErtsSysForkerProto *proto = (ErtsSysForkerProto *)iov[0].iov_base;
-
- close(proto->u.start.fds[0]);
- close(proto->u.start.fds[1]);
- if (proto->u.start.fds[1] != proto->u.start.fds[2])
- close(proto->u.start.fds[2]);
+ ErtsSysForkerProto *qproto = (ErtsSysForkerProto *)iov[0].iov_base;
- driver_deq(port_num, sizeof(*proto));
-
- if (driver_sizeq(port_num) > 0)
+ if (forker_deq(port_num, qproto))
driver_select(port_num, forker_fd, ERL_DRV_WRITE|ERL_DRV_USE, 1);
} else
#endif
{
- ASSERT(proto->action == ErtsSysForkerProtoAction_SigChld);
-
- /* ideally this would be a port_command call, but as command is
- already used by the spawn_driver, we use control instead.
- Note that when using erl_drv_port_control it is an asynchronous
- control. */
- erl_drv_port_control(proto->u.sigchld.port_id, 'S',
- (char*)proto, sizeof(*proto));
+ ASSERT(proto.action == ErtsSysForkerProtoAction_SigChld);
+ forker_sigchld(proto.u.sigchld.port_id, proto.u.sigchld.error_number);
}
}
@@ -1730,7 +1741,8 @@ static void forker_ready_output(ErlDrvData e, ErlDrvEvent fd)
ErlDrvPort port_num = (ErlDrvPort)e;
#ifndef FORKER_PROTO_START_ACK
- while (driver_sizeq(port_num) > 0) {
+ int loops = 10;
+ while (driver_sizeq(port_num) > 0 && --loops) {
#endif
int vlen;
SysIOVec *iov = driver_peekq(port_num, &vlen);
@@ -1738,20 +1750,24 @@ static void forker_ready_output(ErlDrvData e, ErlDrvEvent fd)
ASSERT(iov[0].iov_len >= (sizeof(*proto)));
if (sys_uds_write(forker_fd, (char*)proto, sizeof(*proto),
proto->u.start.fds, 3, 0) < 0) {
- if (errno == ERRNO_BLOCK)
+ if (errno == ERRNO_BLOCK || errno == EINTR) {
return;
- erts_exit(ERTS_DUMP_EXIT, "Failed to write to erl_child_setup: %d\n", errno);
+ } else if (errno == EMFILE) {
+ forker_sigchld(proto->u.start.port_id, errno);
+ if (forker_deq(port_num, proto) == 0)
+ driver_select(port_num, forker_fd, ERL_DRV_WRITE, 0);
+ return;
+ } else {
+ erts_exit(ERTS_DUMP_EXIT, "Failed to write to erl_child_setup: %d\n", errno);
+ }
}
#ifndef FORKER_PROTO_START_ACK
- close(proto->u.start.fds[0]);
- close(proto->u.start.fds[1]);
- if (proto->u.start.fds[1] != proto->u.start.fds[2])
- close(proto->u.start.fds[2]);
- driver_deq(port_num, sizeof(*proto));
+ if (forker_deq(port_num, proto) == 0)
+ driver_select(port_num, forker_fd, ERL_DRV_WRITE, 0);
}
-#endif
-
+#else
driver_select(port_num, forker_fd, ERL_DRV_WRITE, 0);
+#endif
}
static ErlDrvSSizeT forker_control(ErlDrvData e, unsigned int cmd, char *buf,
@@ -1777,20 +1793,21 @@ static ErlDrvSSizeT forker_control(ErlDrvData e, unsigned int cmd, char *buf,
if ((res = sys_uds_write(forker_fd, (char*)proto, sizeof(*proto),
proto->u.start.fds, 3, 0)) < 0) {
- if (errno == ERRNO_BLOCK) {
+ if (errno == ERRNO_BLOCK || errno == EINTR) {
driver_select(port_num, forker_fd, ERL_DRV_WRITE|ERL_DRV_USE, 1);
return 0;
+ } else if (errno == EMFILE) {
+ forker_sigchld(proto->u.start.port_id, errno);
+ forker_deq(port_num, proto);
+ return 0;
+ } else {
+ erts_exit(ERTS_DUMP_EXIT, "Failed to write to erl_child_setup: %d\n", errno);
}
- erts_exit(ERTS_DUMP_EXIT, "Failed to write to erl_child_setup: %d\n", errno);
}
#ifndef FORKER_PROTO_START_ACK
ASSERT(res == sizeof(*proto));
- close(proto->u.start.fds[0]);
- close(proto->u.start.fds[1]);
- if (proto->u.start.fds[1] != proto->u.start.fds[2])
- close(proto->u.start.fds[2]);
- driver_deq(port_num, sizeof(*proto));
+ forker_deq(port_num, proto);
#endif
return 0;
diff --git a/erts/emulator/sys/unix/sys_float.c b/erts/emulator/sys/unix/sys_float.c
index a82c15bd32..832074f679 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/sys/unix/sys_time.c b/erts/emulator/sys/unix/sys_time.c
index ef05380d17..8ba575b7b6 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2005-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/sys/unix/sys_uds.c b/erts/emulator/sys/unix/sys_uds.c
index 278c6b6ba1..39a4866065 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2002-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -132,7 +132,7 @@ sys_uds_writev(int fd, struct iovec *iov, size_t iov_len,
struct msghdr msg;
struct cmsghdr *cmsg = NULL;
- int res, i;
+ int res, i, error;
/* initialize socket message */
memset(&msg, 0, sizeof(struct msghdr));
@@ -173,11 +173,22 @@ sys_uds_writev(int fd, struct iovec *iov, size_t iov_len,
res = sendmsg(fd, &msg, flags);
+#ifdef ETOOMANYREFS
+ /* Linux may give ETOOMANYREFS when there are too many fds in transit.
+ We map this to EMFILE as bsd and other use this error code and we want
+ the behaviour to be the same on all OSs */
+ if (errno == ETOOMANYREFS)
+ errno = EMFILE;
+#endif
+ error = errno;
+
if (iov_len > MAXIOV)
free(iov[0].iov_base);
free(msg.msg_control);
+ errno = error;
+
return res;
}
diff --git a/erts/emulator/sys/unix/sys_uds.h b/erts/emulator/sys/unix/sys_uds.h
index 26c91d6a00..49a4b39250 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2002-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/sys/win32/erl_poll.c b/erts/emulator/sys/win32/erl_poll.c
index fd4c745c3b..fcf5a0d533 100644
--- a/erts/emulator/sys/win32/erl_poll.c
+++ b/erts/emulator/sys/win32/erl_poll.c
@@ -362,11 +362,11 @@ is_io_ready(ErtsPollSet *ps)
}
static ERTS_INLINE void
-woke_up(ErtsPollSet *ps)
+woke_up(ErtsPollSet *ps, int waketype)
{
if (erts_atomic32_read_nob(&ps->wakeup_state) == ERTS_POLL_NOT_WOKEN)
erts_atomic32_cmpxchg_nob(&ps->wakeup_state,
- ERTS_POLL_WOKEN_TIMEDOUT,
+ waketype,
ERTS_POLL_NOT_WOKEN);
#ifdef DEBUG
{
@@ -960,12 +960,12 @@ static int cancel_driver_select(ErtsPollSet *ps, HANDLE event)
void erts_poll_interrupt(ErtsPollSet *ps, int set /* bool */)
{
- HARDTRACEF(("In erts_poll_interrupt(%d)",set));
+ HARDTRACEF(("In erts_poll_interrupt(%p, %d)",ps,set));
if (!set)
reset_interrupt(ps);
else
set_interrupt(ps);
- HARDTRACEF(("Out erts_poll_interrupt(%d)",set));
+ HARDTRACEF(("Out erts_poll_interrupt(%p, %d)",ps,set));
}
@@ -1051,19 +1051,20 @@ int erts_poll_wait(ErtsPollSet *ps,
if (!erts_atomic32_read_nob(&break_waiter_state)) {
HANDLE harr[2] = {ps->event_io_ready, break_happened_event};
- int num_h = 2;
+ int num_h = 2, handle;
ERTS_MSACC_PUSH_STATE();
HARDDEBUGF(("Start waiting %d [%d]",num_h, (int) timeout));
ERTS_POLLSET_UNLOCK(ps);
erts_thr_progress_prepare_wait(NULL);
ERTS_MSACC_SET_STATE_CACHED(ERTS_MSACC_STATE_SLEEP);
- WaitForMultipleObjects(num_h, harr, FALSE, timeout);
+ handle = WaitForMultipleObjects(num_h, harr, FALSE, timeout);
erts_thr_progress_finalize_wait(NULL);
ERTS_MSACC_POP_STATE();
ERTS_POLLSET_LOCK(ps);
HARDDEBUGF(("Stop waiting %d [%d]",num_h, (int) timeout));
- woke_up(ps);
+ if (handle == WAIT_OBJECT_0)
+ woke_up(ps, ERTS_POLL_WOKEN_TIMEDOUT);
}
ERTS_UNSET_BREAK_REQUESTED;
@@ -1075,7 +1076,10 @@ int erts_poll_wait(ErtsPollSet *ps,
erts_mtx_unlock(&break_waiter_lock);
switch (break_state) {
case BREAK_WAITER_GOT_BREAK:
+ woke_up(ps, ERTS_POLL_WOKEN_INTR);
ERTS_SET_BREAK_REQUESTED;
+ /* Wake aux thread to get handle break */
+ erts_aux_thread_poke();
break;
case BREAK_WAITER_GOT_HALT:
erts_exit(0,"");
diff --git a/erts/emulator/sys/win32/erl_win32_sys_ddll.c b/erts/emulator/sys/win32/erl_win32_sys_ddll.c
index fc2179328f..7fe1f5cc78 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2006-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/sys/win32/erl_win_dyn_driver.h b/erts/emulator/sys/win32/erl_win_dyn_driver.h
index 0d1a6d4c87..c683e8cf49 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2003-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/sys/win32/erl_win_sys.h b/erts/emulator/sys/win32/erl_win_sys.h
index 1f53452d17..b00ba287e2 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1997-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/sys/win32/sys_interrupt.c b/erts/emulator/sys/win32/sys_interrupt.c
index 02aa50500f..cee269eed4 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1997-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/sys/win32/sys_time.c b/erts/emulator/sys/win32/sys_time.c
index 25c2ad385c..a1dd14f871 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1997-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/alloc_SUITE.erl b/erts/emulator/test/alloc_SUITE.erl
index 88ff2a7a92..4e0243c1cd 100644
--- a/erts/emulator/test/alloc_SUITE.erl
+++ b/erts/emulator/test/alloc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -71,7 +71,8 @@ migration(Cfg) ->
%% Disable driver_alloc to avoid recursive alloc_util calls
%% through enif_mutex_create() in my_creating_mbc().
drv_case(Cfg, concurrent, "+MZe true +MRe false"),
- drv_case(Cfg, concurrent, "+MZe true +MRe false +MZas ageffcbf").
+ drv_case(Cfg, concurrent, "+MZe true +MRe false +MZas ageffcbf"),
+ drv_case(Cfg, concurrent, "+MZe true +MRe false +MZas chaosff").
erts_mmap(Config) when is_list(Config) ->
case {os:type(), mmsc_flags()} of
diff --git a/erts/emulator/test/alloc_SUITE_data/migration.c b/erts/emulator/test/alloc_SUITE_data/migration.c
index 1d974225fc..78f3a633e8 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2014-2018. 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 bdf8f6c34e..d3b3b96b14 100644
--- a/erts/emulator/test/beam_SUITE.erl
+++ b/erts/emulator/test/beam_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/beam_literals_SUITE.erl b/erts/emulator/test/beam_literals_SUITE.erl
index b447ca0210..82a5e2b172 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-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl
index 32bfcd5520..9e7bcd5255 100644
--- a/erts/emulator/test/bif_SUITE.erl
+++ b/erts/emulator/test/bif_SUITE.erl
@@ -36,7 +36,8 @@
error_stacktrace_during_call_trace/1,
group_leader_prio/1, group_leader_prio_dirty/1,
is_process_alive/1,
- process_info_blast/1]).
+ process_info_blast/1,
+ os_env_case_sensitivity/1]).
suite() ->
[{ct_hooks,[ts_install_cth]},
@@ -51,7 +52,7 @@ all() ->
erl_crash_dump_bytes, min_max, erlang_halt, is_builtin,
error_stacktrace, error_stacktrace_during_call_trace,
group_leader_prio, group_leader_prio_dirty,
- is_process_alive, process_info_blast].
+ is_process_alive, process_info_blast, os_env_case_sensitivity].
%% Uses erlang:display to test that erts_printf does not do deep recursion
display(Config) when is_list(Config) ->
@@ -443,6 +444,17 @@ os_env_long(Min, Max, Value) ->
true = os:unsetenv(EnvVar),
os_env_long(Min+1, Max, Value).
+os_env_case_sensitivity(Config) when is_list(Config) ->
+ %% The keys in os:getenv/putenv must be case-insensitive on Windows, and
+ %% case-sensitive elsewhere.
+ true = os:putenv("os_env_gurka", "gaffel"),
+ Expected = case os:type() of
+ {win32, _} -> "gaffel";
+ _ -> false
+ end,
+ Expected = os:getenv("OS_ENV_GURKA"),
+ ok.
+
%% Test that string:to_integer does not Halloc in wrong order.
otp_7526(Config) when is_list(Config) ->
ok = test_7526(256).
diff --git a/erts/emulator/test/big_SUITE.erl b/erts/emulator/test/big_SUITE.erl
index 5939d024ae..0a42b09903 100644
--- a/erts/emulator/test/big_SUITE.erl
+++ b/erts/emulator/test/big_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/binary_SUITE.erl b/erts/emulator/test/binary_SUITE.erl
index a3c3daac15..23c675733c 100644
--- a/erts/emulator/test/binary_SUITE.erl
+++ b/erts/emulator/test/binary_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/call_trace_SUITE.erl b/erts/emulator/test/call_trace_SUITE.erl
index d19f7f81ad..742592f88e 100644
--- a/erts/emulator/test/call_trace_SUITE.erl
+++ b/erts/emulator/test/call_trace_SUITE.erl
@@ -1395,7 +1395,7 @@ seq(M, N, R) when M =< N ->
seq(M, N-1, [N|R]);
seq(_, _, R) -> R.
-%% lists:reverse can not be called since it is traced
+%% lists:reverse cannot be called since it is traced
reverse(L) ->
reverse(L, []).
%%
diff --git a/erts/emulator/test/code_SUITE.erl b/erts/emulator/test/code_SUITE.erl
index 661a2ee6c9..7e690fd870 100644
--- a/erts/emulator/test/code_SUITE.erl
+++ b/erts/emulator/test/code_SUITE.erl
@@ -332,6 +332,7 @@ constant_pools(Config) when is_list(Config) ->
A = literals:a(),
B = literals:b(),
C = literals:huge_bignum(),
+ D = literals:funs(),
process_flag(trap_exit, true),
Self = self(),
@@ -345,7 +346,7 @@ constant_pools(Config) when is_list(Config) ->
true = erlang:purge_module(literals),
NoOldHeap ! done,
receive
- {'EXIT',NoOldHeap,{A,B,C}} ->
+ {'EXIT',NoOldHeap,{A,B,C,D}} ->
ok;
Other ->
ct:fail({unexpected,Other})
@@ -362,7 +363,7 @@ constant_pools(Config) when is_list(Config) ->
erlang:purge_module(literals),
OldHeap ! done,
receive
- {'EXIT',OldHeap,{A,B,C,[1,2,3|_]=Seq}} when length(Seq) =:= 16 ->
+ {'EXIT',OldHeap,{A,B,C,D,[1,2,3|_]=Seq}} when length(Seq) =:= 16 ->
ok
end,
@@ -390,7 +391,7 @@ constant_pools(Config) when is_list(Config) ->
{'DOWN', Mon, process, Hib, Reason} ->
{undef, [{no_module,
no_function,
- [{A,B,C,[1,2,3|_]=Seq}], _}]} = Reason,
+ [{A,B,C,D,[1,2,3|_]=Seq}], _}]} = Reason,
16 = length(Seq)
end,
HeapSz = TotHeapSz, %% Ensure restored to hibernated state...
@@ -400,7 +401,9 @@ constant_pools(Config) when is_list(Config) ->
no_old_heap(Parent) ->
A = literals:a(),
B = literals:b(),
- Res = {A,B,literals:huge_bignum()},
+ C = literals:huge_bignum(),
+ D = literals:funs(),
+ Res = {A,B,C,D},
Parent ! go,
receive
done ->
@@ -410,7 +413,9 @@ no_old_heap(Parent) ->
old_heap(Parent) ->
A = literals:a(),
B = literals:b(),
- Res = {A,B,literals:huge_bignum(),lists:seq(1, 16)},
+ C = literals:huge_bignum(),
+ D = literals:funs(),
+ Res = {A,B,C,D,lists:seq(1, 16)},
create_old_heap(),
Parent ! go,
receive
@@ -421,7 +426,9 @@ old_heap(Parent) ->
hibernated(Parent) ->
A = literals:a(),
B = literals:b(),
- Res = {A,B,literals:huge_bignum(),lists:seq(1, 16)},
+ C = literals:huge_bignum(),
+ D = literals:funs(),
+ Res = {A,B,C,D,lists:seq(1, 16)},
Parent ! go,
erlang:hibernate(no_module, no_function, [Res]).
@@ -755,7 +762,8 @@ t_copy_literals_frags(Config) when is_list(Config) ->
0, 1, 2, 3, 4, 5, 6, 7,
8, 9,10,11,12,13,14,15,
0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9,10,11,12,13,14,15>>}]),
+ 8, 9,10,11,12,13,14,15>>},
+ {f, fun ?MODULE:all/0}]),
{module, ?mod} = erlang:load_module(?mod, Bin),
N = 6000,
@@ -796,6 +804,7 @@ literal_receiver() ->
C = ?mod:c(),
D = ?mod:d(),
E = ?mod:e(),
+ F = ?mod:f(),
literal_receiver();
{Pid, sender_confirm} ->
io:format("sender confirm ~w~n", [Pid]),
@@ -811,7 +820,8 @@ literal_sender(N, Recv) ->
?mod:b(),
?mod:c(),
?mod:d(),
- ?mod:e()]},
+ ?mod:e(),
+ ?mod:f()]},
literal_sender(N - 1, Recv).
literal_switcher() ->
@@ -957,7 +967,7 @@ erl_544(Config) when is_list(Config) ->
StackFun = fun(_, _, _) -> false end,
FormatFun = fun (Term, _) -> io_lib:format("~tp", [Term]) end,
Formated =
- lib:format_stacktrace(1, Stack, StackFun, FormatFun),
+ erl_error:format_stacktrace(1, Stack, StackFun, FormatFun),
true = is_list(Formated),
ok
after
diff --git a/erts/emulator/test/code_SUITE_data/literals.erl b/erts/emulator/test/code_SUITE_data/literals.erl
index 7c3b0ebe73..13c8b412b0 100644
--- a/erts/emulator/test/code_SUITE_data/literals.erl
+++ b/erts/emulator/test/code_SUITE_data/literals.erl
@@ -19,7 +19,8 @@
%%
-module(literals).
--export([a/0,b/0,huge_bignum/0,binary/0,unused_binaries/0,bits/0]).
+-export([a/0,b/0,huge_bignum/0,funs/0,
+ binary/0,unused_binaries/0,bits/0]).
-export([msg1/0,msg2/0,msg3/0,msg4/0,msg5/0]).
a() ->
@@ -108,3 +109,8 @@ msg2() -> {"hello","world"}.
msg3() -> <<"halloj">>.
msg4() -> #{ 1=> "hello", b => "world"}.
msg5() -> {1,2,3,4,5,6}.
+
+funs() ->
+ %% Literal funs (in a non-literal list).
+ [fun ?MODULE:a/0,
+ fun() -> ok end]. %No environment.
diff --git a/erts/emulator/test/decode_packet_SUITE.erl b/erts/emulator/test/decode_packet_SUITE.erl
index 0ccdbd7ee8..ef13b515fb 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-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/dgawd_handler.erl b/erts/emulator/test/dgawd_handler.erl
index 29b9d6ac7b..b66b5a073f 100644
--- a/erts/emulator/test/dgawd_handler.erl
+++ b/erts/emulator/test/dgawd_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl
index e40d346e10..885c66331c 100644
--- a/erts/emulator/test/distribution_SUITE.erl
+++ b/erts/emulator/test/distribution_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -73,7 +73,7 @@
dist_evil_parallel_receiver/0]).
%% epmd_module exports
--export([start_link/0, register_node/2, register_node/3, port_please/2]).
+-export([start_link/0, register_node/2, register_node/3, port_please/2, address_please/3]).
suite() ->
[{ct_hooks,[ts_install_cth]},
@@ -797,7 +797,7 @@ show_term(Term) ->
%% Tests behaviour after net_kernel:stop (OTP-2586).
stop_dist(Config) when is_list(Config) ->
- Str = os:cmd(atom_to_list(lib:progname())
+ Str = os:cmd(ct:get_progname()
++ " -noshell -pa "
++ proplists:get_value(data_dir, Config)
++ " -s run"),
@@ -974,9 +974,9 @@ dist_auto_connect_start(Name, Value) when is_list(Name), is_atom(Value) ->
ModuleDir = filename:dirname(code:which(?MODULE)),
ValueStr = atom_to_list(Value),
Cookie = atom_to_list(erlang:get_cookie()),
- Cmd = lists:concat(
+ Cmd = lists:append(
[%"xterm -e ",
- atom_to_list(lib:progname()),
+ ct:get_progname(),
% " -noinput ",
" -detached ",
long_or_short(), " ", Name,
@@ -2086,6 +2086,11 @@ port_please(_Name, _Ip) ->
{port, Port, Version}
end.
+address_please(_Name, _Address, _AddressFamily) ->
+ %% Use localhost.
+ IP = {127,0,0,1},
+ {ok, IP}.
+
%%% Utilities
timestamp() ->
diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl
index 40c7cc11e1..9ffb484eb4 100644
--- a/erts/emulator/test/driver_SUITE.erl
+++ b/erts/emulator/test/driver_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -81,6 +81,7 @@
thr_msg_blast/1,
consume_timeslice/1,
env/1,
+ poll_pipe/1,
z_test/1]).
-export([bin_prefix/2]).
@@ -168,6 +169,7 @@ all() -> %% Keep a_test first and z_test last...
thr_msg_blast,
consume_timeslice,
env,
+ poll_pipe,
z_test].
groups() ->
@@ -2643,24 +2645,7 @@ wait_deallocations() ->
driver_alloc_size() ->
wait_deallocations(),
- case erlang:system_info({allocator_sizes, driver_alloc}) of
- false ->
- undefined;
- MemInfo ->
- CS = lists:foldl(
- fun ({instance, _, L}, Acc) ->
- {value,{_,MBCS}} = lists:keysearch(mbcs, 1, L),
- {value,{_,SBCS}} = lists:keysearch(sbcs, 1, L),
- [MBCS,SBCS | Acc]
- end,
- [],
- MemInfo),
- lists:foldl(
- fun(L, Sz0) ->
- {value,{_,Sz,_,_}} = lists:keysearch(blocks_size, 1, L),
- Sz0+Sz
- end, 0, CS)
- end.
+ erts_debug:alloc_blocks_size(driver_alloc).
rpc(Config, Fun) ->
case proplists:get_value(node, Config) of
@@ -2693,3 +2678,25 @@ rpc(Config, Fun) ->
ct:fail(Other)
end
end.
+
+poll_pipe(Config) when is_list(Config) ->
+ %% ERL-647; we wouldn't see any events on EOF when polling a pipe using
+ %% kqueue(2).
+ case os:type() of
+ {unix, _} ->
+ Command = "erl -noshell -eval "
+ "'\"DATA\n\" = io:get_line(\"\"),"
+ "eof = io:get_line(\"\"),"
+ "halt()' <<< 'DATA'",
+ Ref = make_ref(),
+ Self = self(),
+ Pid = spawn(fun() -> os:cmd(Command), Self ! Ref end),
+ receive
+ Ref -> ok
+ after 5000 ->
+ exit(Pid, kill),
+ ct:fail("Stuck reading from stdin.")
+ end;
+ _ ->
+ {skipped, "Unix-only test"}
+ end.
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 fa58e9d5ec..9e96923e17 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2007-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/dump_SUITE.erl b/erts/emulator/test/dump_SUITE.erl
index 8d18d46d92..d0237b78cc 100644
--- a/erts/emulator/test/dump_SUITE.erl
+++ b/erts/emulator/test/dump_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/efile_SUITE.erl b/erts/emulator/test/efile_SUITE.erl
index 821381bf0d..7dcf302742 100644
--- a/erts/emulator/test/efile_SUITE.erl
+++ b/erts/emulator/test/efile_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/erts_debug_SUITE.erl b/erts/emulator/test/erts_debug_SUITE.erl
index 6aa7a445b5..f39dbedd8f 100644
--- a/erts/emulator/test/erts_debug_SUITE.erl
+++ b/erts/emulator/test/erts_debug_SUITE.erl
@@ -22,8 +22,10 @@
-include_lib("common_test/include/ct.hrl").
-export([all/0, suite/0,
- test_size/1,flat_size_big/1,df/1,term_type/1,
- instructions/1, stack_check/1]).
+ test_size/1,flat_size_big/1,df/1,term_type/1,
+ instructions/1, stack_check/1, alloc_blocks_size/1]).
+
+-export([do_alloc_blocks_size/0]).
suite() ->
[{ct_hooks,[ts_install_cth]},
@@ -31,7 +33,7 @@ suite() ->
all() ->
[test_size, flat_size_big, df, instructions, term_type,
- stack_check].
+ stack_check, alloc_blocks_size].
test_size(Config) when is_list(Config) ->
ConsCell1 = id([a|b]),
@@ -210,5 +212,28 @@ instructions(Config) when is_list(Config) ->
_ = [list_to_atom(I) || I <- Is],
ok.
+alloc_blocks_size(Config) when is_list(Config) ->
+ F = fun(Args) ->
+ Node = start_slave(Args),
+ ok = rpc:call(Node, ?MODULE, do_alloc_blocks_size, []),
+ true = test_server:stop_node(Node)
+ end,
+ F("+Meamax"),
+ F("+Meamin"),
+ F(""),
+ ok.
+
+do_alloc_blocks_size() ->
+ _ = erts_debug:alloc_blocks_size(binary_alloc),
+ ok.
+
+start_slave(Args) ->
+ Name = ?MODULE_STRING ++ "_slave",
+ Pa = filename:dirname(code:which(?MODULE)),
+ {ok, Node} = test_server:start_node(list_to_atom(Name),
+ slave,
+ [{args, "-pa " ++ Pa ++ " " ++ Args}]),
+ Node.
+
id(I) ->
I.
diff --git a/erts/emulator/test/exception_SUITE.erl b/erts/emulator/test/exception_SUITE.erl
index 60d14ce841..aec66cb9a3 100644
--- a/erts/emulator/test/exception_SUITE.erl
+++ b/erts/emulator/test/exception_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/fun_SUITE.erl b/erts/emulator/test/fun_SUITE.erl
index 7d29ebec52..f8a879182e 100644
--- a/erts/emulator/test/fun_SUITE.erl
+++ b/erts/emulator/test/fun_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -576,7 +576,7 @@ refc_dist(Config) when is_list(Config) ->
process_flag(trap_exit, true),
Pid = spawn_link(Node, fun() -> receive
Fun when is_function(Fun) ->
- 2 = fun_refc(Fun),
+ 3 = fun_refc(Fun),
exit({normal,Fun}) end
end),
F = fun() -> 42 end,
@@ -598,7 +598,7 @@ refc_dist_send(Node, F) ->
Pid = spawn_link(Node, fun() -> receive
{To,Fun} when is_function(Fun) ->
wait_until(fun () ->
- 2 =:= fun_refc(Fun)
+ 3 =:= fun_refc(Fun)
end),
To ! Fun
end
@@ -626,7 +626,7 @@ refc_dist_reg_send(Node, F) ->
Me ! Ref,
receive
{Me,Fun} when is_function(Fun) ->
- 2 = fun_refc(Fun),
+ 3 = fun_refc(Fun),
Me ! Fun
end
end),
@@ -806,11 +806,13 @@ verify_not_undef(Fun, Tag) ->
ct:fail("tag ~w not defined in fun_info", [Tag]);
{Tag,_} -> ok
end.
-
+
id(X) ->
X.
spawn_call(Node, AFun) ->
+ Parent = self(),
+ Init = erlang:whereis(init),
Pid = spawn_link(Node,
fun() ->
receive
@@ -821,8 +823,10 @@ spawn_call(Node, AFun) ->
_ -> lists:seq(0, Arity-1)
end,
Res = apply(Fun, Args),
- {pid,Creator} = erlang:fun_info(Fun, pid),
- Creator ! {result,Res}
+ case erlang:fun_info(Fun, pid) of
+ {pid,Init} -> Parent ! {result,Res};
+ {pid,Creator} -> Creator ! {result,Res}
+ end
end
end),
Pid ! {AFun,AFun,AFun},
diff --git a/erts/emulator/test/iovec_SUITE.erl b/erts/emulator/test/iovec_SUITE.erl
index 963b7e2501..d17a28d47f 100644
--- a/erts/emulator/test/iovec_SUITE.erl
+++ b/erts/emulator/test/iovec_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/lcnt_SUITE.erl b/erts/emulator/test/lcnt_SUITE.erl
index dfffd662e2..87b97037d6 100644
--- a/erts/emulator/test/lcnt_SUITE.erl
+++ b/erts/emulator/test/lcnt_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/map_SUITE.erl b/erts/emulator/test/map_SUITE.erl
index f93c637650..d0a6763fe5 100644
--- a/erts/emulator/test/map_SUITE.erl
+++ b/erts/emulator/test/map_SUITE.erl
@@ -3080,8 +3080,19 @@ y_regs(Config) when is_list(Config) ->
true = is_map(Map2) andalso is_map(Map4),
+ gurka = y_regs_literal(0),
+ gaffel = y_regs_literal(1),
+
ok.
+y_regs_literal(Key) when is_integer(Key) ->
+ %% Forces the key to be placed in a Y register.
+ lists:seq(1, 2),
+ case is_map_key(Key, #{ 0 => 0 }) of
+ true -> gurka;
+ false -> gaffel
+ end.
+
y_regs_update(Map0, Val0) ->
Val1 = {t,Val0},
K1 = id({key,1}),
diff --git a/erts/emulator/test/match_spec_SUITE.erl b/erts/emulator/test/match_spec_SUITE.erl
index 4415d8d1b9..21de6b1002 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-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/module_info_SUITE.erl b/erts/emulator/test/module_info_SUITE.erl
index 46a3bba732..93f9de0c28 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-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/monitor_SUITE.erl b/erts/emulator/test/monitor_SUITE.erl
index c7250a9d26..27351dc5c1 100644
--- a/erts/emulator/test/monitor_SUITE.erl
+++ b/erts/emulator/test/monitor_SUITE.erl
@@ -314,7 +314,7 @@ local_remove_monitor(Config) when is_list(Config) ->
remote_remove_monitor(Config) when is_list(Config) ->
{ok, N} = test_server:start_node(demonitor_flush, slave, []),
- Gs = generate(fun () -> start_remove_monitor_group(node()) end,
+ Gs = generate(fun () -> start_remove_monitor_group(N) end,
?RM_MON_GROUPS),
{True, False} = lists:foldl(fun (G, {T, F}) ->
receive
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index df521311e3..a2f3489943 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -45,8 +45,9 @@
api_macros/1,
from_array/1, iolist_as_binary/1, resource/1, resource_binary/1,
resource_takeover/1,
- threading/1, send/1, send2/1, send3/1, send_threaded/1, neg/1,
- is_checks/1,
+ threading/1, send/1, send2/1, send3/1, send_threaded/1,
+ send_trace/1, send_seq_trace/1,
+ neg/1, is_checks/1,
get_length/1, make_atom/1, make_string/1, reverse_list_test/1,
otp_9828/1,
otp_9668/1, consume_timeslice/1, nif_schedule/1,
@@ -1789,6 +1790,59 @@ send(Config) when is_list(Config) ->
{ok,0} = send_list_seq(7, DeadPid),
ok.
+
+%% Test tracing of enif_send
+send_trace(Config) when is_list(Config) ->
+ ensure_lib_loaded(Config),
+
+ Papa = self(),
+ N = 1500,
+ List = lists:seq(1,N),
+
+ Tracer = spawn_link(fun F() -> receive get -> Papa ! receive_any(), F() end end),
+
+ erlang:trace(self(), true, [send,'receive',{tracer,Tracer}]),
+ {ok,1} = send_list_seq(N, self()),
+ List = receive_any(),
+ timeout = receive_any(0),
+ Tracer ! get,
+ {trace,Papa,send,List,Papa} = receive_any(),
+ Tracer ! get,
+ {trace,Papa,'receive',List} = receive_any().
+
+%% Test that seq_trace works with nif trace
+send_seq_trace(Config) when is_list(Config) ->
+ ensure_lib_loaded(Config),
+
+ Papa = self(),
+ N = 1500,
+ List = lists:seq(1,N),
+ Label = make_ref(),
+
+ Tracer = spawn_link(fun F() -> receive get -> Papa ! receive_any(), F() end end),
+
+ seq_trace:set_system_tracer(Tracer),
+ seq_trace:set_token(label,Label),
+ seq_trace:set_token(send,true),
+ seq_trace:set_token('receive',true),
+
+ {ok,1} = send_list_seq(N, self()),
+ List = receive_any(),
+ timeout = receive_any(0),
+ {ok,1} = send_list_seq(N, self()),
+ List = receive_any(),
+ timeout = receive_any(0),
+
+ Tracer ! get,
+ {seq_trace,Label,{send,{0,1},Papa,Papa,List}} = receive_any(),
+ Tracer ! get,
+ {seq_trace,Label,{'receive',{0,1},Papa,Papa,List}} = receive_any(),
+ Tracer ! get,
+ {seq_trace,Label,{send,{1,2},Papa,Papa,List}} = receive_any(),
+ Tracer ! get,
+ {seq_trace,Label,{'receive',{1,2},Papa,Papa,List}} = receive_any().
+
+
%% More NIF message sending
send2(Config) when is_list(Config) ->
ensure_lib_loaded(Config),
@@ -2663,16 +2717,23 @@ nif_term_to_binary(Config) ->
nif_binary_to_term(Config) ->
ensure_lib_loaded(Config),
- T = {#{ok => nok}, <<0:8096>>, lists:seq(1,100)},
+ BigMap = maps:from_list([{I,-I} || I <- lists:seq(1,100)]),
+ [nif_binary_to_term_do(T)
+ || T <- [{#{ok => nok}, <<0:8096>>, lists:seq(1,100)},
+ atom, 42, self(), BigMap]],
+ ok.
+
+nif_binary_to_term_do(T) ->
+ Dummy = [true|false],
Bin = term_to_binary(T),
Len = byte_size(Bin),
- {Len,T} = binary_to_term_nif(Bin, undefined, 0),
+ {Len,T,Dummy} = binary_to_term_nif(Bin, undefined, 0),
Len = binary_to_term_nif(Bin, self(), 0),
- T = receive M -> M after 1000 -> timeout end,
+ {T,Dummy} = receive M -> M after 1000 -> timeout end,
- {Len, T} = binary_to_term_nif(Bin, undefined, ?ERL_NIF_BIN2TERM_SAFE),
+ {Len,T,Dummy} = 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),
+ undefined, ?ERL_NIF_BIN2TERM_SAFE),
false = binary_to_term_nif(Bin, undefined, 1),
ok.
diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c
index a0aef60cf1..f2ce6dbe67 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-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2009-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -2405,7 +2405,7 @@ static ERL_NIF_TERM term_to_binary(ErlNifEnv* env, int argc, const ERL_NIF_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;
+ ERL_NIF_TERM term, dummy, ret_term;
ErlNifPid pid;
ErlNifEnv *msg_env = env;
unsigned int opts;
@@ -2418,6 +2418,9 @@ static ERL_NIF_TERM binary_to_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM
|| !enif_get_uint(env, argv[2], &opts))
return enif_make_badarg(env);
+ /* build dummy heap term first to provoke OTP-15080 */
+ dummy = enif_make_list_cell(msg_env, atom_true, atom_false);
+
ret = enif_binary_to_term(msg_env, bin.data, bin.size, &term,
(ErlNifBinaryToTerm)opts);
if (!ret)
@@ -2425,11 +2428,12 @@ static ERL_NIF_TERM binary_to_term(ErlNifEnv* env, int argc, const ERL_NIF_TERM
ret_term = enif_make_uint64(env, ret);
if (msg_env != env) {
- enif_send(env, &pid, msg_env, term);
+ enif_send(env, &pid, msg_env,
+ enif_make_tuple2(msg_env, term, dummy));
enif_free_env(msg_env);
return ret_term;
} else {
- return enif_make_tuple2(env, ret_term, term);
+ return enif_make_tuple3(env, ret_term, term, dummy);
}
}
diff --git a/erts/emulator/test/num_bif_SUITE.erl b/erts/emulator/test/num_bif_SUITE.erl
index 290bb61fc8..700734cd0b 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-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl
index 5b39d05df8..eb9b94a316 100644
--- a/erts/emulator/test/port_SUITE.erl
+++ b/erts/emulator/test/port_SUITE.erl
@@ -965,7 +965,7 @@ env_slave(File, Env) ->
env_slave(File, Env, Body) ->
file:write_file(File, term_to_binary(Body)),
- Program = atom_to_list(lib:progname()),
+ Program = ct:get_progname(),
Dir = filename:dirname(code:which(?MODULE)),
Cmd = Program ++ " -pz " ++ Dir ++
" -noinput -run " ++ ?MODULE_STRING ++ " env_slave_main " ++
@@ -1129,7 +1129,7 @@ try_bad_args(Args) ->
cd(Config) when is_list(Config) ->
ct:timetrap({minutes, 1}),
- Program = atom_to_list(lib:progname()),
+ Program = ct:get_progname(),
DataDir = proplists:get_value(data_dir, Config),
TestDir = filename:join(DataDir, "dir"),
Cmd = Program ++ " -pz " ++ DataDir ++
@@ -1191,7 +1191,7 @@ cd(Config) when is_list(Config) ->
%% be relative the new cwd and not the original
cd_relative(Config) ->
- Program = atom_to_list(lib:progname()),
+ Program = ct:get_progname(),
DataDir = proplists:get_value(data_dir, Config),
TestDir = filename:join(DataDir, "dir"),
@@ -1214,7 +1214,7 @@ cd_relative(Config) ->
relative_cd() ->
- Program = atom_to_list(lib:progname()),
+ Program = ct:get_progname(),
ok = file:set_cwd(".."),
{ok, Cwd} = file:get_cwd(),
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index 585c5a1871..f4b1d885fe 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -59,6 +59,7 @@
no_priority_inversion2/1,
system_task_blast/1,
system_task_on_suspended/1,
+ system_task_failed_enqueue/1,
gc_request_when_gc_disabled/1,
gc_request_blast_when_gc_disabled/1]).
-export([prio_server/2, prio_client/2, init/1, handle_event/2]).
@@ -106,7 +107,7 @@ groups() ->
otp_7738_resume]},
{system_task, [],
[no_priority_inversion, no_priority_inversion2,
- system_task_blast, system_task_on_suspended,
+ system_task_blast, system_task_on_suspended, system_task_failed_enqueue,
gc_request_when_gc_disabled, gc_request_blast_when_gc_disabled]}].
init_per_suite(Config) ->
@@ -2232,8 +2233,8 @@ processes_term_proc_list(Config) when is_list(Config) ->
%% We have to run this test case with +S1 since instrument:allocations()
%% will report a free()'d block as present until it's actually deallocated
%% by its employer.
- Run("+MSe true +MSatags false +S1"),
- Run("+MSe true +MSatags true +S1"),
+ Run("+MSe true +Muatags false +S1"),
+ Run("+MSe true +Muatags true +S1"),
ok.
@@ -2241,10 +2242,12 @@ processes_term_proc_list(Config) when is_list(Config) ->
chk_term_proc_list(?LINE, MC, XB)).
chk_term_proc_list(Line, MustChk, ExpectBlks) ->
- Allocs = instrument:allocations(#{ allocator_types => [sl_alloc] }),
+ Allocs = instrument:allocations(),
case {MustChk, Allocs} of
{false, {error, not_enabled}} ->
not_enabled;
+ {false, {ok, {_Shift, _Unscanned, ByOrigin}}} when ByOrigin =:= #{} ->
+ not_enabled;
{_, {ok, {_Shift, _Unscanned, ByOrigin}}} ->
ByType = maps:get(system, ByOrigin, #{}),
Hist = maps:get(ptab_list_deleted_el, ByType, {}),
@@ -2625,6 +2628,57 @@ system_task_on_suspended(Config) when is_list(Config) ->
ok
end.
+%% When a system task couldn't be enqueued due to the process being in an
+%% incompatible state, it would linger in the system task list and get executed
+%% anyway the next time the process was scheduled. This would result in a
+%% double-free at best.
+%%
+%% This test continuously purges modules while other processes run dirty code,
+%% which will provoke this error as ERTS_PSTT_CPC can't be enqueued while a
+%% process is running dirty code.
+system_task_failed_enqueue(Config) when is_list(Config) ->
+ case erlang:system_info(dirty_cpu_schedulers) of
+ N when N > 0 ->
+ system_task_failed_enqueue_1(Config);
+ _ ->
+ {skipped, "No dirty scheduler support"}
+ end.
+
+system_task_failed_enqueue_1(Config) ->
+ Priv = proplists:get_value(priv_dir, Config),
+
+ Purgers = [spawn_link(fun() -> purge_loop(Priv, Id) end)
+ || Id <- lists:seq(1, erlang:system_info(schedulers))],
+ Hogs = [spawn_link(fun() -> dirty_loop() end)
+ || _ <- lists:seq(1, erlang:system_info(dirty_cpu_schedulers))],
+
+ ct:sleep(5000),
+
+ [begin
+ unlink(Pid),
+ exit(Pid, kill)
+ end || Pid <- (Purgers ++ Hogs)],
+
+ ok.
+
+purge_loop(PrivDir, Id) ->
+ Mod = "failed_enq_" ++ integer_to_list(Id),
+ Path = PrivDir ++ "/" ++ Mod,
+ file:write_file(Path ++ ".erl",
+ "-module('" ++ Mod ++ "').\n" ++
+ "-export([t/0]).\n" ++
+ "t() -> ok."),
+ purge_loop_1(Path).
+purge_loop_1(Path) ->
+ {ok, Mod} = compile:file(Path, []),
+ erlang:delete_module(Mod),
+ erts_code_purger:purge(Mod),
+ purge_loop_1(Path).
+
+dirty_loop() ->
+ ok = erts_debug:dirty_cpu(reschedule, 10000),
+ dirty_loop().
+
gc_request_when_gc_disabled(Config) when is_list(Config) ->
AIS = erts_debug:set_internal_state(available_internal_state, true),
gc_request_when_gc_disabled_do(ref),
diff --git a/erts/emulator/test/ref_SUITE.erl b/erts/emulator/test/ref_SUITE.erl
index 5f519d522e..74df857c65 100644
--- a/erts/emulator/test/ref_SUITE.erl
+++ b/erts/emulator/test/ref_SUITE.erl
@@ -22,6 +22,7 @@
-export([all/0, suite/0]).
-export([wrap_1/1]).
+-export([compare_list/1, compare_ets/1]).
-export([loop_ref/1]).
@@ -32,7 +33,7 @@ suite() ->
{timetrap, {minutes, 2}}].
all() ->
- [wrap_1].
+ [wrap_1, compare_list, compare_ets].
%% Check that refs don't wrap around easily.
wrap_1(Config) when is_list(Config) ->
@@ -53,3 +54,28 @@ loop_ref(Parent) ->
loop_ref(R, R, _) -> ok;
loop_ref(R0, _, N) ->
loop_ref(R0, make_ref(), N+1).
+
+%% Check that ref ordering works
+compare_list(Config) when is_list(Config) ->
+ %% Although this test uses external refs, it would apply the same to plain refs
+ ExtRef1 = <<131,114,0,3,100,0,3,110,64,98,3, 0,0,173,156, 0,216,0,4, 0,0,0,0>>,
+ ExtRef2 = <<131,114,0,3,100,0,3,110,64,98,3, 0,1,31,27, 129,4,0,1, 0,0,0,0>>,
+
+ Ref1 = binary_to_term(ExtRef1), %% #Ref<[email protected]>
+ Ref2 = binary_to_term(ExtRef2), %% #Ref<[email protected]>
+ OrderedList = [Ref1, Ref2],
+ OrderedList = lists:sort(OrderedList),
+ ok.
+
+%% This is the scarier case since it makes terms "invisible" in ets or Mnesia
+%% (the underlying fault cause is the same as compare_list/1)
+compare_ets(Config) when is_list(Config) ->
+ W2s = [610350147,899574699,2994196869,686384822,2397690439, 923302211],
+ ExtRefBase = <<131,114,0,3,100,0,3,110,64,98,3>>,
+ ExtRefs = [<<ExtRefBase/binary, 1:32, W2:32, 0:32>> || W2 <- W2s],
+ Refs = [binary_to_term(Bin) || Bin <- ExtRefs],
+
+ Ets = ets:new(refbug, [ordered_set]),
+ ets:insert(Ets, [{Ref,Ref} || Ref <- Refs]),
+ 0 = length([R || R <- ets:tab2list(Ets), ets:lookup(Ets, element(1,R)) == []]),
+ ok.
diff --git a/erts/emulator/test/register_SUITE.erl b/erts/emulator/test/register_SUITE.erl
index 49da94a775..a7c0acbf17 100644
--- a/erts/emulator/test/register_SUITE.erl
+++ b/erts/emulator/test/register_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/sensitive_SUITE.erl b/erts/emulator/test/sensitive_SUITE.erl
index c3e303bbd1..206d2c1bfc 100644
--- a/erts/emulator/test/sensitive_SUITE.erl
+++ b/erts/emulator/test/sensitive_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -413,7 +413,7 @@ my_process_info(Pid, Tag) ->
t_process_display(Config) when is_list(Config) ->
Dir = filename:dirname(code:which(?MODULE)),
- Cmd = atom_to_list(lib:progname()) ++ " -noinput -pa " ++ Dir ++
+ Cmd = ct:get_progname() ++ " -noinput -pa " ++ Dir ++
" -run " ++ ?MODULE_STRING ++ " remote_process_display",
io:put_chars(Cmd),
P = open_port({spawn,Cmd}, [in,stderr_to_stdout,eof]),
diff --git a/erts/emulator/test/smoke_test_SUITE.erl b/erts/emulator/test/smoke_test_SUITE.erl
index b3d34103f1..26c610e3a8 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-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/statistics_SUITE.erl b/erts/emulator/test/statistics_SUITE.erl
index 3f2897242e..ae3099633a 100644
--- a/erts/emulator/test/statistics_SUITE.erl
+++ b/erts/emulator/test/statistics_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/system_info_SUITE.erl b/erts/emulator/test/system_info_SUITE.erl
index fdf4aab24d..8ea2d88ec4 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-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -37,6 +37,7 @@
-export([process_count/1, system_version/1, misc_smoke_tests/1,
heap_size/1, wordsize/1, memory/1, ets_limit/1, atom_limit/1,
+ ets_count/1,
atom_count/1]).
suite() ->
@@ -45,6 +46,7 @@ suite() ->
all() ->
[process_count, system_version, misc_smoke_tests,
+ ets_count,
heap_size, wordsize, memory, ets_limit, atom_limit, atom_count].
%%%
@@ -455,11 +457,16 @@ cmp_memory(MWs, Str) ->
%% Total, processes, processes_used, and system will seldom
%% give us exactly the same result since the two readings
%% aren't taken atomically.
+ %%
+ %% Torerance is scaled according to the number of schedulers
+ %% to match spawn_mem_workers.
+
+ Tolerance = 1.05 + 0.01 * erlang:system_info(schedulers_online),
- cmp_memory(total, EM, EDM, 1.05),
- cmp_memory(processes, EM, EDM, 1.05),
- cmp_memory(processes_used, EM, EDM, 1.05),
- cmp_memory(system, EM, EDM, 1.05),
+ cmp_memory(total, EM, EDM, Tolerance),
+ cmp_memory(processes, EM, EDM, Tolerance),
+ cmp_memory(processes_used, EM, EDM, Tolerance),
+ cmp_memory(system, EM, EDM, Tolerance),
ok.
@@ -478,6 +485,21 @@ get_node_name(Config) ->
++ "-"
++ integer_to_list(erlang:unique_integer([positive]))).
+ets_count(Config) when is_list(Config) ->
+ [ets_count_do([Type | Named])
+ || Type <- [set, bag, duplicate_bag, ordered_set],
+ Named <- [[named_table], []]
+ ],
+ ok.
+
+ets_count_do(Opts) ->
+ Before = erlang:system_info(ets_count),
+ T = ets:new(?MODULE, Opts),
+ After = erlang:system_info(ets_count),
+ After = Before + 1,
+ ets:delete(T),
+ Before = erlang:system_info(ets_count).
+
%% Verify system_info(ets_limit) reflects max ETS table settings.
ets_limit(Config0) when is_list(Config0) ->
diff --git a/erts/emulator/test/system_profile_SUITE.erl b/erts/emulator/test/system_profile_SUITE.erl
index c9be54f668..0c3844e90f 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-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -95,18 +95,20 @@ do_runnable_procs({TsType, TsTypeFlag}) ->
% FIXME: Set #laps and #nodes in config file
Nodes = 10,
Laps = 10,
- Master = ring(Nodes),
+ All = ring(Nodes, [link,monitor]),
+ [Master | _] = All,
undefined = erlang:system_profile(Pid, [runnable_procs]++TsTypeFlag),
% loop a message
ok = ring_message(Master, message, Laps),
+ ok = kill_ring(Master),
+ [receive {'DOWN', _, process, P, _} -> ok end || P <- All],
Events = get_profiler_events(),
- kill_em_all = kill_ring(Master),
erlang:system_profile(undefined, []),
put(master, Master),
put(laps, Laps),
true = has_runnable_event(TsType, Events),
Pids = sort_events_by_pid(Events),
- ok = check_events(TsType, Pids),
+ ok = check_events(TsType, Pids, (Laps+1)*2+2, (Laps+1)*2),
erase(),
exit(Pid,kill),
ok.
@@ -139,7 +141,7 @@ do_runnable_ports({TsType, TsTypeFlag}, Config) ->
erlang:system_profile(undefined, []),
true = has_runnable_event(TsType, Events),
Pids = sort_events_by_pid(Events),
- ok = check_events(TsType, Pids),
+ ok = check_events(TsType, Pids, Laps*2+2, Laps*2),
erase(),
exit(Pid,kill),
ok.
@@ -171,12 +173,12 @@ dont_profile_profiler(Config) when is_list(Config) ->
Nodes = 10,
Laps = 10,
- Master = ring(Nodes),
+ [Master|_] = ring(Nodes, [link]),
undefined = erlang:system_profile(Pid, [runnable_procs]),
% loop a message
ok = ring_message(Master, message, Laps),
erlang:system_profile(undefined, []),
- kill_em_all = kill_ring(Master),
+ ok = kill_ring(Master),
Events = get_profiler_events(),
false = has_profiler_pid_event(Events, Pid),
@@ -248,27 +250,28 @@ check_block_system({TsType, TsTypeFlag}, Nodes) ->
%%% Check events
-check_events(_TsType, []) -> ok;
-check_events(TsType, [Pid | Pids]) ->
+check_events(_TsType, [], _, _) -> ok;
+check_events(TsType, [Pid | Pids], ExpMaster, ExpMember) ->
Master = get(master),
- Laps = get(laps),
CheckPids = get(pids),
{Events, N} = get_pid_events(Pid),
ok = check_event_flow(Events),
ok = check_event_ts(TsType, Events),
IsMember = lists:member(Pid, CheckPids),
- case Pid of
- Master ->
- io:format("Expected ~p and got ~p profile events from ~p: ok~n", [Laps*2+2, N, Pid]),
- N = Laps*2 + 2,
- check_events(TsType, Pids);
- Pid when IsMember == true ->
- io:format("Expected ~p and got ~p profile events from ~p: ok~n", [Laps*2, N, Pid]),
- N = Laps*2,
- check_events(TsType, Pids);
- Pid ->
- check_events(TsType, Pids)
- end.
+ {Title,Exp} = case Pid of
+ Master -> {master,ExpMaster};
+ Pid when IsMember == true -> {member,ExpMember};
+ _ -> {other,N}
+ end,
+ ok = case N of
+ Exp -> ok;
+ _ ->
+ io:format("Expected ~p and got ~p profile events from ~p ~p:~n~p~n",
+ [Exp, N, Title, Pid, Events]),
+ error
+ end,
+ check_events(TsType, Pids, ExpMaster, ExpMember).
+
%% timestamp consistency check for descending timestamps
@@ -296,7 +299,13 @@ check_event_ts(TsType, [{Pid, _, _, TS1}=Event | Events], {Pid,_,_,TS0}) ->
%% consistency check for active vs. inactive activity (runnable)
check_event_flow(Events) ->
- check_event_flow(Events, undefined).
+ case check_event_flow(Events, undefined) of
+ ok -> ok;
+ Error ->
+ io:format("Events = ~p\n", [Events]),
+ Error
+ end.
+
check_event_flow([], _) -> ok;
check_event_flow([Event | PidEvents], undefined) ->
check_event_flow(PidEvents, Event);
@@ -336,10 +345,11 @@ sort_events_by_pid([Event | Events],Pids) ->
%% API
% Returns master pid
-ring(N) ->
- Pids = build_ring(N, []),
+ring(N, SpawnOpt) ->
+ Pids = build_ring(N, [], SpawnOpt),
put(pids, Pids),
- setup_ring(Pids).
+ setup_ring(Pids),
+ Pids.
ring_message(Master, Message, Laps) ->
Master ! {message, Master, Laps, Message},
@@ -347,13 +357,19 @@ ring_message(Master, Message, Laps) ->
{laps_complete, Master} -> ok
end.
-kill_ring(Master) -> Master ! kill_em_all.
+kill_ring(Master) ->
+ Master ! kill_em_all,
+ ok.
%% Process ring helpers
-build_ring(0, Pids) -> Pids;
-build_ring(N, Pids) ->
- build_ring(N - 1, [spawn_link(?MODULE, ring_loop, [undefined]) | Pids]).
+build_ring(0, Pids, _) -> Pids;
+build_ring(N, Pids, SpawnOpt) ->
+ Pid = case spawn_opt(?MODULE, ring_loop, [undefined], SpawnOpt) of
+ {P,_} -> P;
+ P -> P
+ end,
+ build_ring(N-1, [Pid | Pids], SpawnOpt).
setup_ring([Master | Relayers]) ->
% Relayers may not include the master pid
@@ -382,15 +398,13 @@ ring_loop(RelayTo) ->
{message, Master, Lap, Msg}=Message ->
case {self(), Lap} of
{Master, 0} ->
- get(supervisor) ! {laps_complete, self()},
- ring_loop(RelayTo);
+ get(supervisor) ! {laps_complete, self()};
{Master, Lap} ->
- RelayTo ! {message, Master, Lap - 1, Msg},
- ring_loop(RelayTo);
+ RelayTo ! {message, Master, Lap - 1, Msg};
_ ->
- RelayTo ! Message,
- ring_loop(RelayTo)
- end
+ RelayTo ! Message
+ end,
+ ring_loop(RelayTo)
end.
%%%
diff --git a/erts/emulator/test/timer_bif_SUITE.erl b/erts/emulator/test/timer_bif_SUITE.erl
index fc11a04a31..15fe13c8c0 100644
--- a/erts/emulator/test/timer_bif_SUITE.erl
+++ b/erts/emulator/test/timer_bif_SUITE.erl
@@ -361,7 +361,7 @@ evil_timers(Config) when is_list(Config) ->
%%
%% 1. A timer started with erlang:start_timer(Time, Receiver, Msg),
%% where Msg is a composite term, expires, and the receivers main
- %% lock *can not* be acquired immediately (typically when the
+ %% lock *cannot* be acquired immediately (typically when the
%% receiver *is* running).
%%
%% The wrap tuple ({timeout, TRef, Msg}) will in this case
@@ -372,7 +372,7 @@ evil_timers(Config) when is_list(Config) ->
RecvTimeOutMsgs0 = evil_recv_timeouts(200),
%% 2. A timer started with erlang:start_timer(Time, Receiver, Msg),
%% where Msg is an immediate term, expires, and the receivers main
- %% lock *can not* be acquired immediately (typically when the
+ %% lock *cannot* be acquired immediately (typically when the
%% receiver *is* running).
%%
%% The wrap tuple will in this case be allocated in a new
diff --git a/erts/emulator/test/trace_SUITE.erl b/erts/emulator/test/trace_SUITE.erl
index def25dba7d..c2d5cd7023 100644
--- a/erts/emulator/test/trace_SUITE.erl
+++ b/erts/emulator/test/trace_SUITE.erl
@@ -29,7 +29,7 @@
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_new_trace/1,
- suspend/1, mutual_suspend/1, suspend_exit/1, suspender_exit/1,
+ suspend/1, suspend_exit/1, suspender_exit/1,
suspend_system_limit/1, suspend_opts/1, suspend_waiting/1,
new_clear/1, existing_clear/1, tracer_die/1,
set_on_spawn/1, set_on_first_spawn/1, cpu_timestamp/1,
@@ -38,7 +38,8 @@
system_monitor_long_gc_1/1, system_monitor_long_gc_2/1,
system_monitor_large_heap_1/1, system_monitor_large_heap_2/1,
system_monitor_long_schedule/1,
- bad_flag/1, trace_delivered/1, trap_exit_self_receive/1]).
+ bad_flag/1, trace_delivered/1, trap_exit_self_receive/1,
+ trace_info_badarg/1, erl_704/1]).
-include_lib("common_test/include/ct.hrl").
@@ -53,7 +54,7 @@ all() ->
[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_exit, suspender_exit,
suspend_system_limit, suspend_opts, suspend_waiting,
new_clear, existing_clear, tracer_die, set_on_spawn,
set_on_first_spawn, set_on_link, set_on_first_link,
@@ -62,7 +63,7 @@ all() ->
system_monitor_long_gc_2, system_monitor_large_heap_1,
system_monitor_long_schedule,
system_monitor_large_heap_2, bad_flag, trace_delivered,
- trap_exit_self_receive].
+ trap_exit_self_receive, trace_info_badarg, erl_704].
init_per_testcase(_Case, Config) ->
[{receiver,spawn(fun receiver/0)}|Config].
@@ -1234,55 +1235,6 @@ do_suspend(Pid, N) ->
erlang:yield(),
do_suspend(Pid, N-1).
-
-
-mutual_suspend(Config) when is_list(Config) ->
- TimeoutSecs = 5*60,
- ct:timetrap({seconds, TimeoutSecs}),
- Parent = self(),
- Fun = fun () ->
- receive
- {go, Pid} ->
- do_mutual_suspend(Pid, 100000)
- end,
- Parent ! {done, self()},
- receive after infinity -> ok end
- end,
- P1 = spawn_link(Fun),
- P2 = spawn_link(Fun),
- T1 = erlang:start_timer((TimeoutSecs - 5)*1000, self(), oops),
- T2 = erlang:start_timer((TimeoutSecs - 5)*1000, self(), oops),
- P1 ! {go, P2},
- P2 ! {go, P1},
- Res1 = receive
- {done, P1} -> done;
- {timeout,T1,_} -> timeout
- end,
- Res2 = receive
- {done, P2} -> done;
- {timeout,T2,_} -> timeout
- end,
- P1S = process_info(P1, status),
- P2S = process_info(P2, status),
- io:format("P1S=~p P2S=~p", [P1S, P2S]),
- false = {status, suspended} == P1S,
- false = {status, suspended} == P2S,
- unlink(P1), exit(P1, bang),
- unlink(P2), exit(P2, bang),
- done = Res1,
- done = Res2,
- ok.
-
-do_mutual_suspend(_Pid, 0) ->
- ok;
-do_mutual_suspend(Pid, N) ->
- %% Suspend a process and test that it is suspended.
- true = erlang:suspend_process(Pid),
- {status, suspended} = process_info(Pid, status),
- %% Unsuspend the process.
- true = erlang:resume_process(Pid),
- do_mutual_suspend(Pid, N-1).
-
suspend_exit(Config) when is_list(Config) ->
ct:timetrap({minutes, 2}),
rand:seed(exsplus, {4711,17,4711}),
@@ -1513,7 +1465,8 @@ suspend_opts(Config) when is_list(Config) ->
dbl_async = AA,
synced = S,
async_once = AO} = Acc) ->
- erlang:suspend_process(Tok, [asynchronous]),
+ Tag = {make_ref(), self()},
+ erlang:suspend_process(Tok, [{asynchronous, Tag}]),
Res = case {suspend_count(Tok), N rem 4} of
{0, 2} ->
erlang:suspend_process(Tok,
@@ -1549,7 +1502,11 @@ suspend_opts(Config) when is_list(Config) ->
_ ->
Acc
end,
- erlang:resume_process(Tok),
+ receive
+ {Tag, Result} ->
+ suspended = Result,
+ erlang:resume_process(Tok)
+ end,
erlang:yield(),
Res
end,
@@ -1778,6 +1735,25 @@ trap_exit_self_receive(Config) ->
receive_nothing(),
ok.
+trace_info_badarg(Config) when is_list(Config) ->
+ catch erlang:trace_info({a,b,c},d),
+ ok.
+
+%% An incoming suspend monitor down wasn't handled
+%% correct when the local monitor half had been
+%% removed with an emulator crash as result.
+erl_704(Config) ->
+ erl_704_test(100).
+
+erl_704_test(0) ->
+ ok;
+erl_704_test(N) ->
+ P = spawn(fun () -> receive infinity -> ok end end),
+ erlang:suspend_process(P),
+ exit(P, kill),
+ (catch erlang:resume_process(P)),
+ erl_704_test(N-1).
+
drop_trace_until_down(Proc, Mon) ->
drop_trace_until_down(Proc, Mon, false, 0, 0).
diff --git a/erts/emulator/test/tracer_SUITE.erl b/erts/emulator/test/tracer_SUITE.erl
index e1362ef07a..5556953feb 100644
--- a/erts/emulator/test/tracer_SUITE.erl
+++ b/erts/emulator/test/tracer_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -623,7 +623,7 @@ test(Event, TraceFlag, Tc, Expect, _Removes, Dies) ->
Expect(Pid1, State1, Opts),
receive M11 -> ct:fail({unexpected, M11}) after 0 -> ok end,
- if not Dies ->
+ if not Dies andalso Event /= in ->
{flags, [TraceFlag]} = erlang:trace_info(Pid1, flags),
{tracer, {tracer_test, State1}} = erlang:trace_info(Pid1, tracer),
erlang:trace(Pid1, false, [TraceFlag]);
@@ -640,7 +640,7 @@ test(Event, TraceFlag, Tc, Expect, _Removes, Dies) ->
Expect(Pid1T, State1, Opts#{ scheduler_id => number,
timestamp => timestamp}),
receive M11T -> ct:fail({unexpected, M11T}) after 0 -> ok end,
- if not Dies ->
+ if not Dies andalso Event /= in ->
{flags, [scheduler_id, TraceFlag, timestamp]}
= erlang:trace_info(Pid1T, flags),
{tracer, {tracer_test, State1}} = erlang:trace_info(Pid1T, tracer),
@@ -655,7 +655,7 @@ test(Event, TraceFlag, Tc, Expect, _Removes, Dies) ->
Tc(Pid2),
ok = trace_delivered(Pid2),
receive M2 -> ct:fail({unexpected, M2}) after 0 -> ok end,
- if not Dies ->
+ if not Dies andalso Event /= in ->
{flags, [TraceFlag]} = erlang:trace_info(Pid2, flags),
{tracer, {tracer_test, State2}} = erlang:trace_info(Pid2, tracer),
erlang:trace(Pid2, false, [TraceFlag]);
diff --git a/erts/emulator/test/tuple_SUITE.erl b/erts/emulator/test/tuple_SUITE.erl
index baf41180e0..e03677a518 100644
--- a/erts/emulator/test/tuple_SUITE.erl
+++ b/erts/emulator/test/tuple_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/test/z_SUITE.erl b/erts/emulator/test/z_SUITE.erl
index 103f9f1550..1c52e1a934 100644
--- a/erts/emulator/test/z_SUITE.erl
+++ b/erts/emulator/test/z_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/emulator/utils/make_driver_tab b/erts/emulator/utils/make_driver_tab
index b7bca1dc3a..a000b9d415 100755
--- a/erts/emulator/utils/make_driver_tab
+++ b/erts/emulator/utils/make_driver_tab
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
+# Copyright Ericsson AB 1999-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/erts/emulator/utils/make_tables b/erts/emulator/utils/make_tables
index 094a35ae4b..deee5c2344 100755
--- a/erts/emulator/utils/make_tables
+++ b/erts/emulator/utils/make_tables
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
+# Copyright Ericsson AB 1999-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c
index 21a3f40c97..0cb01fd4ef 100644
--- a/erts/etc/common/erlexec.c
+++ b/erts/etc/common/erlexec.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/etc/common/escript.c b/erts/etc/common/escript.c
index d739d21f12..078937e676 100644
--- a/erts/etc/common/escript.c
+++ b/erts/etc/common/escript.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2007-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2007-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -139,15 +139,6 @@ get_env(char *key)
}
static void
-free_env_val(char *value)
-{
-#ifdef __WIN32__
- if (value)
- efree(value);
-#endif
-}
-
-static void
set_env(char *key, char *value)
{
#ifdef __WIN32__
@@ -422,7 +413,6 @@ main(int argc, char** argv)
int eargv_size;
int eargc_base; /* How many arguments in the base of eargv. */
char* emulator;
- char* env;
char* basename;
char* def_emu_lookup_path;
char scriptname[PMAX];
@@ -504,7 +494,7 @@ main(int argc, char** argv)
}
/* Determine path to emulator */
- emulator = env = get_env("ESCRIPT_EMULATOR");
+ emulator = get_env("ESCRIPT_EMULATOR");
if (emulator == NULL) {
emulator = get_default_emulator(def_emu_lookup_path);
@@ -518,7 +508,6 @@ main(int argc, char** argv)
*/
PUSH(emulator);
- free_env_val(env);
PUSH("+B");
PUSH2("-boot", "no_dot_erlang");
diff --git a/erts/etc/common/heart.c b/erts/etc/common/heart.c
index 8f1e89b638..bd218ff725 100644
--- a/erts/etc/common/heart.c
+++ b/erts/etc/common/heart.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/etc/unix/cerl.src b/erts/etc/unix/cerl.src
index 9dd8d85abe..2e034513b0 100644
--- a/erts/etc/unix/cerl.src
+++ b/erts/etc/unix/cerl.src
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2016. All Rights Reserved.
+# Copyright Ericsson AB 2003-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -69,15 +69,6 @@ cxargs_add() {
done
}
-eeargs=
-eeargs_add() {
- while [ $# -gt 0 ]; do
- cargs="$cargs $1"
- eeargs="$eeargs $1"
- shift
- done
-}
-
core=
GDB=
@@ -97,8 +88,6 @@ TARGET=%TARGET%
PROGNAME=$ROOTDIR/bin/cerl
EMU=beam
-PRELOADED=$ROOTDIR/erts/preloaded/ebin
-
while [ $# -gt 0 ]; do
case "$1" in
@@ -255,7 +244,7 @@ EXEC=$BINDIR/erlexec
PROGNAME="$PROGNAME$cargs"
EMU="$EMU$TYPE"
-EMU_NAME=`$EXEC -emu_name_exit $eeargs`
+EMU_NAME=`$EXEC -emu_name_exit`
if [ $skip_erlexec = yes ]; then
emu_xargs=`echo $xargs | sed "s|+|-|g"`
@@ -269,21 +258,20 @@ if [ $skip_erlexec = yes ]; then
'
set -- $beam_args
IFS="$SAVE_IFS"
-else
- xargs="$xargs -pz $PRELOADED --"
fi
if [ "x$GDB" = "x" ]; then
if [ $run_valgrind = yes ]; then
valversion=`valgrind --version`
valmajor=`echo $valversion | sed 's,[a-z]*\-\([0-9]*\).*,\1,'`
valminor=`echo $valversion | sed 's,[a-z]*\-[0-9]*.\([0-9]*\).*,\1,'`
+ valint=`echo "$valmajor * 1000 + $valminor" | bc`
if [ "x$VALGRIND_LOG_XML" = "x" ]; then
valgrind_xml=
log_file_prefix="--log-file="
else
export VALGRIND_LOG_XML
valgrind_xml="--xml=yes"
- if [ $valmajor -gt 2 -a $valminor -gt 4 ]; then
+ if [ $valint -gt 3004 ]; then
log_file_prefix="--xml-file="
else
log_file_prefix="--log-file="
@@ -292,7 +280,7 @@ if [ "x$GDB" = "x" ]; then
if [ "x$VALGRIND_LOG_DIR" = "x" ]; then
valgrind_log=
else
- if [ $valmajor -gt 2 -a $valminor -gt 4 ]; then
+ if [ $valint -gt 3004 ]; then
valgrind_log="$log_file_prefix$VALGRIND_LOG_DIR/$VALGRIND_LOGFILE_PREFIX$VALGRIND_LOGFILE_INFIX$EMU_NAME.log.$$"
else
valgrind_log="$log_file_prefix$VALGRIND_LOG_DIR/$VALGRIND_LOGFILE_PREFIX$VALGRIND_LOGFILE_INFIX$EMU_NAME.log"
@@ -316,12 +304,12 @@ if [ "x$GDB" = "x" ]; then
sched_arg=
fi
- exec $taskset1 valgrind $valgrind_xml $valgrind_log $valgrind_misc_flags $BINDIR/$EMU_NAME $sched_arg $emu_xargs "$@" -pz $PRELOADED
+ exec $taskset1 valgrind $valgrind_xml $valgrind_log $valgrind_misc_flags $BINDIR/$EMU_NAME $sched_arg $emu_xargs "$@"
elif [ $run_rr = yes ]; then
- exec rr record --ignore-nested $BINDIR/$EMU_NAME $emu_xargs "$@" -pz $PRELOADED
+ exec rr record --ignore-nested $BINDIR/$EMU_NAME $emu_xargs "$@"
else
- exec $EXEC $eeargs $xargs ${1+"$@"}
+ exec $EXEC $xargs ${1+"$@"}
fi
elif [ "x$GDB" = "xgdb" ]; then
case "x$core" in
diff --git a/erts/etc/unix/dyn_erl.c b/erts/etc/unix/dyn_erl.c
index 5c7c3cad38..c4a2f7217c 100644
--- a/erts/etc/unix/dyn_erl.c
+++ b/erts/etc/unix/dyn_erl.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2009-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in
index e5ef819444..b12a205ba7 100644
--- a/erts/etc/unix/etp-commands.in
+++ b/erts/etc/unix/etp-commands.in
@@ -1232,6 +1232,141 @@ end
# Commands for special term bunches.
#
+define etp-sig-int
+ set $etp_sig_is_message = 0
+ set $etp_sig_tag = ($arg0)->m[0]
+ if ($etp_sig_tag & 0x3) != 0 || $etp_sig_tag == etp_the_non_value
+ set $etp_sig_is_message = !0
+ # A message
+ if $etp_sig_tag != etp_the_non_value
+ etp-1 $etp_sig_tag 0
+ else
+ print "!ENCODED-DIST-MSG"
+ end
+ if ($arg0)->m[1] != $etp_nil
+ printf " @token= "
+ etp-1 ($arg0)->m[1] 0
+ end
+ printf " @from= "
+ etp-1 ($arg0)->m[2] 0
+ else
+ if ($etp_sig_tag & 0x3f) != 0x30
+ print "!INVALID-SIGNAL"
+ else
+ set $etp_sig_op = (($etp_sig_tag >> 6) & 0xff)
+ set $etp_sig_type = (($etp_sig_tag >> 14) & 0xff)
+ if $etp_sig_op == 0
+ printf "!EXIT[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 1
+ printf "!EXIT-LINKED[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 2
+ printf "!MONITOR-DOWN[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 3
+ printf "!MONITOR[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 4
+ printf "!DEMONITOR[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 5
+ printf "!LINK[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 6
+ printf "!UNLINK[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 7
+ printf "!GROUP-LEADER[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 8
+ printf "!TRACE-CHANGE-STATE[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 9
+ printf "!PERSISTENT-MONITOR-MESSAGE[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 10
+ printf "!IS-ALIVE[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 11
+ printf "!PROCESS-INFO[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 12
+ printf "!SYNC-SUSPEND[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 13
+ printf "!RPC[%d]", $etp_sig_type
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+
+define etp-sigq-int
+# Args: ErlMessageQueue*
+#
+# Non-reentrant
+#
+ set $etp_sig = ($arg0)
+ set $etp_sig_save = ($arg1)
+ set $etp_sig_save_last = ($arg2)
+ set $etp_sigq_msig_len = 0
+ set $etp_sigq_nmsig_len = 0
+
+ printf " ["
+ while $etp_sig != (void *) 0
+ set $etp_sig_next = $etp_sig->next
+ if $etp_sig != ($arg0)
+ printf " "
+ end
+ etp-sig-int $etp_sig
+ if $etp_sig_is_message
+ set $etp_sigq_msig_len++
+ else
+ set $etp_sigq_nmsig_len++
+ end
+ if $etp_sig_next
+ printf ","
+ end
+ if $etp_sig_save && *$etp_sig_save == $etp_sig
+ printf " %% <== SAVE"
+ else
+ if $etp_sig_save_last && *$etp_sig_save_last == $etp_sig
+ printf " %% <== SAVED_LAST"
+ end
+ end
+ if $etp_sig_next
+ printf "\n"
+ end
+ set $etp_sig = $etp_sig_next
+ end
+ printf "]\n\n"
+ printf " Message signals: %d\n", $etp_sigq_msig_len
+ printf " Non-message signals: %d\n\n", $etp_sigq_nmsig_len
+end
+
+define etp-sigqs
+ printf " --- Inner signal queue (message queue) ---\n"
+ etp-sigq-int ($arg0)->sig_qs.first ($arg0)->sig_qs.save ($arg0)->sig_qs.saved_last
+ printf " --- Middle signal queue ---\n"
+ etp-sigq-int ($arg0)->sig_qs.cont ($arg0)->sig_qs.save ($arg0)->sig_qs.saved_last
+ printf " --- Outer queue ---\n"
+ etp-sigq-int ($arg0)->sig_inq.first ($arg0)->sig_qs.save ($arg0)->sig_qs.saved_last
+end
+
define etp-msgq
# Args: ErlMessageQueue*
#
@@ -1937,7 +2072,7 @@ document etp-proc-flags
%---------------------------------------------------------------------------
end
-define etp-process-info
+define etp-process-info-int
# Args: Process*
#
printf " Pid: "
@@ -2000,6 +2135,17 @@ define etp-process-info
etp-1 ((Eterm)($etp_proc->parent))
printf "\n Pointer: (Process *) %p\n", $etp_proc
end
+ if ($arg1)
+ etp-sigqs $etp_proc
+ end
+end
+
+define etp-process-info
+ etp-process-info-int ($arg0) 0
+end
+
+define etp-process-info-x
+ etp-process-info-int ($arg0) !0
end
document etp-process-info
@@ -2010,7 +2156,7 @@ document etp-process-info
%---------------------------------------------------------------------------
end
-define etp-processes
+define etp-processes-int
if (!erts_initialized)
printf "No processes, since system isn't initialized!\n"
else
@@ -2026,7 +2172,7 @@ define etp-processes
if ($proc != ((Process *) 0) && $proc != $invalid_proc)
printf "---\n"
printf " Pix: %d\n", $proc_ix
- etp-process-info $proc
+ etp-process-info-int $proc ($arg0)
set $proc_cnt--
end
if $proc_ix == $proc_printile
@@ -2039,6 +2185,14 @@ define etp-processes
end
end
+define etp-processes
+ etp-processes-int 0
+end
+
+define etp-processes-x
+ etp-processes-int !0
+end
+
document etp-processes
%---------------------------------------------------------------------------
% etp-processes
@@ -2580,25 +2734,37 @@ define etp-aux-work-flags
printf " fix-alloc-lower-lim"
end
if ($arg0 & 0x10)
- printf " async-ready"
+ printf " later-op"
end
if ($arg0 & 0x20)
- printf " async-ready-clean"
+ printf " canceled-timers"
end
if ($arg0 & 0x40)
- printf " misc-work-thr-prgr"
+ printf " canceled-timers-thr-prgr"
end
if ($arg0 & 0x80)
- printf " misc-work"
+ printf " async-ready"
end
if ($arg0 & 0x100)
- printf " check-children"
+ printf " async-ready-clean"
end
if ($arg0 & 0x200)
- printf " set-tmo"
+ printf " misc-thr-prgr"
end
if ($arg0 & 0x400)
- printf " mseg-cached-check"
+ printf " misc"
+ end
+ if ($arg0 & 0x800)
+ printf " set-tmo"
+ end
+ if ($arg0 & 0x1000)
+ printf " mseg-cache-check"
+ end
+ if ($arg0 & 0x2000)
+ printf " yield"
+ end
+ if ($arg0 & 0x1000)
+ printf " reap-ports"
end
if ($arg0 & ~0x7ff)
printf " GARBAGE"
diff --git a/erts/include/internal/erl_printf.h b/erts/include/internal/erl_printf.h
index 7e9807f6a8..6881c9d4f1 100644
--- a/erts/include/internal/erl_printf.h
+++ b/erts/include/internal/erl_printf.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2005-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/include/internal/gcc/ethr_membar.h b/erts/include/internal/gcc/ethr_membar.h
index 07960ce040..5cbda5582d 100644
--- a/erts/include/internal/gcc/ethr_membar.h
+++ b/erts/include/internal/gcc/ethr_membar.h
@@ -96,7 +96,7 @@
* issue an aquire memory barrier and an __atomic
* builtin memory acess with the __ATOMIC_RELEASE
* memory model must at least issue a release memory
- * barrier. Otherwise the two can not be paired.
+ * barrier. Otherwise the two cannot be paired.
* 4. All __atomic builtins accessing memory using the
* __ATOMIC_CONSUME builtin can be used for the same
* reason __ATOMIC_ACQUIRE can be used. The ethread
diff --git a/erts/lib_src/Makefile.in b/erts/lib_src/Makefile.in
index 48660f7c71..8e1f5b58c4 100644
--- a/erts/lib_src/Makefile.in
+++ b/erts/lib_src/Makefile.in
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2016. All Rights Reserved.
+# Copyright Ericsson AB 2004-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -334,7 +334,7 @@ ETHREAD_LIB=
endif
-ifneq ($(CREATE_DIRS),)
+ifneq ($(strip $(CREATE_DIRS)),)
_create_dirs := $(shell mkdir -p $(CREATE_DIRS))
endif
diff --git a/erts/lib_src/common/erl_printf.c b/erts/lib_src/common/erl_printf.c
index 1de0f81e84..259ba8c81d 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2005-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/lib_src/common/erl_printf_format.c b/erts/lib_src/common/erl_printf_format.c
index 5a680d6f9d..8f9e0b4a90 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-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2005-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam
index 495d306a23..0f5f5036f0 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
index cd2c0ac69d..6017112dac 100644
--- a/erts/preloaded/ebin/erl_tracer.beam
+++ 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 6184a36d7c..7a4167b0e9 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 b6c69e3e67..c899b69a2c 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_dirty_process_signal_handler.beam b/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam
index 8d9ca3fcae..9490a56758 100644
--- a/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam
+++ b/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam
index cdfdaf9640..15c59de80a 100644
--- a/erts/preloaded/ebin/erts_internal.beam
+++ b/erts/preloaded/ebin/erts_internal.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_literal_area_collector.beam b/erts/preloaded/ebin/erts_literal_area_collector.beam
index 18f1f76055..e650a6b5af 100644
--- a/erts/preloaded/ebin/erts_literal_area_collector.beam
+++ b/erts/preloaded/ebin/erts_literal_area_collector.beam
Binary files differ
diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam
index 1b458fc5da..858a9dc63e 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 69d809e325..0d194896c7 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_buffer.beam b/erts/preloaded/ebin/prim_buffer.beam
index e2f0d3f44d..4ad1380d0b 100644
--- a/erts/preloaded/ebin/prim_buffer.beam
+++ b/erts/preloaded/ebin/prim_buffer.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam
index e962fcfa17..2ae18846bf 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 b11e428229..3316e4348c 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 350cc343d5..c30c589d3a 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 1d50d32efe..4923cadbdc 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 a328711702..07e7e97814 100644
--- a/erts/preloaded/ebin/zlib.beam
+++ b/erts/preloaded/ebin/zlib.beam
Binary files differ
diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl
index 42c1f32a8e..ae5f86e017 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-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index 5fcad25c6d..261b731900 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -86,15 +86,15 @@
| 'nano_seconds'.
-opaque prepared_code() :: reference().
-
-export_type([prepared_code/0]).
--opaque dist_handle() :: atom().
+-opaque nif_resource() :: reference().
+-export_type([nif_resource/0]).
+-opaque dist_handle() :: atom().
-export_type([dist_handle/0]).
-type iovec() :: [binary()].
-
-export_type([iovec/0]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1521,8 +1521,21 @@ pre_loaded() ->
-spec erlang:process_display(Pid, Type) -> true when
Pid :: pid(),
Type :: backtrace.
-process_display(_Pid, _Type) ->
- erlang:nif_error(undefined).
+process_display(Pid, Type) ->
+ case case erts_internal:process_display(Pid, Type) of
+ Ref when erlang:is_reference(Ref) ->
+ receive
+ {Ref, Res} ->
+ Res
+ end;
+ Res ->
+ Res
+ end of
+ badarg ->
+ erlang:error(badarg, [Pid, Type]);
+ Result ->
+ Result
+ end.
%% process_flag/3
-spec process_flag(Pid, Flag, Value) -> OldValue when
@@ -1530,8 +1543,15 @@ process_display(_Pid, _Type) ->
Flag :: save_calls,
Value :: non_neg_integer(),
OldValue :: non_neg_integer().
-process_flag(_Pid, _Flag, _Value) ->
- erlang:nif_error(undefined).
+process_flag(Pid, Flag, Value) ->
+ case case erts_internal:process_flag(Pid, Flag, Value) of
+ Ref when erlang:is_reference(Ref) ->
+ receive {Ref, Res} -> Res end;
+ Res -> Res
+ end of
+ badarg -> erlang:error(badarg, [Pid, Flag, Value]);
+ Result -> Result
+ end.
%% process_info/1
-spec process_info(Pid) -> Info when
@@ -1685,12 +1705,26 @@ setnode(_P1, _P2) ->
erlang:nif_error(undefined).
%% setnode/3
--spec erlang:setnode(P1, P2, P3) -> dist_handle() when
- P1 :: atom(),
- P2 :: port(),
- P3 :: {term(), term(), term(), term()}.
-setnode(_P1, _P2, _P3) ->
- erlang:nif_error(undefined).
+-spec erlang:setnode(Node, DistCtrlr, Opts) -> dist_handle() when
+ Node :: atom(),
+ DistCtrlr :: port() | pid(),
+ Opts :: {integer(), integer(), atom(), atom()}.
+setnode(Node, DistCtrlr, {Flags, Ver, IC, OC} = Opts) when erlang:is_atom(IC),
+ erlang:is_atom(OC) ->
+ case case erts_internal:create_dist_channel(Node, DistCtrlr,
+ Flags, Ver) of
+ {ok, DH} -> DH;
+ {message, Ref} -> receive {Ref, Res} -> Res end;
+ Err -> Err
+ end of
+ Error when erlang:is_atom(Error) ->
+ erlang:error(Error, [Node, DistCtrlr, Opts]);
+ DHandle ->
+ DHandle
+ end;
+setnode(Node, DistCtrlr, Opts) ->
+ erlang:error(badarg, [Node, DistCtrlr, Opts]).
+
%% size/1
%% Shadowed by erl_bif_types: erlang:size/1
@@ -1749,9 +1783,32 @@ start_timer(_Time, _Dest, _Msg, _Options) ->
-spec erlang:suspend_process(Suspendee, OptList) -> boolean() when
Suspendee :: pid(),
OptList :: [Opt],
- Opt :: unless_suspending | asynchronous.
-suspend_process(_Suspendee, _OptList) ->
- erlang:nif_error(undefined).
+ Opt :: unless_suspending | asynchronous | {asynchronous, term()}.
+suspend_process(Suspendee, OptList) ->
+ case case erts_internal:suspend_process(Suspendee, OptList) of
+ Ref when erlang:is_reference(Ref) ->
+ receive {Ref, Res} -> Res end;
+ Res ->
+ Res
+ end of
+ true -> true;
+ false -> false;
+ Error -> erlang:error(Error, [Suspendee, OptList])
+ end.
+
+-spec erlang:suspend_process(Suspendee) -> 'true' when
+ Suspendee :: pid().
+suspend_process(Suspendee) ->
+ case case erts_internal:suspend_process(Suspendee, []) of
+ Ref when erlang:is_reference(Ref) ->
+ receive {Ref, Res} -> Res end;
+ Res ->
+ Res
+ end of
+ true -> true;
+ false -> erlang:error(internal_error, [Suspendee]);
+ Error -> erlang:error(Error, [Suspendee])
+ end.
%% system_monitor/0
-spec erlang:system_monitor() -> MonSettings when
@@ -2259,7 +2316,7 @@ process_flag(_Flag, _Value) ->
{min_heap_size, MinHeapSize :: non_neg_integer()} |
{min_bin_vheap_size, MinBinVHeapSize :: non_neg_integer()} |
{max_heap_size, MaxHeapSize :: max_heap_size()} |
- {monitored_by, Pids :: [pid()]} |
+ {monitored_by, MonitoredBy :: [pid() | port() | nif_resource()]} |
{monitors,
Monitors :: [{process | port, Pid :: pid() | port() |
{RegName :: atom(), Node :: node()}}]} |
@@ -2624,11 +2681,12 @@ tuple_to_list(_Tuple) ->
(dist_ctrl) -> {Node :: node(),
ControllingEntity :: port() | pid()};
(driver_version) -> string();
- (dynamic_trace) -> none | dtrace | systemtap;
+ (dynamic_trace) -> none | dtrace | systemtap;
(dynamic_trace_probes) -> boolean();
(end_time) -> non_neg_integer();
(elib_malloc) -> false;
(eager_check_io) -> boolean();
+ (ets_count) -> pos_integer();
(ets_limit) -> pos_integer();
(fullsweep_after) -> {fullsweep_after, non_neg_integer()};
(garbage_collection) -> [{atom(), integer()}];
@@ -3045,15 +3103,6 @@ send_nosuspend(Pid, Msg, Opts) ->
localtime_to_universaltime(Localtime) ->
erlang:localtime_to_universaltime(Localtime, undefined).
--spec erlang:suspend_process(Suspendee) -> 'true' when
- Suspendee :: pid().
-suspend_process(P) ->
- case catch erlang:suspend_process(P, []) of
- {'EXIT', {Reason, _}} -> erlang:error(Reason, [P]);
- {'EXIT', Reason} -> erlang:error(Reason, [P]);
- Res -> Res
- end.
-
%%
%% Port BIFs
%%
@@ -3605,90 +3654,28 @@ memory() ->
-spec erlang:memory(Type :: memory_type()) -> non_neg_integer();
(TypeList :: [memory_type()]) -> [{memory_type(), non_neg_integer()}].
memory(Type) when erlang:is_atom(Type) ->
- {AA, ALCU, ChkSup, BadArgZero} = need_mem_info(Type),
- case get_mem_data(ChkSup, ALCU, AA) of
- notsup ->
- erlang:error(notsup, [Type]);
- Mem ->
- Value = get_memval(Type, Mem),
- case {BadArgZero, Value} of
- {true, 0} -> erlang:error(badarg, [Type]);
- _ -> Value
- end
+ try
+ case aa_mem_data(au_mem_data(?ALL_NEEDED_ALLOCS)) of
+ notsup -> erlang:error(notsup);
+ Mem -> get_memval(Type, Mem)
+ end
+ catch
+ error:badarg -> erlang:error(badarg)
end;
memory(Types) when erlang:is_list(Types) ->
- {AA, ALCU, ChkSup, BadArgZeroList} = need_mem_info_list(Types),
- case get_mem_data(ChkSup, ALCU, AA) of
- notsup ->
- erlang:error(notsup, [Types]);
- Mem ->
- case memory_result_list(Types, BadArgZeroList, Mem) of
- badarg -> erlang:error(badarg, [Types]);
- Result -> Result
- end
- end.
-
-memory_result_list([], [], _Mem) ->
- [];
-memory_result_list([T|Ts], [BAZ|BAZs], Mem) ->
- case memory_result_list(Ts, BAZs, Mem) of
- badarg -> badarg;
- TVs ->
- V = get_memval(T, Mem),
- case {BAZ, V} of
- {true, 0} -> badarg;
- _ -> [{T, V}| TVs]
- end
- end.
-
-get_mem_data(true, AlcUAllocs, NeedAllocatedAreas) ->
- case memory_is_supported() of
- false -> notsup;
- true -> get_mem_data(false, AlcUAllocs, NeedAllocatedAreas)
- end;
-get_mem_data(false, AlcUAllocs, NeedAllocatedAreas) ->
- AlcUMem = case AlcUAllocs of
- [] -> #memory{};
- _ ->
- au_mem_data(AlcUAllocs)
- end,
- case NeedAllocatedAreas of
- true -> aa_mem_data(AlcUMem);
- false -> AlcUMem
+ try
+ case aa_mem_data(au_mem_data(?ALL_NEEDED_ALLOCS)) of
+ notsup -> erlang:error(notsup);
+ Mem -> memory_1(Types, Mem)
+ end
+ catch
+ error:badarg -> erlang:error(badarg)
end.
-need_mem_info_list([]) ->
- {false, [], false, []};
-need_mem_info_list([T|Ts]) ->
- {MAA, MALCU, MChkSup, MBadArgZero} = need_mem_info_list(Ts),
- {AA, ALCU, ChkSup, BadArgZero} = need_mem_info(T),
- {case AA of
- true -> true;
- _ -> MAA
- end,
- ALCU ++ (MALCU -- ALCU),
- case ChkSup of
- true -> true;
- _ -> MChkSup
- end,
- [BadArgZero|MBadArgZero]}.
-
-need_mem_info(Type) when Type == total;
- Type == system ->
- {true, ?ALL_NEEDED_ALLOCS, false, false};
-need_mem_info(Type) when Type == processes;
- Type == processes_used ->
- {true, [eheap_alloc, fix_alloc], true, false};
-need_mem_info(Type) when Type == atom;
- Type == atom_used;
- Type == code ->
- {true, [], true, false};
-need_mem_info(binary) ->
- {false, [binary_alloc], true, false};
-need_mem_info(ets) ->
- {true, [ets_alloc], true, false};
-need_mem_info(_) ->
- {false, [], false, true}.
+memory_1([Type | Types], Mem) ->
+ [{Type, get_memval(Type, Mem)} | memory_1(Types, Mem)];
+memory_1([], _Mem) ->
+ [].
get_memval(total, #memory{total = V}) -> V;
get_memval(processes, #memory{processes = V}) -> V;
@@ -3699,16 +3686,7 @@ get_memval(atom_used, #memory{atom_used = V}) -> V;
get_memval(binary, #memory{binary = V}) -> V;
get_memval(code, #memory{code = V}) -> V;
get_memval(ets, #memory{ets = V}) -> V;
-get_memval(_, #memory{}) -> 0.
-
-memory_is_supported() ->
- {_, _, FeatureList, _} = erlang:system_info(allocator),
- case ((erlang:system_info(alloc_util_allocators)
- -- ?CARRIER_ALLOCS)
- -- FeatureList) of
- [] -> true;
- _ -> false
- end.
+get_memval(_, #memory{}) -> erlang:error(badarg).
get_blocks_size([{blocks_size, Sz, _, _} | Rest], Acc) ->
get_blocks_size(Rest, Acc+Sz);
@@ -3719,19 +3697,9 @@ get_blocks_size([_ | Rest], Acc) ->
get_blocks_size([], Acc) ->
Acc.
-
-blocks_size([{Carriers, SizeList} | Rest], Acc) when Carriers == mbcs;
- Carriers == mbcs_pool;
- Carriers == sbcs ->
- blocks_size(Rest, get_blocks_size(SizeList, Acc));
-blocks_size([_ | Rest], Acc) ->
- blocks_size(Rest, Acc);
-blocks_size([], Acc) ->
- Acc.
-
get_fix_proc([{ProcType, A1, U1}| Rest], {A0, U0}) when ProcType == proc;
- ProcType == monitor_sh;
- ProcType == nlink_sh;
+ ProcType == monitor;
+ ProcType == link;
ProcType == msg_ref;
ProcType == ll_ptimer;
ProcType == hl_ptimer;
@@ -3753,64 +3721,78 @@ fix_proc([_ | Rest], Acc) ->
fix_proc([], Acc) ->
Acc.
+au_mem_fix(#memory{ processes = Proc,
+ processes_used = ProcU,
+ system = Sys } = Mem, Data) ->
+ case fix_proc(Data, {0, 0}) of
+ {A, U} ->
+ Mem#memory{ processes = Proc+A,
+ processes_used = ProcU+U,
+ system = Sys-A };
+ {Mask, A, U} ->
+ Mem#memory{ processes = Mask band (Proc+A),
+ processes_used = Mask band (ProcU+U),
+ system = Mask band (Sys-A) }
+ end.
+
+au_mem_acc(#memory{ total = Tot,
+ processes = Proc,
+ processes_used = ProcU } = Mem,
+ eheap_alloc, Data) ->
+ Sz = get_blocks_size(Data, 0),
+ Mem#memory{ total = Tot+Sz,
+ processes = Proc+Sz,
+ processes_used = ProcU+Sz};
+au_mem_acc(#memory{ total = Tot,
+ system = Sys,
+ ets = Ets } = Mem, ets_alloc, Data) ->
+ Sz = get_blocks_size(Data, 0),
+ Mem#memory{ total = Tot+Sz,
+ system = Sys+Sz,
+ ets = Ets+Sz };
+au_mem_acc(#memory{total = Tot,
+ system = Sys,
+ binary = Bin } = Mem,
+ binary_alloc, Data) ->
+ Sz = get_blocks_size(Data, 0),
+ Mem#memory{ total = Tot+Sz,
+ system = Sys+Sz,
+ binary = Bin+Sz};
+au_mem_acc(#memory{ total = Tot,
+ system = Sys } = Mem,
+ _Type, Data) ->
+ Sz = get_blocks_size(Data, 0),
+ Mem#memory{ total = Tot+Sz,
+ system = Sys+Sz }.
+
+au_mem_foreign(Mem, [{Type, SizeList} | Rest]) ->
+ au_mem_foreign(au_mem_acc(Mem, Type, SizeList), Rest);
+au_mem_foreign(Mem, []) ->
+ Mem.
+
+au_mem_current(Mem0, Type, [{mbcs_pool, MBCS} | Rest]) ->
+ [Foreign] = [Foreign || {foreign_blocks, Foreign} <- MBCS],
+ SizeList = MBCS -- [Foreign],
+ Mem = au_mem_foreign(Mem0, Foreign),
+ au_mem_current(au_mem_acc(Mem, Type, SizeList), Type, Rest);
+au_mem_current(Mem, Type, [{mbcs, SizeList} | Rest]) ->
+ au_mem_current(au_mem_acc(Mem, Type, SizeList), Type, Rest);
+au_mem_current(Mem, Type, [{sbcs, SizeList} | Rest]) ->
+ au_mem_current(au_mem_acc(Mem, Type, SizeList), Type, Rest);
+au_mem_current(Mem, Type, [_ | Rest]) ->
+ au_mem_current(Mem, Type, Rest);
+au_mem_current(Mem, _Type, []) ->
+ Mem.
+
au_mem_data(notsup, _) ->
notsup;
au_mem_data(_, [{_, false} | _]) ->
notsup;
-au_mem_data(#memory{total = Tot,
- processes = Proc,
- processes_used = ProcU} = Mem,
- [{eheap_alloc, _, Data} | Rest]) ->
- Sz = blocks_size(Data, 0),
- au_mem_data(Mem#memory{total = Tot+Sz,
- processes = Proc+Sz,
- processes_used = ProcU+Sz},
- Rest);
-au_mem_data(#memory{total = Tot,
- system = Sys,
- ets = Ets} = Mem,
- [{ets_alloc, _, Data} | Rest]) ->
- Sz = blocks_size(Data, 0),
- au_mem_data(Mem#memory{total = Tot+Sz,
- system = Sys+Sz,
- ets = Ets+Sz},
- Rest);
-au_mem_data(#memory{total = Tot,
- system = Sys,
- binary = Bin} = Mem,
- [{binary_alloc, _, Data} | Rest]) ->
- Sz = blocks_size(Data, 0),
- au_mem_data(Mem#memory{total = Tot+Sz,
- system = Sys+Sz,
- binary = Bin+Sz},
- Rest);
-au_mem_data(#memory{total = Tot,
- processes = Proc,
- processes_used = ProcU,
- system = Sys} = Mem,
- [{fix_alloc, _, Data} | Rest]) ->
- Sz = blocks_size(Data, 0),
- case fix_proc(Data, {0, 0}) of
- {A, U} ->
- au_mem_data(Mem#memory{total = Tot+Sz,
- processes = Proc+A,
- processes_used = ProcU+U,
- system = Sys+Sz-A},
- Rest);
- {Mask, A, U} ->
- au_mem_data(Mem#memory{total = Tot+Sz,
- processes = Mask band (Proc+A),
- processes_used = Mask band (ProcU+U),
- system = Mask band (Sys+Sz-A)},
- Rest)
- end;
-au_mem_data(#memory{total = Tot,
- system = Sys} = Mem,
- [{_, _, Data} | Rest]) ->
- Sz = blocks_size(Data, 0),
- au_mem_data(Mem#memory{total = Tot+Sz,
- system = Sys+Sz},
- Rest);
+au_mem_data(#memory{} = Mem0, [{fix_alloc, _, Data} | Rest]) ->
+ Mem = au_mem_fix(Mem0, Data),
+ au_mem_data(au_mem_current(Mem, fix_alloc, Data), Rest);
+au_mem_data(#memory{} = Mem, [{Type, _, Data} | Rest]) ->
+ au_mem_data(au_mem_current(Mem, Type, Data), Rest);
au_mem_data(EMD, []) ->
EMD.
@@ -3855,7 +3837,6 @@ aa_mem_data(#memory{processes = Proc,
processes_used = ProcU,
system = Sys} = Mem,
[{ProcData, Sz} | Rest]) when ProcData == bif_timer;
- ProcData == link_lh;
ProcData == process_table ->
aa_mem_data(Mem#memory{processes = Proc+Sz,
processes_used = ProcU+Sz,
diff --git a/erts/preloaded/src/erts.app.src b/erts/preloaded/src/erts.app.src
index 338f168158..1ccc4988c2 100644
--- a/erts/preloaded/src/erts.app.src
+++ b/erts/preloaded/src/erts.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/preloaded/src/erts_code_purger.erl b/erts/preloaded/src/erts_code_purger.erl
index fd214228c7..c41532ed87 100644
--- a/erts/preloaded/src/erts_code_purger.erl
+++ b/erts/preloaded/src/erts_code_purger.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2016. All Rights Reserved.
+%% Copyright Ericsson AB 2016-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@
-export([start/0, purge/1, soft_purge/1, pending_purge_lambda/3,
finish_after_on_load/2]).
--spec start() -> term().
+-spec start() -> no_return().
start() ->
register(erts_code_purger, self()),
process_flag(trap_exit, true),
diff --git a/erts/preloaded/src/erts_dirty_process_signal_handler.erl b/erts/preloaded/src/erts_dirty_process_signal_handler.erl
index ab71790b9d..381f81ef14 100644
--- a/erts/preloaded/src/erts_dirty_process_signal_handler.erl
+++ b/erts/preloaded/src/erts_dirty_process_signal_handler.erl
@@ -50,10 +50,12 @@ handle_request(Pid) when is_pid(Pid) ->
handle_incoming_signals(Pid, 0);
handle_request({Requester, Target, Prio,
{SysTaskOp, ReqId, Arg} = Op} = Request) ->
- case handle_sys_task(Requester, Target, SysTaskOp, ReqId, Arg) of
- true ->
+ case handle_sys_task(Requester, Target, SysTaskOp, ReqId, Arg, 0) of
+ done ->
ok;
- false ->
+ busy ->
+ self() ! Request;
+ normal ->
%% Target has stopped executing dirty since the
%% initial request was made. Dispatch the
%% request to target and let it handle it itself...
@@ -83,15 +85,19 @@ handle_incoming_signals(Pid, N) ->
_Res -> ok
end.
-handle_sys_task(Requester, Target, check_process_code, ReqId, Module) ->
- case erts_internal:is_process_executing_dirty(Target) of
- false ->
- false;
- true ->
- _ = check_process(Requester, Target, ReqId, Module),
- true
+handle_sys_task(Requester, Target, check_process_code, ReqId, Module, N) ->
+ case erts_internal:check_dirty_process_code(Target, Module) of
+ Bool when Bool == true; Bool == false ->
+ Requester ! {check_process_code, ReqId, Bool},
+ done;
+ busy ->
+ case N > 5 of
+ true ->
+ busy;
+ false ->
+ handle_sys_task(Requester, Target, check_process_code,
+ ReqId, Module, N+1)
+ end;
+ Res ->
+ Res
end.
-
-check_process(Requester, Target, ReqId, Module) ->
- Result = erts_internal:check_dirty_process_code(Target, Module),
- Requester ! {check_process_code, ReqId, Result}.
diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl
index 79169b7d23..88f47e917b 100644
--- a/erts/preloaded/src/erts_internal.erl
+++ b/erts/preloaded/src/erts_internal.erl
@@ -82,6 +82,14 @@
-export([gather_alloc_histograms/1, gather_carrier_info/1]).
+-export([suspend_process/2]).
+
+-export([process_display/2]).
+
+-export([process_flag/3]).
+
+-export([create_dist_channel/4]).
+
%%
%% Await result of send to port
%%
@@ -303,7 +311,8 @@ get_cpc_opts([{allow_gc, AllowGC} | Options], Async) when AllowGC == true;
get_cpc_opts([], Async) ->
Async.
--spec check_dirty_process_code(Pid,Module) -> 'true' | 'false' when
+-spec check_dirty_process_code(Pid, Module) -> Result when
+ Result :: boolean() | 'normal' | 'busy',
Pid :: pid(),
Module :: module().
check_dirty_process_code(_Pid,_Module) ->
@@ -644,3 +653,41 @@ gather_alloc_histograms(_) ->
gather_carrier_info(_) ->
erlang:nif_error(undef).
+
+-spec suspend_process(Suspendee, OptList) -> Result when
+ Result :: boolean() | 'badarg' | reference(),
+ Suspendee :: pid(),
+ OptList :: [Opt],
+ Opt :: unless_suspending | asynchronous | {asynchronous, term()}.
+
+suspend_process(_Suspendee, _OptList) ->
+ erlang:nif_error(undefined).
+
+%% process_display/2
+-spec process_display(Pid, Type) -> 'true' | 'badarg' | reference() when
+ Pid :: pid(),
+ Type :: backtrace.
+process_display(_Pid, _Type) ->
+ erlang:nif_error(undefined).
+
+%% process_flag/3
+-spec process_flag(Pid, Flag, Value) -> OldValue | 'badarg' | reference() when
+ Pid :: pid(),
+ Flag :: save_calls,
+ Value :: non_neg_integer(),
+ OldValue :: non_neg_integer().
+process_flag(_Pid, _Flag, _Value) ->
+ erlang:nif_error(undefined).
+
+-spec create_dist_channel(Node, DistCtrlr, Flags, Ver) -> Result when
+ Node :: atom(),
+ DistCtrlr :: port() | pid(),
+ Flags :: integer(),
+ Ver :: integer(),
+ Result :: {'ok', erlang:dist_handle()}
+ | {'message', reference()}
+ | 'badarg'
+ | 'system_limit'.
+
+create_dist_channel(_Node, _DistCtrlr, _Flags, _Ver) ->
+ erlang:nif_error(undefined).
diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl
index 9e3de87e08..253fcf7a1f 100644
--- a/erts/preloaded/src/init.erl
+++ b/erts/preloaded/src/init.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl
index 558a0f883f..517ca74301 100644
--- a/erts/preloaded/src/prim_file.erl
+++ b/erts/preloaded/src/prim_file.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -562,7 +562,7 @@ list_dir_convert([RawName | Rest], SkipInvalid, Result) ->
logger ! {log,warning,"Non-unicode filename ~p ignored\n", [RawName],
#{pid=>self(),
gl=>group_leader(),
- time=>erlang:monotonic_time(microsecond),
+ time=>erlang:system_time(microsecond),
error_logger=>#{tag=>warning_msg}}},
list_dir_convert(Rest, SkipInvalid, Result);
{error, _} ->
@@ -580,15 +580,20 @@ read_link_info(Name, Opts) ->
read_info_1(Name, 0, proplist_get_value(time, Opts, local)).
read_info_1(Name, FollowLinks, TimeType) ->
- try read_info_nif(encode_path(Name), FollowLinks) of
- {error, Reason} -> {error, Reason};
- FileInfo ->
- CTime = from_posix_seconds(FileInfo#file_info.ctime, TimeType),
- MTime = from_posix_seconds(FileInfo#file_info.mtime, TimeType),
- ATime = from_posix_seconds(FileInfo#file_info.atime, TimeType),
- {ok, FileInfo#file_info{ ctime = CTime, mtime = MTime, atime = ATime }}
+ try
+ case read_info_nif(encode_path(Name), FollowLinks) of
+ {error, Reason} ->
+ {error, Reason};
+ FileInfo ->
+ CTime = from_posix_seconds(FileInfo#file_info.ctime, TimeType),
+ MTime = from_posix_seconds(FileInfo#file_info.mtime, TimeType),
+ ATime = from_posix_seconds(FileInfo#file_info.atime, TimeType),
+ {ok, FileInfo#file_info{ ctime = CTime,
+ mtime = MTime,
+ atime = ATime }}
+ end
catch
- error:badarg -> {error, badarg}
+ error:_ -> {error, badarg}
end.
write_file_info(Filename, Info) ->
diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl
index 2a3605260d..bcb54cca42 100644
--- a/erts/preloaded/src/prim_inet.erl
+++ b/erts/preloaded/src/prim_inet.erl
@@ -1557,7 +1557,7 @@ type_opt_1(O) when is_atom(O) -> undefined.
%% Get. No supplied value.
type_value(get, undefined) -> false; % Undefined type
-%% These two clauses can not happen since they are only used
+%% These two clauses cannot happen since they are only used
%% in record fields - from record fields they must have a
%% value though it might be 'undefined', so record fields
%% calls type_value/3, not type_value/2.
@@ -1723,7 +1723,7 @@ type_value_2(_, _) -> false.
%% Get. No supplied value.
%%
-%% These two clauses can not happen since they are only used
+%% These two clauses cannot happen since they are only used
%% in record fields - from record fields they must have a
%% value though it might be 'undefined', so record fields
%% calls enc_value/3, not enc_value/2.
diff --git a/erts/preloaded/src/prim_zip.erl b/erts/preloaded/src/prim_zip.erl
index 5cc15b7acd..ca5cfec0e3 100644
--- a/erts/preloaded/src/prim_zip.erl
+++ b/erts/preloaded/src/prim_zip.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/preloaded/src/zlib.erl b/erts/preloaded/src/zlib.erl
index a4ef42204d..6f53e67901 100644
--- a/erts/preloaded/src/zlib.erl
+++ b/erts/preloaded/src/zlib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -87,7 +87,7 @@
%%------------------------------------------------------------------------
%% Public data types.
--type zstream() :: term().
+-type zstream() :: reference().
-type zflush() :: 'none' | 'sync' | 'full' | 'finish'.
-type zlevel() ::
@@ -102,11 +102,11 @@
-type zmethod() :: 'deflated'.
-record(zlib_opts, {
- stream :: zstream(),
- method :: term(),
- input_chunk_size :: integer(),
- output_chunk_size :: integer(),
- flush :: integer()
+ stream :: zstream() | 'undefined',
+ method :: function(),
+ input_chunk_size :: pos_integer(),
+ output_chunk_size :: pos_integer(),
+ flush :: non_neg_integer()
}).
%%------------------------------------------------------------------------
@@ -168,7 +168,7 @@ deflateInit_nif(_Z, _Level, _Method, _WindowBits, _MemLevel, _Strategy) ->
-spec deflateSetDictionary(Z, Dictionary) -> Adler32 when
Z :: zstream(),
Dictionary :: iodata(),
- Adler32 :: integer().
+ Adler32 :: non_neg_integer().
deflateSetDictionary(Z, Dictionary) ->
deflateSetDictionary_nif(Z, Dictionary).
deflateSetDictionary_nif(_Z, _Dictionary) ->
@@ -295,7 +295,7 @@ inflate(Z, Data) ->
Options :: list({exception_on_need_dict, boolean()}),
Decompressed :: iolist() |
{need_dictionary,
- Adler32 :: integer(),
+ Adler32 :: non_neg_integer(),
Output :: iolist()}.
inflate(Z, Data, Options) ->
enqueue_input(Z, Data),
@@ -357,7 +357,7 @@ exception_on_need_dict(Z, Output) when is_list(Output); is_binary(Output) ->
Result :: {continue, Output :: iolist()} |
{finished, Output :: iolist()} |
{need_dictionary,
- Adler32 :: integer(),
+ Adler32 :: non_neg_integer(),
Output :: iolist()}.
safeInflate(Z, Data) ->
enqueue_input(Z, Data),
@@ -389,7 +389,7 @@ getBufSize_nif(_Z) ->
-spec crc32(Z) -> CRC when
Z :: zstream(),
- CRC :: integer().
+ CRC :: non_neg_integer().
crc32(Z) ->
crc32_nif(Z).
crc32_nif(_Z) ->
@@ -398,7 +398,7 @@ crc32_nif(_Z) ->
-spec crc32(Z, Data) -> CRC when
Z :: zstream(),
Data :: iodata(),
- CRC :: integer().
+ CRC :: non_neg_integer().
crc32(Z, Data) when is_reference(Z) ->
erlang:crc32(Data);
crc32(_Z, _Data) ->
@@ -406,9 +406,9 @@ crc32(_Z, _Data) ->
-spec crc32(Z, PrevCRC, Data) -> CRC when
Z :: zstream(),
- PrevCRC :: integer(),
+ PrevCRC :: non_neg_integer(),
Data :: iodata(),
- CRC :: integer().
+ CRC :: non_neg_integer().
crc32(Z, CRC, Data) when is_reference(Z) ->
erlang:crc32(CRC, Data);
crc32(_Z, _CRC, _Data) ->
@@ -416,10 +416,10 @@ crc32(_Z, _CRC, _Data) ->
-spec crc32_combine(Z, CRC1, CRC2, Size2) -> CRC when
Z :: zstream(),
- CRC :: integer(),
- CRC1 :: integer(),
- CRC2 :: integer(),
- Size2 :: integer().
+ CRC :: non_neg_integer(),
+ CRC1 :: non_neg_integer(),
+ CRC2 :: non_neg_integer(),
+ Size2 :: non_neg_integer().
crc32_combine(Z, CRC1, CRC2, Size2) when is_reference(Z) ->
erlang:crc32_combine(CRC1, CRC2, Size2);
crc32_combine(_Z, _CRC1, _CRC2, _Size2) ->
@@ -428,7 +428,7 @@ crc32_combine(_Z, _CRC1, _CRC2, _Size2) ->
-spec adler32(Z, Data) -> CheckSum when
Z :: zstream(),
Data :: iodata(),
- CheckSum :: integer().
+ CheckSum :: non_neg_integer().
adler32(Z, Data) when is_reference(Z) ->
erlang:adler32(Data);
adler32(_Z, _Data) ->
@@ -436,9 +436,9 @@ adler32(_Z, _Data) ->
-spec adler32(Z, PrevAdler, Data) -> CheckSum when
Z :: zstream(),
- PrevAdler :: integer(),
+ PrevAdler :: non_neg_integer(),
Data :: iodata(),
- CheckSum :: integer().
+ CheckSum :: non_neg_integer().
adler32(Z, Adler, Data) when is_reference(Z) ->
erlang:adler32(Adler, Data);
adler32(_Z, _Adler, _Data) ->
@@ -446,10 +446,10 @@ adler32(_Z, _Adler, _Data) ->
-spec adler32_combine(Z, Adler1, Adler2, Size2) -> Adler when
Z :: zstream(),
- Adler :: integer(),
- Adler1 :: integer(),
- Adler2 :: integer(),
- Size2 :: integer().
+ Adler :: non_neg_integer(),
+ Adler1 :: non_neg_integer(),
+ Adler2 :: non_neg_integer(),
+ Size2 :: non_neg_integer().
adler32_combine(Z, Adler1, Adler2, Size2) when is_reference(Z) ->
erlang:adler32_combine(Adler1, Adler2, Size2);
adler32_combine(_Z, _Adler1, _Adler2, _Size2) ->
diff --git a/erts/test/erlc_SUITE.erl b/erts/test/erlc_SUITE.erl
index 394ecc8964..0c5b9f8358 100644
--- a/erts/test/erlc_SUITE.erl
+++ b/erts/test/erlc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -505,7 +505,7 @@ run_command(Dir, {win32, _}, Cmd) ->
{BatchFile,
Run,
["@echo off\r\n",
- "set ERLC_EMULATOR=", atom_to_list(lib:progname()), "\r\n",
+ "set ERLC_EMULATOR=", ct:get_progname(), "\r\n",
Cmd, "\r\n",
"if errorlevel 1 echo _ERROR_\r\n",
"if not errorlevel 1 echo _OK_\r\n"]};
@@ -514,7 +514,7 @@ run_command(Dir, {unix, _}, Cmd) ->
{Name,
"/bin/sh " ++ Name,
["#!/bin/sh\n",
- "ERLC_EMULATOR='", atom_to_list(lib:progname()), "'\n",
+ "ERLC_EMULATOR='", ct:get_progname(), "'\n",
"export ERLC_EMULATOR\n",
Cmd, "\n",
"case $? in\n",
diff --git a/erts/test/erlexec_SUITE.erl b/erts/test/erlexec_SUITE.erl
index 73ed0ac56a..602dc5ce2e 100644
--- a/erts/test/erlexec_SUITE.erl
+++ b/erts/test/erlexec_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/test/nt_SUITE.erl b/erts/test/nt_SUITE.erl
index 3081b58835..b2a0445ec1 100644
--- a/erts/test/nt_SUITE.erl
+++ b/erts/test/nt_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/test/otp_SUITE.erl b/erts/test/otp_SUITE.erl
index 3abe45c141..2372e8b9ac 100644
--- a/erts/test/otp_SUITE.erl
+++ b/erts/test/otp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/test/run_erl_SUITE.erl b/erts/test/run_erl_SUITE.erl
index 08edd930b4..7c6f58a93a 100644
--- a/erts/test/run_erl_SUITE.erl
+++ b/erts/test/run_erl_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/test/upgrade_SUITE.erl b/erts/test/upgrade_SUITE.erl
index 73d221cfab..f92c25bdb4 100644
--- a/erts/test/upgrade_SUITE.erl
+++ b/erts/test/upgrade_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2014-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@
-define(upgr_sname,otp_upgrade).
-%% Applications that are excluded from this test because they can not
+%% Applications that are excluded from this test because they cannot
%% just be started in a new node with out specific configuration.
-define(start_exclude,
[cosEvent,cosEventDomain,cosFileTransfer,cosNotification,
diff --git a/erts/test/z_SUITE.erl b/erts/test/z_SUITE.erl
index bb1afecafc..6a34299dd2 100644
--- a/erts/test/z_SUITE.erl
+++ b/erts/test/z_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/erts/vsn.mk b/erts/vsn.mk
index 25acd9cc34..c0444fa483 100644
--- a/erts/vsn.mk
+++ b/erts/vsn.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2017. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@
# %CopyrightEnd%
#
-VSN = 9.3.1
+VSN = 10.0.5
# Port number 4365 in 4.2
# Port number 4366 in 4.3
diff --git a/lib/Makefile b/lib/Makefile
index 0053238826..cdb3f3f3dc 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -58,7 +58,7 @@ else
SUB_DIRECTORIES = hipe parsetools asn1/src
else
ifdef TERTIARY_BOOTSTRAP
- SUB_DIRECTORIES = snmp sasl jinterface ic syntax_tools wx
+ SUB_DIRECTORIES = snmp sasl jinterface syntax_tools wx
else
ifdef DOC_BOOTSTRAP
SUB_DIRECTORIES = xmerl edoc erl_docgen
diff --git a/lib/asn1/c_src/asn1_erl_nif.c b/lib/asn1/c_src/asn1_erl_nif.c
index d5aaadb89b..797be6d4f8 100644
--- a/lib/asn1/c_src/asn1_erl_nif.c
+++ b/lib/asn1/c_src/asn1_erl_nif.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2002-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -949,6 +949,12 @@ static int ber_decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *
unsigned char *tmp_out_buff;
ERL_NIF_TERM term = 0, curr_head = 0;
+ /* Recursion depth limitation, borrow a signed int: maybe_ret */
+ maybe_ret = (int) (ErlNifSInt) ((char *)value - (char *)ib_index);
+ maybe_ret = maybe_ret < 0 ? -maybe_ret : maybe_ret;
+ if (maybe_ret >= sizeof(void *) * 8192) /* 8 k pointer words */
+ return ASN1_ERROR;
+
if (((in_buf[*ib_index]) & 0x80) == ASN1_SHORT_DEFINITE_LENGTH) {
len = in_buf[*ib_index];
} else if (in_buf[*ib_index] == ASN1_INDEFINITE_LENGTH) {
@@ -993,7 +999,7 @@ static int ber_decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *
while (*ib_index < end_index) {
if ((maybe_ret = ber_decode(env, &term, in_buf, ib_index,
- in_buf_len)) <= ASN1_ERROR
+ *ib_index + len)) <= ASN1_ERROR
)
return maybe_ret;
curr_head = enif_make_list_cell(env, term, curr_head);
diff --git a/lib/asn1/doc/src/Makefile b/lib/asn1/doc/src/Makefile
index 2b5d9467d9..9c0d865884 100644
--- a/lib/asn1/doc/src/Makefile
+++ b/lib/asn1/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -107,6 +107,7 @@ html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f $(GEN_XML) errs core *~
diff --git a/lib/asn1/doc/src/notes.xml b/lib/asn1/doc/src/notes.xml
index bb15c9ff5f..c86fa79c2c 100644
--- a/lib/asn1/doc/src/notes.xml
+++ b/lib/asn1/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,43 @@
<p>This document describes the changes made to the asn1 application.</p>
+<section><title>Asn1 5.0.6</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Update to use the new string api instead of the old.</p>
+ <p>
+ Own Id: OTP-15036</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Asn1 5.0.5.1</title>
+
+ <section><title>Known Bugs and Problems</title>
+ <list>
+ <item>
+ <p>A bug in ASN.1 BER decoding has been fixed. When
+ decoding a recursively enclosed term the length was not
+ propagated to that term decoding, so if the length of the
+ enclosed term was longer than the enclosing that error
+ was not dectected</p> <p>A hard coded C stack limitation
+ for decoding recursive ASN.1 terms has been introduced.
+ This is currently set to 8 kWords giving a nesting depth
+ of about 1000 levels. Deeper terms can not be decoded,
+ which should not be much of a real world limitation.</p>
+ <p>
+ Own Id: OTP-14440 Aux Id: ERIERL-220 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Asn1 5.0.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/asn1/src/asn1ct.erl b/lib/asn1/src/asn1ct.erl
index e9e9f6eb42..cd50d30aa8 100644
--- a/lib/asn1/src/asn1ct.erl
+++ b/lib/asn1/src/asn1ct.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl
index 321980e5e4..9ec0d93e93 100644
--- a/lib/asn1/src/asn1ct_check.erl
+++ b/lib/asn1/src/asn1ct_check.erl
@@ -5770,7 +5770,7 @@ format_error({missing_ocft,Component}) ->
format_error(multiple_uniqs) ->
"implementation limitation: only one UNIQUE field is allowed in CLASS";
format_error({namelist_redefinition,Name}) ->
- io_lib:format("the name '~s' can not be redefined", [Name]);
+ io_lib:format("the name '~s' cannot be redefined", [Name]);
format_error({param_bad_type, Ref}) ->
io_lib:format("'~p' is not a parameterized type", [Ref]);
format_error(param_wrong_number_of_arguments) ->
diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl
index ee039dfbab..28836ff264 100644
--- a/lib/asn1/src/asn1ct_gen.erl
+++ b/lib/asn1/src/asn1ct_gen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/asn1/src/asn1rtt_real_common.erl b/lib/asn1/src/asn1rtt_real_common.erl
index 81c1f54d74..0d53447eb7 100644
--- a/lib/asn1/src/asn1rtt_real_common.erl
+++ b/lib/asn1/src/asn1rtt_real_common.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl
index 8cf6745103..5506923341 100644
--- a/lib/asn1/test/asn1_SUITE.erl
+++ b/lib/asn1/test/asn1_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -132,7 +132,8 @@ groups() ->
testSeq2738,
% Uses 'Constructed'
{group, [], [constructed,
- ber_decode_error]},
+ ber_decode_error,
+ otp_14440]},
testSeqSetIndefinite,
testChoiceIndefinite,
per_open_type,
@@ -736,6 +737,36 @@ ber_decode_error(Config, Rule, Opts) ->
asn1_test_lib:compile("Constructed", Config, [Rule|Opts]),
ber_decode_error:run(Opts).
+otp_14440(_Config) ->
+ Args = " -pa \"" ++ filename:dirname(code:which(?MODULE)) ++ "\"",
+ {ok,N} = slave:start(hostname(), otp_14440, Args),
+ Result = rpc:call(N, ?MODULE, otp_14440_decode, []),
+ io:format("Decode result = ~p~n", [Result]),
+ case Result of
+ {exit,{error,{asn1,{invalid_value,5}}}} ->
+ ok = slave:stop(N);
+ %% We get this if stack depth limit kicks in:
+ {exit,{error,{asn1,{unknown,_}}}} ->
+ ok = slave:stop(N);
+ _ ->
+ _ = slave:stop(N),
+ ?t:fail(Result)
+ end.
+%%
+otp_14440_decode() ->
+ Data =
+ iolist_to_binary(
+ lists:duplicate(
+ 32, list_to_binary(lists:duplicate(1024, 16#7f)))),
+ try asn1rt_nif:decode_ber_tlv(Data) of
+ Result ->
+ {unexpected_return,Result}
+ catch
+ Class:Reason ->
+ {Class,Reason}
+ end.
+
+
h323test(Config) -> test(Config, fun h323test/3).
h323test(Config, Rule, Opts) ->
Files = ["H235-SECURITY-MESSAGES", "H323-MESSAGES",
@@ -1350,7 +1381,7 @@ xref_export_all(_Config) ->
{ok,_} = xref:q(S, Def),
{ok,Unused} = xref:q(S, "X - Called - range (closure E | Called)"),
xref:stop(S),
- case Unused of
+ case Unused -- [{?MODULE,otp_14440_decode,0}] of
[] ->
ok;
[_|_] ->
@@ -1385,3 +1416,11 @@ all_called_1([F|T]) when is_atom(F) ->
L ++ all_called_1(T);
all_called_1([]) ->
[].
+
+hostname() ->
+ hostname(atom_to_list(node())).
+
+hostname([$@ | Hostname]) ->
+ list_to_atom(Hostname);
+hostname([_C | Cs]) ->
+ hostname(Cs).
diff --git a/lib/asn1/test/asn1_SUITE_data/IN-CS-1-Datatypes.asn b/lib/asn1/test/asn1_SUITE_data/IN-CS-1-Datatypes.asn
index ff0361f5c5..fb092f3f9c 100644
--- a/lib/asn1/test/asn1_SUITE_data/IN-CS-1-Datatypes.asn
+++ b/lib/asn1/test/asn1_SUITE_data/IN-CS-1-Datatypes.asn
@@ -1152,7 +1152,7 @@ FilteringCriteria ::= CHOICE {
-- In case calledAddressValue is specified, the numbers to be filtered are from calledAddressValue
-- up to and including calledAddressValue + maximumNumberOfCounters-1.
--- The last two digits of calledAddressvalue can not exceed 100-maximumNumberOfCounters.
+-- The last two digits of calledAddressvalue cannot exceed 100-maximumNumberOfCounters.
FilteringTimeOut ::= CHOICE {
duration [0] Duration,
stopTime [1] DateAndTime
diff --git a/lib/asn1/test/testUniqueObjectSets.erl b/lib/asn1/test/testUniqueObjectSets.erl
index c75a673c4b..0c61da96a1 100644
--- a/lib/asn1/test/testUniqueObjectSets.erl
+++ b/lib/asn1/test/testUniqueObjectSets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2014-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/asn1/test/test_modified_x420.erl b/lib/asn1/test/test_modified_x420.erl
index 15f7c70978..a4b335026d 100644
--- a/lib/asn1/test/test_modified_x420.erl
+++ b/lib/asn1/test/test_modified_x420.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/asn1/vsn.mk b/lib/asn1/vsn.mk
index 39dfe8f4fb..30cbca3773 100644
--- a/lib/asn1/vsn.mk
+++ b/lib/asn1/vsn.mk
@@ -1 +1 @@
-ASN1_VSN = 5.0.5
+ASN1_VSN = 5.0.6
diff --git a/lib/common_test/doc/src/Makefile b/lib/common_test/doc/src/Makefile
index 293ef591cb..4d6161d3ae 100644
--- a/lib/common_test/doc/src/Makefile
+++ b/lib/common_test/doc/src/Makefile
@@ -140,6 +140,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN1DIR)/*
rm -f $(MAN3DIR)/*
rm -f $(MAN6DIR)/*
diff --git a/lib/common_test/doc/src/ct.xml b/lib/common_test/doc/src/ct.xml
index afd8741cd1..c0380c4142 100644
--- a/lib/common_test/doc/src/ct.xml
+++ b/lib/common_test/doc/src/ct.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2010</year><year>2017</year>
+ <year>2010</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -572,6 +572,16 @@
</func>
<func>
+ <name>get_progname() -&gt; string()</name>
+ <fsummary>Returns the command used to start this Erlang instance.</fsummary>
+ <desc><marker id="get_progname-0"/>
+ <p>Returns the command used to start this Erlang instance.
+ If this information could not be found, the string
+ <c>"no_prog_name"</c> is returned.</p>
+ </desc>
+ </func>
+
+ <func>
<name>get_status() -&gt; TestStatus | {error, Reason} | no_tests_running</name>
<fsummary>Returns status of ongoing test.</fsummary>
<type>
@@ -1512,7 +1522,7 @@
<v>Hours = integer()</v>
<v>Mins = integer()</v>
<v>Secs = integer()</v>
- <v>Millisecs = integer() | float()</v>
+ <v>Millisecs = integer()</v>
<v>Func = {M, F, A} | function()</v>
<v>M = atom()</v>
<v>F = atom()</v>
diff --git a/lib/common_test/doc/src/ct_ftp.xml b/lib/common_test/doc/src/ct_ftp.xml
index a6f01dd58e..592c5eb05d 100644
--- a/lib/common_test/doc/src/ct_ftp.xml
+++ b/lib/common_test/doc/src/ct_ftp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2010</year><year>2016</year>
+ <year>2010</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/common_test/doc/src/ct_hooks.xml b/lib/common_test/doc/src/ct_hooks.xml
index 954be0ffba..2f853d133d 100644
--- a/lib/common_test/doc/src/ct_hooks.xml
+++ b/lib/common_test/doc/src/ct_hooks.xml
@@ -368,7 +368,7 @@
<seealso marker="common_test#Module:end_per_testcase-2"><c>end_per_testcase</c></seealso>
instead.</p>
- <p>This function can not change the result of the test case by returning skip or fail
+ <p>This function cannot change the result of the test case by returning skip or fail
tuples, but it may insert items in <c>Config</c> that can be read in
<c>end_per_testcase/2</c> or in <c>post_end_per_testcase/5</c>.</p>
diff --git a/lib/common_test/doc/src/ct_hooks_chapter.xml b/lib/common_test/doc/src/ct_hooks_chapter.xml
index 7ecc2e4298..ea4b67be08 100644
--- a/lib/common_test/doc/src/ct_hooks_chapter.xml
+++ b/lib/common_test/doc/src/ct_hooks_chapter.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2011</year><year>2017</year>
+ <year>2011</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -379,7 +379,7 @@
(in Kernel):
</p>
<code>
- %%% @doc Common Test Example Common Test Hook module.
+ %%% Common Test Example Common Test Hook module.
-module(example_cth).
%% Callbacks
@@ -408,51 +408,51 @@
-record(state, { file_handle, total, suite_total, ts, tcs, data }).
- %% @doc Return a unique id for this CTH.
+ %% Return a unique id for this CTH.
id(Opts) ->
proplists:get_value(filename, Opts, "/tmp/file.log").
- %% @doc Always called before any other callback function. Use this to initiate
+ %% Always called before any other callback function. Use this to initiate
%% any common state.
init(Id, Opts) ->
{ok,D} = file:open(Id,[write]),
{ok, #state{ file_handle = D, total = 0, data = [] }}.
- %% @doc Called before init_per_suite is called.
+ %% Called before init_per_suite is called.
pre_init_per_suite(Suite,Config,State) ->
{Config, State#state{ suite_total = 0, tcs = [] }}.
- %% @doc Called after init_per_suite.
+ %% Called after init_per_suite.
post_init_per_suite(Suite,Config,Return,State) ->
{Return, State}.
- %% @doc Called before end_per_suite.
+ %% Called before end_per_suite.
pre_end_per_suite(Suite,Config,State) ->
{Config, State}.
- %% @doc Called after end_per_suite.
+ %% Called after end_per_suite.
post_end_per_suite(Suite,Config,Return,State) ->
Data = {suites, Suite, State#state.suite_total, lists:reverse(State#state.tcs)},
{Return, State#state{ data = [Data | State#state.data] ,
total = State#state.total + State#state.suite_total } }.
- %% @doc Called before each init_per_group.
+ %% Called before each init_per_group.
pre_init_per_group(Suite,Group,Config,State) ->
{Config, State}.
- %% @doc Called after each init_per_group.
+ %% Called after each init_per_group.
post_init_per_group(Suite,Group,Config,Return,State) ->
{Return, State}.
- %% @doc Called before each end_per_group.
+ %% Called before each end_per_group.
pre_end_per_group(Suite,Group,Config,State) ->
{Config, State}.
- %% @doc Called after each end_per_group.
+ %% Called after each end_per_group.
post_end_per_group(Suite,Group,Config,Return,State) ->
{Return, State}.
- %% @doc Called before each init_per_testcase.
+ %% Called before each init_per_testcase.
pre_init_per_testcase(Suite,TC,Config,State) ->
{Config, State#state{ ts = now(), total = State#state.suite_total + 1 } }.
@@ -460,26 +460,26 @@
post_init_per_testcase(Suite,TC,Config,Return,State) ->
{Return, State}
-%% @doc Called before each end_per_testcase (immediately after the test case).
+%% Called before each end_per_testcase (immediately after the test case).
pre_end_per_testcase(Suite,TC,Config,State) ->
{Config, State}.
- %% @doc Called after each end_per_testcase.
+ %% Called after each end_per_testcase.
post_end_per_testcase(Suite,TC,Config,Return,State) ->
TCInfo = {testcase, Suite, TC, Return, timer:now_diff(now(), State#state.ts)},
{Return, State#state{ ts = undefined, tcs = [TCInfo | State#state.tcs] } }.
- %% @doc Called after post_init_per_suite, post_end_per_suite, post_init_per_group,
+ %% Called after post_init_per_suite, post_end_per_suite, post_init_per_group,
%% post_end_per_group and post_end_per_testcase if the suite, group or test case failed.
on_tc_fail(Suite, TC, Reason, State) ->
State.
- %% @doc Called when a test case is skipped by either user action
+ %% Called when a test case is skipped by either user action
%% or due to an init function failing.
on_tc_skip(Suite, TC, Reason, State) ->
State.
- %% @doc Called when the scope of the CTH is done
+ %% Called when the scope of the CTH is done
terminate(State) ->
io:format(State#state.file_handle, "~p.~n",
[{test_run, State#state.total, State#state.data}]),
@@ -501,12 +501,13 @@
<tag><c>cth_log_redirect</c></tag>
<item>
<p>Built-in</p>
- <p>Captures all <c>error_logger</c> and SASL logging
- events and prints them to the current test case log. If an event cannot be
- associated with a test case, it is printed in the <c>Common Test</c> framework log.
+ <p>Captures all log events that would normally be printed by the default
+ logger handler, and prints them to the current test case log.
+ If an event cannot be associated with a test case, it is printed in
+ the <c>Common Test</c> framework log.
This happens for test cases running in parallel and events occuring
in-between test cases. You can configure the level of
- <seealso marker="sasl:sasl_app">SASL</seealso> events report
+ <seealso marker="sasl:sasl_app">SASL</seealso> reports
using the normal SASL mechanisms.</p>
</item>
<tag><c>cth_surefire</c></tag>
diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml
index 7e909b24cd..df22896b27 100644
--- a/lib/common_test/doc/src/notes.xml
+++ b/lib/common_test/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -33,6 +33,28 @@
<file>notes.xml</file>
</header>
+<section><title>Common_Test 1.16</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>Use the compiler option <c>nowarn_export_all</c> to
+ disable <c>export_all</c> warnings when automatically
+ compiling test suites.</p>
+ <p>
+ Own Id: OTP-14810</p>
+ </item>
+ <item>
+ <p>
+ Use uri_string module instead of http_uri.</p>
+ <p>
+ Own Id: OTP-14902</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Common_Test 1.15.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -2067,7 +2089,7 @@
ct_netconfc:close_session sometimes returned
{error,closed} because the ssh connection was closed
(from the server side) before the rpc-reply was received
- by the client. This is normal and can not be helped. It
+ by the client. This is normal and cannot be helped. It
has been corrected so the return will be 'ok' in this
case. Other error situations will still give
{error,Reason}.</p>
@@ -2081,7 +2103,7 @@
{error,{process_down,Pid,normal}} because the ssh
connection was closed (from the server side) before the
rpc-reply was received by the client. This is normal and
- can not be helped. It has been corrected so the return
+ cannot be helped. It has been corrected so the return
will be 'ok' in this situation.</p>
<p>
Own Id: OTP-10570</p>
@@ -2733,8 +2755,8 @@
The info function for <c>init/end_per_suite(Config)</c>
is <c>init/end_per_suite()</c>, and for
<c>init/end_per_group(GroupName,Config)</c> it's
- <c>init/end_per_group(GroupName)</c>. Info functions can
- not be used with <c>init/end_per_testcase(TestCase,
+ <c>init/end_per_group(GroupName)</c>. Info functions
+ cannot be used with <c>init/end_per_testcase(TestCase,
Config)</c>, since these configuration functions execute
on the test case process and will use the same properties
as the test case (i.e. properties set by the test case
@@ -3818,7 +3840,7 @@
If the Erlang runtime system was started without access
to an erlang shell (e.g. -noshell), compilation errors
would cause a crash in the Common Test application.
- Without access to a shell, Common Test can not prompt the
+ Without access to a shell, Common Test cannot prompt the
user to choose to continue or abort the test session, but
must assume that the session should proceed.</p>
<p>
diff --git a/lib/common_test/src/Makefile b/lib/common_test/src/Makefile
index 9adcf2f13b..80eaed70bd 100644
--- a/lib/common_test/src/Makefile
+++ b/lib/common_test/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2016. All Rights Reserved.
+# Copyright Ericsson AB 2003-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/common_test/src/common_test.app.src b/lib/common_test/src/common_test.app.src
index f686003637..efebea896c 100644
--- a/lib/common_test/src/common_test.app.src
+++ b/lib/common_test/src/common_test.app.src
@@ -1,7 +1,7 @@
% This is an -*- erlang -*- file.
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index fd7fa07b81..778ea2e9e2 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,38 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc Main user interface for the Common Test framework.
-%%%
-%%% <p> This module implements the command line interface for running
-%%% tests and some basic functions for common test case issues
-%%% such as configuration and logging. </p>
-%%%
-%%% <p><strong>Test Suite Support Macros</strong></p>
-%%%
-%%% <p>The <c>config</c> macro is defined in <c>ct.hrl</c>. This
-%%% macro should be used to retrieve information from the
-%%% <c>Config</c> variable sent to all test cases. It is used with two
-%%% arguments, where the first is the name of the configuration
-%%% variable you wish to retrieve, and the second is the <c>Config</c>
-%%% variable supplied to the test case.</p>
-%%%
-%%% <p>Possible configuration variables include:</p>
-%%% <ul>
-%%% <li><c>data_dir</c> - Data file directory.</li>
-%%% <li><c>priv_dir</c> - Scratch file directory.</li>
-%%% <li>Whatever added by <c>init_per_suite/1</c> or
-%%% <c>init_per_testcase/2</c> in the test suite.</li>
-%%% </ul>
-
-%%% @type var_name() = atom(). A variable name which is specified when
-%%% <c>ct:require/2</c> is called,
-%%% e.g. <c>ct:require(mynodename,{node,[telnet]})</c>
-%%%
-%%% @type target_name() = var_name(). The name of a target.
-%%%
-%%% @type handle() = ct_gen_conn:handle() | term(). The identity of a
-%%% specific connection.
-
-module(ct).
-include("ct.hrl").
@@ -87,6 +55,7 @@
decrypt_config_file/2, decrypt_config_file/3]).
-export([get_target_name/1]).
+-export([get_progname/0]).
-export([parse_table/1, listenv/1]).
-export([remaining_test_procs/0]).
@@ -120,209 +89,34 @@
%%----------------------------------------------------------------------
-
-%%%-----------------------------------------------------------------
-%%% @spec install(Opts) -> ok | {error,Reason}
-%%% Opts = [Opt]
-%%% Opt = {config,ConfigFiles} | {event_handler,Modules} |
-%%% {decrypt,KeyOrFile}
-%%% ConfigFiles = [ConfigFile]
-%%% ConfigFile = string()
-%%% Modules = [atom()]
-%%% KeyOrFile = {key,Key} | {file,KeyFile}
-%%% Key = string()
-%%% KeyFile = string()
-%%% @doc Install config files and event handlers.
-%%%
-%%% <p>Run this function once before first test.</p>
-%%%
-%%% <p>Example:<br/>
-%%% <c>install([{config,["config_node.ctc","config_user.ctc"]}])</c>.</p>
-%%%
-%%% <p>Note that this function is automatically run by the
-%%% <c>ct_run</c> program.</p>
install(Opts) ->
ct_run:install(Opts).
-%%%-----------------------------------------------------------------
-%%% @spec run(TestDir,Suite,Cases) -> Result
-%%% TestDir = string()
-%%% Suite = atom()
-%%% Cases = atom() | [atom()]
-%%% Result = [TestResult] | {error,Reason}
-%%%
-%%% @doc Run the given test case(s).
-%%%
-%%% <p>Requires that <c>ct:install/1</c> has been run first.</p>
-%%%
-%%% <p>Suites (*_SUITE.erl) files must be stored in
-%%% <c>TestDir</c> or <c>TestDir/test</c>. All suites
-%%% will be compiled when test is run.</p>
run(TestDir,Suite,Cases) ->
ct_run:run(TestDir,Suite,Cases).
-%%%-----------------------------------------------------------------
-%%% @spec run(TestDir,Suite) -> Result
-%%%
-%%% @doc Run all test cases in the given suite.
-%%% @see run/3.
run(TestDir,Suite) ->
ct_run:run(TestDir,Suite).
-%%%-----------------------------------------------------------------
-%%% @spec run(TestDirs) -> Result
-%%% TestDirs = TestDir | [TestDir]
-%%%
-%%% @doc Run all test cases in all suites in the given directories.
-%%% @see run/3.
run(TestDirs) ->
ct_run:run(TestDirs).
-%%%-----------------------------------------------------------------
-%%% @spec run_test(Opts) -> Result
-%%% Opts = [OptTuples]
-%%% OptTuples = {dir,TestDirs} | {suite,Suites} | {group,Groups} |
-%%% {testcase,Cases} | {spec,TestSpecs} | {join_specs,Bool} |
-%%% {label,Label} | {config,CfgFiles} | {userconfig, UserConfig} |
-%%% {allow_user_terms,Bool} | {logdir,LogDir} |
-%%% {silent_connections,Conns} | {stylesheet,CSSFile} |
-%%% {cover,CoverSpecFile} | {cover_stop,Bool} | {step,StepOpts} |
-%%% {event_handler,EventHandlers} | {include,InclDirs} |
-%%% {auto_compile,Bool} | {abort_if_missing_suites,Bool} |
-%%% {create_priv_dir,CreatePrivDir} |
-%%% {multiply_timetraps,M} | {scale_timetraps,Bool} |
-%%% {repeat,N} | {duration,DurTime} | {until,StopTime} |
-%%% {force_stop,ForceStop} | {decrypt,DecryptKeyOrFile} |
-%%% {refresh_logs,LogDir} | {logopts,LogOpts} |
-%%% {verbosity,VLevels} | {basic_html,Bool} |
-%%% {esc_chars,Bool} | {ct_hooks, CTHs} |
-%%% {enable_builtin_hooks,Bool} | {release_shell,Bool}
-%%% TestDirs = [string()] | string()
-%%% Suites = [string()] | [atom()] | string() | atom()
-%%% Cases = [atom()] | atom()
-%%% Groups = GroupNameOrPath | [GroupNameOrPath]
-%%% GroupNameOrPath = [atom()] | atom() | all
-%%% TestSpecs = [string()] | string()
-%%% Label = string() | atom()
-%%% CfgFiles = [string()] | string()
-%%% UserConfig = [{CallbackMod,CfgStrings}] | {CallbackMod,CfgStrings}
-%%% CallbackMod = atom()
-%%% CfgStrings = [string()] | string()
-%%% LogDir = string()
-%%% Conns = all | [atom()]
-%%% CSSFile = string()
-%%% CoverSpecFile = string()
-%%% StepOpts = [StepOpt] | []
-%%% StepOpt = config | keep_inactive
-%%% EventHandlers = EH | [EH]
-%%% EH = atom() | {atom(),InitArgs} | {[atom()],InitArgs}
-%%% InitArgs = [term()]
-%%% InclDirs = [string()] | string()
-%%% CreatePrivDir = auto_per_run | auto_per_tc | manual_per_tc
-%%% M = integer()
-%%% N = integer()
-%%% DurTime = string(HHMMSS)
-%%% StopTime = string(YYMoMoDDHHMMSS) | string(HHMMSS)
-%%% ForceStop = skip_rest | Bool
-%%% DecryptKeyOrFile = {key,DecryptKey} | {file,DecryptFile}
-%%% DecryptKey = string()
-%%% DecryptFile = string()
-%%% LogOpts = [LogOpt]
-%%% LogOpt = no_nl | no_src
-%%% VLevels = VLevel | [{Category,VLevel}]
-%%% VLevel = integer()
-%%% Category = atom()
-%%% CTHs = [CTHModule | {CTHModule, CTHInitArgs}]
-%%% CTHModule = atom()
-%%% CTHInitArgs = term()
-%%% Result = {Ok,Failed,{UserSkipped,AutoSkipped}} | TestRunnerPid | {error,Reason}
-%%% Ok = integer()
-%%% Failed = integer()
-%%% UserSkipped = integer()
-%%% AutoSkipped = integer()
-%%% TestRunnerPid = pid()
-%%% Reason = term()
-%%% @doc <p>Run tests as specified by the combination of options in <c>Opts</c>.
-%%% The options are the same as those used with the
-%%% <seealso marker="ct_run#ct_run"><c>ct_run</c></seealso> program.
-%%% Note that here a <c>TestDir</c> can be used to point out the path to
-%%% a <c>Suite</c>. Note also that the option <c>testcase</c>
-%%% corresponds to the <c>-case</c> option in the <c>ct_run</c>
-%%% program. Configuration files specified in <c>Opts</c> will be
-%%% installed automatically at startup.</p>
-%%% <p><c>TestRunnerPid</c> is returned if <c>release_shell == true</c>
-%%% (see <c>break/1</c> for details).</p>
-%%% <p><c>Reason</c> indicates what type of error has been encountered.</p>
run_test(Opts) ->
ct_run:run_test(Opts).
-%%%-----------------------------------------------------------------
-%%% @spec run_testspec(TestSpec) -> Result
-%%% TestSpec = [term()]
-%%% Result = {Ok,Failed,{UserSkipped,AutoSkipped}} | {error,Reason}
-%%% Ok = integer()
-%%% Failed = integer()
-%%% UserSkipped = integer()
-%%% AutoSkipped = integer()
-%%% Reason = term()
-%%% @doc Run test specified by <c>TestSpec</c>. The terms are
-%%% the same as those used in test specification files.
-%%% <p><c>Reason</c> indicates what type of error has been encountered.</p>
run_testspec(TestSpec) ->
ct_run:run_testspec(TestSpec).
-%%%-----------------------------------------------------------------
-%%% @spec step(TestDir,Suite,Case) -> Result
-%%% Case = atom()
-%%%
-%%% @doc Step through a test case with the debugger.
-%%% @see run/3
step(TestDir,Suite,Case) ->
ct_run:step(TestDir,Suite,Case).
-%%%-----------------------------------------------------------------
-%%% @spec step(TestDir,Suite,Case,Opts) -> Result
-%%% Case = atom()
-%%% Opts = [Opt] | []
-%%% Opt = config | keep_inactive
-%%%
-%%% @doc Step through a test case with the debugger. If the
-%%% <c>config</c> option has been given, breakpoints will
-%%% be set also on the configuration functions in <c>Suite</c>.
-%%% @see run/3
step(TestDir,Suite,Case,Opts) ->
ct_run:step(TestDir,Suite,Case,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec start_interactive() -> ok
-%%%
-%%% @doc Start CT in interactive mode.
-%%%
-%%% <p>From this mode all test case support functions can be executed
-%%% directly from the erlang shell. The interactive mode can also be
-%%% started from the OS command line with <c>ct_run -shell
-%%% [-config File...]</c>.</p>
-%%%
-%%% <p>If any functions using "required config data" (e.g. telnet or
-%%% ftp functions) are to be called from the erlang shell, config data
-%%% must first be required with <c>ct:require/2</c>.</p>
-%%%
-%%% <p>Example:<br/>
-%%% <c>&gt; ct:require(unix_telnet, unix).</c><br/>
-%%% <c>ok</c><br/>
-%%% <c>&gt; ct_telnet:open(unix_telnet).</c><br/>
-%%% <c>{ok,&lt;0.105.0&gt;}</c><br/>
-%%% <c>&gt; ct_telnet:cmd(unix_telnet, "ls .").</c><br/>
-%%% <c>{ok,["ls","file1 ...",...]}</c></p>
start_interactive() ->
_ = ct_util:start(interactive),
ok.
-%%%-----------------------------------------------------------------
-%%% @spec stop_interactive() -> ok
-%%%
-%%% @doc Exit the interactive mode.
-%%% @see start_interactive/0
stop_interactive() ->
ct_util:stop(normal),
ok.
@@ -331,181 +125,24 @@ stop_interactive() ->
%%% MISC INTERFACE
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%%-----------------------------------------------------------------
-%%% @spec require(Required) -> ok | {error,Reason}
-%%% Required = Key | {Key,SubKeys} | {Key,SubKey,SubKeys}
-%%% Key = atom()
-%%% SubKeys = SubKey | [SubKey]
-%%% SubKey = atom()
-%%%
-%%% @doc Check if the required configuration is available. It is possible
-%%% to specify arbitrarily deep tuples as <c>Required</c>. Note that it is
-%%% only the last element of the tuple which can be a list of <c>SubKey</c>s.
-%%%
-%%% <p>Example 1: require the variable <c>myvar</c>:</p>
-%%% <pre>ok = ct:require(myvar).</pre>
-%%%
-%%% <p>In this case the config file must at least contain:</p>
-%%% <pre>{myvar,Value}.</pre>
-%%%
-%%% <p>Example 2: require the key <c>myvar</c> with
-%%% subkeys <c>sub1</c> and <c>sub2</c>:</p>
-%%% <pre>ok = ct:require({myvar,[sub1,sub2]}).</pre>
-%%%
-%%% <p>In this case the config file must at least contain:</p>
-%%% <pre>{myvar,[{sub1,Value},{sub2,Value}]}.</pre>
-%%%
-%%% <p>Example 3: require the key <c>myvar</c> with
-%%% subkey <c>sub1</c> with <c>subsub1</c>:</p>
-%%% <pre>ok = ct:require({myvar,sub1,sub2}).</pre>
-%%%
-%%% <p>In this case the config file must at least contain:</p>
-%%% <pre>{myvar,[{sub1,[{sub2,Value}]}]}.</pre>
-%%%
-%%% @see require/2
-%%% @see get_config/1
-%%% @see get_config/2
-%%% @see get_config/3
require(Required) ->
ct_config:require(Required).
-%%%-----------------------------------------------------------------
-%%% @spec require(Name,Required) -> ok | {error,Reason}
-%%% Name = atom()
-%%% Required = Key | {Key,SubKey} | {Key,SubKey,SubKey}
-%%% SubKey = Key
-%%% Key = atom()
-%%%
-%%% @doc Check if the required configuration is available, and give it
-%%% a name. The semantics for <c>Required</c> is the same as in
-%%% <c>required/1</c> except that it is not possible to specify a list
-%%% of <c>SubKey</c>s.
-%%%
-%%% <p>If the requested data is available, the sub entry will be
-%%% associated with <c>Name</c> so that the value of the element
-%%% can be read with <c>get_config/1,2</c> provided
-%%% <c>Name</c> instead of the whole <c>Required</c> term.</p>
-%%%
-%%% <p>Example: Require one node with a telnet connection and an
-%%% ftp connection. Name the node <c>a</c>:
-%%% <pre>ok = ct:require(a,{machine,node}).</pre>
-%%% All references to this node may then use the node name.
-%%% E.g. you can fetch a file over ftp like this:</p>
-%%% <pre>ok = ct:ftp_get(a,RemoteFile,LocalFile).</pre>
-%%%
-%%% <p>For this to work, the config file must at least contain:</p>
-%%% <pre>{machine,[{node,[{telnet,IpAddr},{ftp,IpAddr}]}]}.</pre>
-%%%
-%%% <note><p>The behaviour of this function changed radically in common_test
-%%% 1.6.2. In order too keep some backwards compatability it is still possible
-%%% to do: <br/><c>ct:require(a,{node,[telnet,ftp]}).</c><br/>
-%%% This will associate the name <c>a</c> with the top level <c>node</c> entry.
-%%% For this to work, the config file must at least contain:<br/>
-%%% <c>{node,[{telnet,IpAddr},{ftp,IpAddr}]}.</c></p></note>
-%%%
-%%% @see require/1
-%%% @see get_config/1
-%%% @see get_config/2
-%%% @see get_config/3
require(Name,Required) ->
ct_config:require(Name,Required).
-%%%-----------------------------------------------------------------
-%%% @spec get_config(Required) -> Value
-%%% @equiv get_config(Required,undefined,[])
get_config(Required) ->
ct_config:get_config(Required,undefined,[]).
-%%%-----------------------------------------------------------------
-%%% @spec get_config(Required,Default) -> Value
-%%% @equiv get_config(Required,Default,[])
get_config(Required,Default) ->
ct_config:get_config(Required,Default,[]).
-%%%-----------------------------------------------------------------
-%%% @spec get_config(Required,Default,Opts) -> ValueOrElement
-%%% Required = KeyOrName | {KeyOrName,SubKey} | {KeyOrName,SubKey,SubKey}
-%%% KeyOrName = atom()
-%%% SubKey = atom()
-%%% Default = term()
-%%% Opts = [Opt] | []
-%%% Opt = element | all
-%%% ValueOrElement = term() | Default
-%%%
-%%% @doc Read config data values.
-%%%
-%%% <p>This function returns the matching value(s) or config element(s),
-%%% given a config variable key or its associated name
-%%% (if one has been specified with <c>require/2</c> or a
-%%% require statement).</p>
-%%%
-%%% <p>Example, given the following config file:</p>
-%%% <pre>
-%%% {unix,[{telnet,IpAddr},
-%%% {user,[{username,Username},
-%%% {password,Password}]}]}.</pre>
-%%% <p><c>ct:get_config(unix,Default) ->
-%%% [{telnet,IpAddr},
-%%% {user, [{username,Username},
-%%% {password,Password}]}]</c><br/>
-%%% <c>ct:get_config({unix,telnet},Default) -> IpAddr</c><br/>
-%%% <c>ct:get_config({unix,user,username},Default) -> Username</c><br/>
-%%% <c>ct:get_config({unix,ftp},Default) -> Default</c><br/>
-%%% <c>ct:get_config(unknownkey,Default) -> Default</c></p>
-%%%
-%%% <p>If a config variable key has been associated with a name (by
-%%% means of <c>require/2</c> or a require statement), the name
-%%% may be used instead of the key to read the value:</p>
-%%%
-%%% <p><c>ct:require(myuser,{unix,user}) -> ok.</c><br/>
-%%% <c>ct:get_config(myuser,Default) ->
-%%% [{username,Username},
-%%% {password,Password}]</c></p>
-%%%
-%%% <p>If a config variable is defined in multiple files and you want to
-%%% access all possible values, use the <c>all</c> option. The
-%%% values will be returned in a list and the order of the elements
-%%% corresponds to the order that the config files were specified at
-%%% startup.</p>
-%%%
-%%% <p>If you want config elements (key-value tuples) returned as result
-%%% instead of values, use the <c>element</c> option.
-%%% The returned elements will then be on the form <c>{Required,Value}</c></p>
-%%%
-%%% @see get_config/1
-%%% @see get_config/2
-%%% @see require/1
-%%% @see require/2
get_config(Required,Default,Opts) ->
ct_config:get_config(Required,Default,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec reload_config(Required) -> ValueOrElement
-%%% Required = KeyOrName | {KeyOrName,SubKey} | {KeyOrName,SubKey,SubKey}
-%%% KeyOrName = atom()
-%%% SubKey = atom()
-%%% ValueOrElement = term()
-%%%
-%%% @doc Reload config file which contains specified configuration key.
-%%%
-%%% <p>This function performs updating of the configuration data from which the
-%%% given configuration variable was read, and returns the (possibly) new
-%%% value of this variable.</p>
-%%% <p>Note that if some variables were present in the configuration but are not loaded
-%%% using this function, they will be removed from the configuration table together
-%%% with their aliases.</p>
-%%%
reload_config(Required)->
ct_config:reload_config(Required).
-%%%-----------------------------------------------------------------
-%%% @spec get_testspec_terms() -> TestSpecTerms | undefined
-%%% TestSpecTerms = [{Tag,Value}]
-%%% Value = [term()]
-%%%
-%%% @doc Get a list of all test specification terms used to
-%%% configure and run this test.
-%%%
get_testspec_terms() ->
case ct_util:get_testdata(testspec) of
undefined ->
@@ -514,25 +151,6 @@ get_testspec_terms() ->
ct_testspec:testspec_rec2list(CurrSpecRec)
end.
-%%%-----------------------------------------------------------------
-%%% @spec get_testspec_terms(Tags) -> TestSpecTerms | undefined
-%%% Tags = [Tag] | Tag
-%%% Tag = atom()
-%%% TestSpecTerms = [{Tag,Value}] | {Tag,Value}
-%%% Value = [{Node,term()}] | [term()]
-%%% Node = atom()
-%%%
-%%% @doc Read one or more terms from the test specification used
-%%% to configure and run this test. Tag is any valid test specification
-%%% tag, such as e.g. <c>label</c>, <c>config</c>, <c>logdir</c>.
-%%% User specific terms are also available to read if the
-%%% <c>allow_user_terms</c> option has been set. Note that all value tuples
-%%% returned, except user terms, will have the node name as first element.
-%%% Note also that in order to read test terms, use <c>Tag = tests</c>
-%%% (rather than <c>suites</c>, <c>groups</c> or <c>cases</c>). Value is
-%%% then the list of *all* tests on the form:
-%%% <c>[{Node,Dir,[{TestSpec,GroupsAndCases1},...]},...], where
-%%% GroupsAndCases = [{Group,[Case]}] | [Case]</c>.
get_testspec_terms(Tags) ->
case ct_util:get_testdata(testspec) of
undefined ->
@@ -541,24 +159,9 @@ get_testspec_terms(Tags) ->
ct_testspec:testspec_rec2list(Tags, CurrSpecRec)
end.
-
-%%%-----------------------------------------------------------------
-%%% @spec escape_chars(IoList1) -> IoList2 | {error,Reason}
-%%% IoList1 = iolist()
-%%% IoList2 = iolist()
-%%%
-%%% @doc Escape special characters to be printed in html log
-%%%
escape_chars(IoList) ->
ct_logs:escape_chars(IoList).
-%%%-----------------------------------------------------------------
-%%% @spec escape_chars(Format, Args) -> IoList | {error,Reason}
-%%% Format = string()
-%%% Args = list()
-%%%
-%%% @doc Escape special characters to be printed in html log
-%%%
escape_chars(Format, Args) ->
try io_lib:format(Format, Args) of
IoList ->
@@ -568,17 +171,9 @@ escape_chars(Format, Args) ->
{error,Reason}
end.
-%%%-----------------------------------------------------------------
-%%% @spec log(Format) -> ok
-%%% @equiv log(default,50,Format,[],[])
log(Format) ->
log(default,?STD_IMPORTANCE,Format,[],[]).
-%%%-----------------------------------------------------------------
-%%% @spec log(X1,X2) -> ok
-%%% X1 = Category | Importance | Format
-%%% X2 = Format | Args
-%%% @equiv log(Category,Importance,Format,Args,[])
log(X1,X2) ->
{Category,Importance,Format,Args} =
if is_atom(X1) -> {X1,?STD_IMPORTANCE,X2,[]};
@@ -587,12 +182,6 @@ log(X1,X2) ->
end,
log(Category,Importance,Format,Args,[]).
-%%%-----------------------------------------------------------------
-%%% @spec log(X1,X2,X3) -> ok
-%%% X1 = Category | Importance | Format
-%%% X2 = Importance | Format | Args
-%%% X3 = Format | Args | Opts
-%%% @equiv log(Category,Importance,Format,Args,Opts)
log(X1,X2,X3) ->
{Category,Importance,Format,Args,Opts} =
if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[],[]};
@@ -602,13 +191,6 @@ log(X1,X2,X3) ->
end,
log(Category,Importance,Format,Args,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec log(X1,X2,X3,X4) -> ok
-%%% X1 = Category | Importance
-%%% X2 = Importance | Format
-%%% X3 = Format | Args
-%%% X4 = Args | Opts
-%%% @equiv log(Category,Importance,Format,Args,Opts)
log(X1,X2,X3,X4) ->
{Category,Importance,Format,Args,Opts} =
if is_atom(X1), is_integer(X2) -> {X1,X2,X3,X4,[]};
@@ -617,40 +199,12 @@ log(X1,X2,X3,X4) ->
end,
log(Category,Importance,Format,Args,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec log(Category,Importance,Format,Args,Opts) -> ok
-%%% Category = atom()
-%%% Importance = integer()
-%%% Format = string()
-%%% Args = list()
-%%% Opts = [Opt]
-%%% Opt = {heading,string()} | esc_chars | no_css
-%%%
-%%% @doc Printout from a test case to the log file.
-%%%
-%%% <p>This function is meant for printing a string directly from a
-%%% test case to the test case log file.</p>
-%%%
-%%% <p>Default <c>Category</c> is <c>default</c>,
-%%% default <c>Importance</c> is <c>?STD_IMPORTANCE</c>,
-%%% and default value for <c>Args</c> is <c>[]</c>.</p>
-%%% <p>Please see the User's Guide for details on <c>Category</c>
-%%% and <c>Importance</c>.</p>
log(Category,Importance,Format,Args,Opts) ->
ct_logs:tc_log(Category,Importance,Format,Args,Opts).
-
-%%%-----------------------------------------------------------------
-%%% @spec print(Format) -> ok
-%%% @equiv print(default,50,Format,[],[])
print(Format) ->
print(default,?STD_IMPORTANCE,Format,[],[]).
-%%%-----------------------------------------------------------------
-%%% @spec print(X1,X2) -> ok
-%%% X1 = Category | Importance | Format
-%%% X2 = Format | Args
-%%% @equiv print(Category,Importance,Format,Args,[])
print(X1,X2) ->
{Category,Importance,Format,Args} =
if is_atom(X1) -> {X1,?STD_IMPORTANCE,X2,[]};
@@ -659,12 +213,6 @@ print(X1,X2) ->
end,
print(Category,Importance,Format,Args,[]).
-%%%-----------------------------------------------------------------
-%%% @spec print(X1,X2,X3) -> ok
-%%% X1 = Category | Importance | Format
-%%% X2 = Importance | Format | Args
-%%% X3 = Format | Args | Opts
-%%% @equiv print(Category,Importance,Format,Args,Opts)
print(X1,X2,X3) ->
{Category,Importance,Format,Args,Opts} =
if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[],[]};
@@ -674,13 +222,6 @@ print(X1,X2,X3) ->
end,
print(Category,Importance,Format,Args,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec print(X1,X2,X3,X4) -> ok
-%%% X1 = Category | Importance
-%%% X2 = Importance | Format
-%%% X3 = Format | Args
-%%% X4 = Args | Opts
-%%% @equiv print(Category,Importance,Format,Args,Opts)
print(X1,X2,X3,X4) ->
{Category,Importance,Format,Args,Opts} =
if is_atom(X1), is_integer(X2) -> {X1,X2,X3,X4,[]};
@@ -689,40 +230,12 @@ print(X1,X2,X3,X4) ->
end,
print(Category,Importance,Format,Args,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec print(Category,Importance,Format,Args,Opts) -> ok
-%%% Category = atom()
-%%% Importance = integer()
-%%% Format = string()
-%%% Args = list()
-%%% Opts = [Opt]
-%%% Opt = {heading,string()}
-%%%
-%%% @doc Printout from a test case to the console.
-%%%
-%%% <p>This function is meant for printing a string from a test case
-%%% to the console.</p>
-%%%
-%%% <p>Default <c>Category</c> is <c>default</c>,
-%%% default <c>Importance</c> is <c>?STD_IMPORTANCE</c>,
-%%% and default value for <c>Args</c> is <c>[]</c>.</p>
-%%% <p>Please see the User's Guide for details on <c>Category</c>
-%%% and <c>Importance</c>.</p>
print(Category,Importance,Format,Args,Opts) ->
ct_logs:tc_print(Category,Importance,Format,Args,Opts).
-
-%%%-----------------------------------------------------------------
-%%% @spec pal(Format) -> ok
-%%% @equiv pal(default,50,Format,[],[])
pal(Format) ->
pal(default,?STD_IMPORTANCE,Format,[]).
-%%%-----------------------------------------------------------------
-%%% @spec pal(X1,X2) -> ok
-%%% X1 = Category | Importance | Format
-%%% X2 = Format | Args
-%%% @equiv pal(Category,Importance,Format,Args,[])
pal(X1,X2) ->
{Category,Importance,Format,Args} =
if is_atom(X1) -> {X1,?STD_IMPORTANCE,X2,[]};
@@ -731,12 +244,6 @@ pal(X1,X2) ->
end,
pal(Category,Importance,Format,Args,[]).
-%%%-----------------------------------------------------------------
-%%% @spec pal(X1,X2,X3) -> ok
-%%% X1 = Category | Importance | Format
-%%% X2 = Importance | Format | Args
-%%% X3 = Format | Args | Opts
-%%% @equiv pal(Category,Importance,Format,Args,Opts)
pal(X1,X2,X3) ->
{Category,Importance,Format,Args,Opts} =
if is_atom(X1), is_integer(X2) -> {X1,X2,X3,[],[]};
@@ -746,13 +253,6 @@ pal(X1,X2,X3) ->
end,
pal(Category,Importance,Format,Args,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec pal(X1,X2,X3,X4) -> ok
-%%% X1 = Category | Importance
-%%% X2 = Importance | Format
-%%% X3 = Format | Args
-%%% X4 = Args | Opts
-%%% @equiv pal(Category,Importance,Format,Args,Opts)
pal(X1,X2,X3,X4) ->
{Category,Importance,Format,Args,Opts} =
if is_atom(X1), is_integer(X2) -> {X1,X2,X3,X4,[]};
@@ -761,91 +261,25 @@ pal(X1,X2,X3,X4) ->
end,
pal(Category,Importance,Format,Args,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec pal(Category,Importance,Format,Args,Opts) -> ok
-%%% Category = atom()
-%%% Importance = integer()
-%%% Format = string()
-%%% Args = list()
-%%% Opts = [Opt]
-%%% Opt = {heading,string()} | no_css
-%%%
-%%% @doc Print and log from a test case.
-%%%
-%%% <p>This function is meant for printing a string from a test case,
-%%% both to the test case log file and to the console.</p>
-%%%
-%%% <p>Default <c>Category</c> is <c>default</c>,
-%%% default <c>Importance</c> is <c>?STD_IMPORTANCE</c>,
-%%% and default value for <c>Args</c> is <c>[]</c>.</p>
-%%% <p>Please see the User's Guide for details on <c>Category</c>
-%%% and <c>Importance</c>.</p>
pal(Category,Importance,Format,Args,Opts) ->
ct_logs:tc_pal(Category,Importance,Format,Args,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec set_verbosity(Category, Level) -> ok
-%%% Category = default | atom()
-%%% Level = integer()
-%%%
-%%% @doc Set the verbosity level for a category
set_verbosity(Category, Level) ->
ct_util:set_verbosity({Category,Level}).
-%%%-----------------------------------------------------------------
-%%% @spec get_verbosity(Category) -> Level | undefined
-%%% Category = default | atom()
-%%% Level = integer()
-%%%
-%%% @doc Read the verbosity level for a category
get_verbosity(Category) ->
ct_util:get_verbosity(Category).
-%%%-----------------------------------------------------------------
-%%% @spec capture_start() -> ok
-%%%
-%%% @doc Start capturing all text strings printed to stdout during
-%%% execution of the test case.
-%%%
-%%% @see capture_stop/0
-%%% @see capture_get/1
capture_start() ->
test_server:capture_start().
-%%%-----------------------------------------------------------------
-%%% @spec capture_stop() -> ok
-%%%
-%%% @doc Stop capturing text strings (a session started with
-%%% <c>capture_start/0</c>).
-%%%
-%%% @see capture_start/0
-%%% @see capture_get/1
capture_stop() ->
test_server:capture_stop().
-%%%-----------------------------------------------------------------
-%%% @spec capture_get() -> ListOfStrings
-%%% ListOfStrings = [string()]
-%%%
-%%% @equiv capture_get([default])
capture_get() ->
%% remove default log printouts (e.g. ct:log/2 printouts)
capture_get([default]).
-%%%-----------------------------------------------------------------
-%%% @spec capture_get(ExclCategories) -> ListOfStrings
-%%% ExclCategories = [atom()]
-%%% ListOfStrings = [string()]
-%%%
-%%% @doc Return and purge the list of text strings buffered
-%%% during the latest session of capturing printouts to stdout.
-%%% With <c>ExclCategories</c> it's possible to specify
-%%% log categories that should be ignored in <c>ListOfStrings</c>.
-%%% If <c>ExclCategories = []</c>, no filtering takes place.
-%%%
-%%% @see capture_start/0
-%%% @see capture_stop/0
-%%% @see log/3
capture_get([ExclCat | ExclCategories]) ->
Strs = test_server:capture_get(),
CatsStr = [atom_to_list(ExclCat) |
@@ -862,12 +296,6 @@ capture_get([ExclCat | ExclCategories]) ->
capture_get([]) ->
test_server:capture_get().
-%%%-----------------------------------------------------------------
-%%% @spec fail(Reason) -> ok
-%%% Reason = term()
-%%%
-%%% @doc Terminate a test case with the given error
-%%% <c>Reason</c>.
fail(Reason) ->
try
exit({test_case_failed,Reason})
@@ -880,14 +308,6 @@ fail(Reason) ->
erlang:raise(Class, R, Stk)
end.
-%%%-----------------------------------------------------------------
-%%% @spec fail(Format, Args) -> ok
-%%% Format = string()
-%%% Args = list()
-%%%
-%%% @doc Terminate a test case with an error message specified
-%%% by a format string and a list of values (used as arguments to
-%%% <c>io_lib:format/2</c>).
fail(Format, Args) ->
try io_lib:format(Format, Args) of
Str ->
@@ -906,16 +326,6 @@ fail(Format, Args) ->
exit({BadArgs,{?MODULE,fail,[Format,Args]}})
end.
-%%%-----------------------------------------------------------------
-%%% @spec comment(Comment) -> ok
-%%% Comment = term()
-%%%
-%%% @doc Print the given <c>Comment</c> in the comment field in
-%%% the table on the test suite result page.
-%%%
-%%% <p>If called several times, only the last comment is printed.
-%%% The test case return value <c>{comment,Comment}</c>
-%%% overwrites the string set by this function.</p>
comment(Comment) when is_list(Comment) ->
Formatted =
case (catch io_lib:format("~ts",[Comment])) of
@@ -929,19 +339,6 @@ comment(Comment) ->
Formatted = io_lib:format("~tp",[Comment]),
send_html_comment(lists:flatten(Formatted)).
-%%%-----------------------------------------------------------------
-%%% @spec comment(Format, Args) -> ok
-%%% Format = string()
-%%% Args = list()
-%%%
-%%% @doc Print the formatted string in the comment field in
-%%% the table on the test suite result page.
-%%%
-%%% <p>The <c>Format</c> and <c>Args</c> arguments are
-%%% used in call to <c>io_lib:format/2</c> in order to create
-%%% the comment string. The behaviour of <c>comment/2</c> is
-%%% otherwise the same as the <c>comment/1</c> function (see
-%%% above for details).</p>
comment(Format, Args) when is_list(Format), is_list(Args) ->
Formatted =
case (catch io_lib:format(Format, Args)) of
@@ -957,64 +354,28 @@ send_html_comment(Comment) ->
ct_util:set_testdata({{comment,group_leader()},Html}),
test_server:comment(Html).
-%%%-----------------------------------------------------------------
-%%% @spec make_priv_dir() -> ok | {error,Reason}
-%%% Reason = term()
-%%% @doc If the test has been started with the create_priv_dir
-%%% option set to manual_per_tc, in order for the test case to use
-%%% the private directory, it must first create it by calling
-%%% this function.
make_priv_dir() ->
test_server:make_priv_dir().
-%%%-----------------------------------------------------------------
-%%% @spec get_target_name(Handle) -> {ok,TargetName} | {error,Reason}
-%%% Handle = handle()
-%%% TargetName = target_name()
-%%% @doc Return the name of the target that the given connection
-%%% belongs to.
get_target_name(Handle) ->
ct_util:get_target_name(Handle).
-
-%%%-----------------------------------------------------------------
-%%% @spec parse_table(Data) -> {Heading,Table}
-%%% Data = [string()]
-%%% Heading = tuple()
-%%% Table = [tuple()]
-%%%
-%%% @doc Parse the printout from an SQL table and return a list of tuples.
-%%%
-%%% <p>The printout to parse would typically be the result of a
-%%% <c>select</c> command in SQL. The returned
-%%% <c>Table</c> is a list of tuples, where each tuple is a row
-%%% in the table.</p>
-%%%
-%%% <p><c>Heading</c> is a tuple of strings representing the
-%%% headings of each column in the table.</p>
+
+-spec get_progname() -> string().
+
+get_progname() ->
+ case init:get_argument(progname) of
+ {ok, [[Prog]]} ->
+ Prog;
+ _Other ->
+ "no_prog_name"
+ end.
+
parse_table(Data) ->
ct_util:parse_table(Data).
-%%%-----------------------------------------------------------------
-%%% @spec listenv(Telnet) -> [Env]
-%%% Telnet = term()
-%%% Env = {Key,Value}
-%%% Key = string()
-%%% Value = string()
-%%%
-%%% @doc Performs the listenv command on the given telnet connection
-%%% and returns the result as a list of Key-Value pairs.
listenv(Telnet) ->
ct_util:listenv(Telnet).
-
-%%%-----------------------------------------------------------------
-%%% @spec testcases(TestDir, Suite) -> Testcases | {error,Reason}
-%%% TestDir = string()
-%%% Suite = atom()
-%%% Testcases = list()
-%%% Reason = term()
-%%%
-%%% @doc Returns all test cases in the specified suite.
testcases(TestDir, Suite) ->
case make_and_load(TestDir, Suite) of
E = {error,_} ->
@@ -1054,15 +415,6 @@ make_and_load(Dir, Suite) ->
end
end.
-%%%-----------------------------------------------------------------
-%%% @spec userdata(TestDir, Suite) -> SuiteUserData | {error,Reason}
-%%% TestDir = string()
-%%% Suite = atom()
-%%% SuiteUserData = [term()]
-%%% Reason = term()
-%%%
-%%% @doc Returns any data specified with the tag <c>userdata</c>
-%%% in the list of tuples returned from <c>Suite:suite/0</c>.
userdata(TestDir, Suite) ->
case make_and_load(TestDir, Suite) of
E = {error,_} ->
@@ -1088,18 +440,6 @@ get_userdata(List, _) when is_list(List) ->
get_userdata(_BadTerm, Spec) ->
{error,list_to_atom(Spec ++ " must return a list")}.
-%%%-----------------------------------------------------------------
-%%% @spec userdata(TestDir, Suite, GroupOrCase) -> TCUserData | {error,Reason}
-%%% TestDir = string()
-%%% Suite = atom()
-%%% GroupOrCase = {group,GroupName} | atom()
-%%% GroupName = atom()
-%%% TCUserData = [term()]
-%%% Reason = term()
-%%%
-%%% @doc Returns any data specified with the tag <c>userdata</c>
-%%% in the list of tuples returned from <c>Suite:group(GroupName)</c>
-%%% or <c>Suite:Case()</c>.
userdata(TestDir, Suite, {group,GroupName}) ->
case make_and_load(TestDir, Suite) of
E = {error,_} ->
@@ -1118,27 +458,6 @@ userdata(TestDir, Suite, Case) when is_atom(Case) ->
get_userdata(Info, atom_to_list(Case)++"/0")
end.
-
-%%%-----------------------------------------------------------------
-%%% @spec get_status() -> TestStatus | {error,Reason} | no_tests_running
-%%% TestStatus = [StatusElem]
-%%% StatusElem = {current,TestCaseInfo} | {successful,Successful} |
-%%% {failed,Failed} | {skipped,Skipped} | {total,Total}
-%%% TestCaseInfo = {Suite,TestCase} | [{Suite,TestCase}]
-%%% Suite = atom()
-%%% TestCase = atom()
-%%% Successful = integer()
-%%% Failed = integer()
-%%% Skipped = {UserSkipped,AutoSkipped}
-%%% UserSkipped = integer()
-%%% AutoSkipped = integer()
-%%% Total = integer()
-%%% Reason = term()
-%%%
-%%% @doc Returns status of ongoing test. The returned list contains info about
-%%% which test case is currently executing (a list of cases when a
-%%% parallel test case group is executing), as well as counters for
-%%% successful, failed, skipped, and total test cases so far.
get_status() ->
case get_testdata(curr_tc) of
{ok,TestCase} ->
@@ -1170,176 +489,37 @@ get_testdata(Key) ->
{ok,Data}
end.
-%%%-----------------------------------------------------------------
-%%% @spec abort_current_testcase(Reason) -> ok | {error,ErrorReason}
-%%% Reason = term()
-%%% ErrorReason = no_testcase_running | parallel_group
-%%%
-%%% @doc <p>When calling this function, the currently executing test case will be aborted.
-%%% It is the user's responsibility to know for sure which test case is currently
-%%% executing. The function is therefore only safe to call from a function which
-%%% has been called (or synchronously invoked) by the test case.</p>
-%%%
-%%% <p><c>Reason</c>, the reason for aborting the test case, is printed
-%%% in the test case log.</p>
abort_current_testcase(Reason) ->
test_server_ctrl:abort_current_testcase(Reason).
-%%%-----------------------------------------------------------------
-%%% @spec get_event_mgr_ref() -> EvMgrRef
-%%% EvMgrRef = atom()
-%%%
-%%% @doc <p>Call this function in order to get a reference to the
-%%% CT event manager. The reference can be used to e.g. add
-%%% a user specific event handler while tests are running.
-%%% Example:
-%%% <c>gen_event:add_handler(ct:get_event_mgr_ref(), my_ev_h, [])</c></p>
get_event_mgr_ref() ->
?CT_EVMGR_REF.
-%%%-----------------------------------------------------------------
-%%% @spec encrypt_config_file(SrcFileName, EncryptFileName) ->
-%%% ok | {error,Reason}
-%%% SrcFileName = string()
-%%% EncryptFileName = string()
-%%% Reason = term()
-%%%
-%%% @doc <p>This function encrypts the source config file with DES3 and
-%%% saves the result in file <c>EncryptFileName</c>. The key,
-%%% a string, must be available in a text file named
-%%% <c>.ct_config.crypt</c> in the current directory, or the
-%%% home directory of the user (it is searched for in that order).</p>
-%%% <p>See the Common Test User's Guide for information about using
-%%% encrypted config files when running tests.</p>
-%%% <p>See the <c>crypto</c> application for details on DES3
-%%% encryption/decryption.</p>
encrypt_config_file(SrcFileName, EncryptFileName) ->
ct_config:encrypt_config_file(SrcFileName, EncryptFileName).
-%%%-----------------------------------------------------------------
-%%% @spec encrypt_config_file(SrcFileName, EncryptFileName, KeyOrFile) ->
-%%% ok | {error,Reason}
-%%% SrcFileName = string()
-%%% EncryptFileName = string()
-%%% KeyOrFile = {key,string()} | {file,string()}
-%%% Reason = term()
-%%%
-%%% @doc <p>This function encrypts the source config file with DES3 and
-%%% saves the result in the target file <c>EncryptFileName</c>.
-%%% The encryption key to use is either the value in
-%%% <c>{key,Key}</c> or the value stored in the file specified
-%%% by <c>{file,File}</c>.</p>
-%%% <p>See the Common Test User's Guide for information about using
-%%% encrypted config files when running tests.</p>
-%%% <p>See the <c>crypto</c> application for details on DES3
-%%% encryption/decryption.</p>
encrypt_config_file(SrcFileName, EncryptFileName, KeyOrFile) ->
ct_config:encrypt_config_file(SrcFileName, EncryptFileName, KeyOrFile).
-%%%-----------------------------------------------------------------
-%%% @spec decrypt_config_file(EncryptFileName, TargetFileName) ->
-%%% ok | {error,Reason}
-%%% EncryptFileName = string()
-%%% TargetFileName = string()
-%%% Reason = term()
-%%%
-%%% @doc <p>This function decrypts <c>EncryptFileName</c>, previously
-%%% generated with <c>encrypt_config_file/2/3</c>. The original
-%%% file contents is saved in the target file. The encryption key, a
-%%% string, must be available in a text file named
-%%% <c>.ct_config.crypt</c> in the current directory, or the
-%%% home directory of the user (it is searched for in that order).</p>
decrypt_config_file(EncryptFileName, TargetFileName) ->
ct_config:decrypt_config_file(EncryptFileName, TargetFileName).
-%%%-----------------------------------------------------------------
-%%% @spec decrypt_config_file(EncryptFileName, TargetFileName, KeyOrFile) ->
-%%% ok | {error,Reason}
-%%% EncryptFileName = string()
-%%% TargetFileName = string()
-%%% KeyOrFile = {key,string()} | {file,string()}
-%%% Reason = term()
-%%%
-%%% @doc <p>This function decrypts <c>EncryptFileName</c>, previously
-%%% generated with <c>encrypt_config_file/2/3</c>. The original
-%%% file contents is saved in the target file. The key must have the
-%%% the same value as that used for encryption.</p>
decrypt_config_file(EncryptFileName, TargetFileName, KeyOrFile) ->
ct_config:decrypt_config_file(EncryptFileName, TargetFileName, KeyOrFile).
-
-%%%-----------------------------------------------------------------
-%%% @spec add_config(Callback, Config) -> ok | {error, Reason}
-%%% Callback = atom()
-%%% Config = string()
-%%% Reason = term()
-%%%
-%%% @doc <p>This function loads configuration variables using the
-%%% given callback module and configuration string. Callback module
-%%% should be either loaded or present in the code part. Loaded
-%%% configuration variables can later be removed using
-%%% <c>remove_config/2</c> function.</p>
add_config(Callback, Config)->
ct_config:add_config(Callback, Config).
-%%%-----------------------------------------------------------------
-%%% @spec remove_config(Callback, Config) -> ok
-%%% Callback = atom()
-%%% Config = string()
-%%% Reason = term()
-%%%
-%%% @doc <p>This function removes configuration variables (together with
-%%% their aliases) which were loaded with specified callback module and
-%%% configuration string.</p>
remove_config(Callback, Config) ->
ct_config:remove_config(Callback, Config).
-%%%-----------------------------------------------------------------
-%%% @spec timetrap(Time) -> ok
-%%% Time = {hours,Hours} | {minutes,Mins} | {seconds,Secs} | Millisecs | infinity | Func
-%%% Hours = integer()
-%%% Mins = integer()
-%%% Secs = integer()
-%%% Millisecs = integer() | float()
-%%% Func = {M,F,A} | fun()
-%%% M = atom()
-%%% F = atom()
-%%% A = list()
-%%%
-%%% @doc <p>Use this function to set a new timetrap for the running test case.
-%%% If the argument is <c>Func</c>, the timetrap will be triggered
-%%% when this function returns. <c>Func</c> may also return a new
-%%% <c>Time</c> value, which in that case will be the value for the
-%%% new timetrap.</p>
timetrap(Time) ->
test_server:timetrap_cancel(),
test_server:timetrap(Time).
-%%%-----------------------------------------------------------------
-%%% @spec get_timetrap_info() -> {Time,Scale}
-%%% Time = integer() | infinity
-%%% Scale = true | false
-%%%
-%%% @doc <p>Read info about the timetrap set for the current test case.
-%%% <c>Scale</c> indicates if Common Test will attempt to automatically
-%%% compensate timetraps for runtime delays introduced by e.g. tools like
-%%% cover.</p>
get_timetrap_info() ->
test_server:get_timetrap_info().
-%%%-----------------------------------------------------------------
-%%% @spec sleep(Time) -> ok
-%%% Time = {hours,Hours} | {minutes,Mins} | {seconds,Secs} | Millisecs | infinity
-%%% Hours = integer()
-%%% Mins = integer()
-%%% Secs = integer()
-%%% Millisecs = integer() | float()
-%%%
-%%% @doc <p>This function, similar to <c>timer:sleep/1</c>, suspends the test
-%%% case for specified time. However, this function also multiplies
-%%% <c>Time</c> with the 'multiply_timetraps' value (if set) and under
-%%% certain circumstances also scales up the time automatically
-%%% if 'scale_timetraps' is set to true (default is false).</p>
sleep({hours,Hs}) ->
sleep(trunc(Hs * 1000 * 60 * 60));
sleep({minutes,Ms}) ->
@@ -1349,52 +529,12 @@ sleep({seconds,Ss}) ->
sleep(Time) ->
test_server:adjusted_sleep(Time).
-%%%-----------------------------------------------------------------
-%%% @spec notify(Name,Data) -> ok
-%%% Name = atom()
-%%% Data = term()
-%%%
-%%% @doc <p>Sends a asynchronous notification of type <c>Name</c> with
-%%% <c>Data</c>to the common_test event manager. This can later be
-%%% caught by any installed event manager. </p>
-%%% @see //stdlib/gen_event
notify(Name,Data) ->
ct_event:notify(Name, Data).
-%%%-----------------------------------------------------------------
-%%% @spec sync_notify(Name,Data) -> ok
-%%% Name = atom()
-%%% Data = term()
-%%%
-%%% @doc <p>Sends a synchronous notification of type <c>Name</c> with
-%%% <c>Data</c>to the common_test event manager. This can later be
-%%% caught by any installed event manager. </p>
-%%% @see //stdlib/gen_event
sync_notify(Name,Data) ->
ct_event:sync_notify(Name, Data).
-%%%-----------------------------------------------------------------
-%%% @spec break(Comment) -> ok | {error,Reason}
-%%% Comment = string()
-%%% Reason = {multiple_cases_running,TestCases} |
-%%% 'enable break with release_shell option'
-%%% TestCases = [atom()]
-%%%
-%%% @doc <p>This function will cancel any active timetrap and pause the
-%%% execution of the current test case until the user calls the
-%%% <c>continue/0</c> function. It gives the user the opportunity
-%%% to interact with the erlang node running the tests, e.g. for
-%%% debugging purposes or for manually executing a part of the
-%%% test case. If a parallel group is executing, <c>break/2</c>
-%%% should be called instead.</p>
-%%% <p>A cancelled timetrap will not be automatically
-%%% reactivated after the break, but must be started exlicitly with
-%%% <c>ct:timetrap/1</c></p>
-%%% <p>In order for the break/continue functionality to work,
-%%% Common Test must release the shell process controlling stdin.
-%%% This is done by setting the <c>release_shell</c> start option
-%%% to <c>true</c>. See the User's Guide for more information.</p>
-
break(Comment) ->
case {ct_util:get_testdata(starter),
ct_util:get_testdata(release_shell)} of
@@ -1417,19 +557,6 @@ break(Comment) ->
end
end.
-%%%-----------------------------------------------------------------
-%%% @spec break(TestCase, Comment) -> ok | {error,Reason}
-%%% TestCase = atom()
-%%% Comment = string()
-%%% Reason = 'test case not running' |
-%%% 'enable break with release_shell option'
-%%%
-%%% @doc <p>This function works the same way as <c>break/1</c>,
-%%% only the <c>TestCase</c> argument makes it possible to
-%%% pause a test case executing in a parallel group. The
-%%% <c>continue/1</c> function should be used to resume
-%%% execution of <c>TestCase</c>.</p>
-%%% <p>See <c>break/1</c> for more details.</p>
break(TestCase, Comment) ->
case {ct_util:get_testdata(starter),
ct_util:get_testdata(release_shell)} of
@@ -1456,56 +583,12 @@ break(TestCase, Comment) ->
end
end.
-%%%-----------------------------------------------------------------
-%%% @spec continue() -> ok
-%%%
-%%% @doc <p>This function must be called in order to continue after a
-%%% test case (not executing in a parallel group) has called
-%%% <c>break/1</c>.</p>
continue() ->
test_server:continue().
-%%%-----------------------------------------------------------------
-%%% @spec continue(TestCase) -> ok
-%%% TestCase = atom()
-%%%
-%%% @doc <p>This function must be called in order to continue after a
-%%% test case has called <c>break/2</c>. If the paused test case,
-%%% <c>TestCase</c>, executes in a parallel group, this
-%%% function - rather than <c>continue/0</c> - must be used
-%%% in order to let the test case proceed.</p>
continue(TestCase) ->
test_server:continue(TestCase).
-%%%-----------------------------------------------------------------
-%%% @spec remaining_test_procs() -> {TestProcs,SharedGL,OtherGLs}
-%%% TestProcs = [{pid(),GL}]
-%%% GL = SharedGL = pid()
-%%% OtherGLs = [pid()]
-%%%
-%%% @doc <p>This function will return the identity of test- and group
-%%% leader processes that are still running at the time of this call.
-%%% TestProcs are processes in the system that have a Common Test IO
-%%% process as group leader. SharedGL is the central Common Test
-%%% IO process, responsible for printing to log files for configuration
-%%% functions and sequentially executing test cases. OtherGLs are
-%%% Common Test IO processes that print to log files for test cases
-%%% in parallel test case groups.</p>
-%%% <p>The process information returned by this function may be
-%%% used to locate and terminate remaining processes after tests have
-%%% finished executing. The function would typically by called from
-%%% Common Test Hook functions.</p>
-%%% <p>Note that processes that execute configuration functions or
-%%% test cases are never included in TestProcs. It is therefore safe
-%%% to use post configuration hook functions (such as post_end_per_suite,
-%%% post_end_per_group, post_end_per_testcase) to terminate all processes
-%%% in TestProcs that have the current group leader process as its group
-%%% leader.</p>
-%%% <p>Note also that the shared group leader (SharedGL) must never be
-%%% terminated by the user, only by Common Test. Group leader processes
-%%% for parallel test case groups (OtherGLs) may however be terminated
-%%% in post_end_per_group hook functions.</p>
-%%%
remaining_test_procs() ->
ct_util:remaining_test_procs().
diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl
index e33b47b0e8..a10d939919 100644
--- a/lib/common_test/src/ct_config.erl
+++ b/lib/common_test/src/ct_config.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/src/ct_config_plain.erl b/lib/common_test/src/ct_config_plain.erl
index d525019f7b..7b68ac6597 100644
--- a/lib/common_test/src/ct_config_plain.erl
+++ b/lib/common_test/src/ct_config_plain.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/src/ct_cover.erl b/lib/common_test/src/ct_cover.erl
index c258516915..d286f20a4d 100644
--- a/lib/common_test/src/ct_cover.erl
+++ b/lib/common_test/src/ct_cover.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,11 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework code coverage support module.
-%%%
-%%% <p>This module exports help functions for performing code
-%%% coverage analysis.</p>
-
-module(ct_cover).
-export([get_spec/1, add_nodes/1, remove_nodes/1, cross_cover_analyse/2]).
@@ -31,16 +26,6 @@
-include_lib("kernel/include/file.hrl").
-%%%-----------------------------------------------------------------
-%%% @spec add_nodes(Nodes) -> {ok,StartedNodes} | {error,Reason}
-%%% Nodes = [atom()]
-%%% StartedNodes = [atom()]
-%%% Reason = cover_not_running | not_main_node
-%%%
-%%% @doc Add nodes to current cover test (only works if cover support
-%%% is active!). To have effect, this function should be called
-%%% from init_per_suite/1 before any actual tests are performed.
-%%%
add_nodes([]) ->
{ok,[]};
add_nodes(Nodes) ->
@@ -67,17 +52,6 @@ add_nodes(Nodes) ->
end
end.
-
-%%%-----------------------------------------------------------------
-%%% @spec remove_nodes(Nodes) -> ok | {error,Reason}
-%%% Nodes = [atom()]
-%%% Reason = cover_not_running | not_main_node
-%%%
-%%% @doc Remove nodes from current cover test. Call this function
-%%% to stop cover test on nodes previously added with add_nodes/1.
-%%% Results on the remote node are transferred to the Common Test
-%%% node.
-%%%
remove_nodes([]) ->
ok;
remove_nodes(Nodes) ->
@@ -103,25 +77,11 @@ remove_nodes(Nodes) ->
end
end.
-
-%%%-----------------------------------------------------------------
-%%% @spec cross_cover_analyse(Level,Tests) -> ok
-%%% Level = overview | details
-%%% Tests = [{Tag,Dir}]
-%%% Tag = atom()
-%%% Dir = string()
-%%%
-%%% @doc Accumulate cover results over multiple tests.
-%%% See the chapter about <seealso
-%%% marker="cover_chapter#cross_cover">cross cover
-%%% analysis</seealso> in the users's guide.
-%%%
cross_cover_analyse(Level,Tests) ->
test_server_ctrl:cross_cover_analyse(Level,Tests).
%%%-----------------------------------------------------------------
-%%% @hidden
%% Read cover specification file and return the parsed info.
%% -> CoverSpec: {CoverFile,Nodes,Import,Export,AppCoverInfo}
diff --git a/lib/common_test/src/ct_default_gl.erl b/lib/common_test/src/ct_default_gl.erl
index 9ae430c546..cf1bcc058d 100644
--- a/lib/common_test/src/ct_default_gl.erl
+++ b/lib/common_test/src/ct_default_gl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/src/ct_event.erl b/lib/common_test/src/ct_event.erl
index 8b5bba7600..3689c6bc45 100644
--- a/lib/common_test/src/ct_event.erl
+++ b/lib/common_test/src/ct_event.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,14 +18,14 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework Event Handler
+%%% doc Common Test Framework Event Handler
%%%
-%%% <p>This module implements an event handler that CT uses to
+%%% This module implements an event handler that CT uses to
%%% handle status and progress notifications during test runs.
%%% The notifications are handled locally (per node) and passed
%%% on to ct_master when CT runs in distributed mode. This
%%% module may be used as a template for other event handlers
-%%% that can be plugged in to handle local logging and reporting.</p>
+%%% that can be plugged in to handle local logging and reporting.
-module(ct_event).
-behaviour(gen_event).
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index 7f7e9ae6f9..7e98e6395f 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,10 +18,10 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework callback module.
+%%% Common Test Framework callback module.
%%%
-%%% <p>This module exports framework callback functions which are
-%%% called from the test_server.</p>
+%%% This module exports framework callback functions which are
+%%% called from the test_server.
-module(ct_framework).
@@ -42,7 +42,7 @@
-define(rev(L), lists:reverse(L)).
%%%-----------------------------------------------------------------
-%%% @spec init_tc(Mod,Func,Args) -> {ok,NewArgs} | {error,Reason} |
+%%% -spec init_tc(Mod,Func,Args) -> {ok,NewArgs} | {error,Reason} |
%%% {skip,Reason} | {auto_skip,Reason}
%%% Mod = atom()
%%% Func = atom()
@@ -50,7 +50,7 @@
%%% NewArgs = list()
%%% Reason = term()
%%%
-%%% @doc Test server framework callback, called by the test_server
+%%% Test server framework callback, called by the test_server
%%% when a new test case is started.
init_tc(_,{end_per_testcase_not_run,_},[Config]) ->
%% Testcase is completed (skipped or failed), but end_per_testcase
@@ -649,7 +649,7 @@ try_set_default(Name,Key,Info,Where) ->
%%%-----------------------------------------------------------------
-%%% @spec end_tc(Mod,Func,Args) -> {ok,NewArgs}| {error,Reason} |
+%%% -spec end_tc(Mod,Func,Args) -> {ok,NewArgs}| {error,Reason} |
%%% {skip,Reason} | {auto_skip,Reason}
%%% Mod = atom()
%%% Func = atom()
@@ -657,7 +657,7 @@ try_set_default(Name,Key,Info,Where) ->
%%% NewArgs = list()
%%% Reason = term()
%%%
-%%% @doc Test server framework callback, called by the test_server
+%%% Test server framework callback, called by the test_server
%%% when a test case is finished.
end_tc(Mod, Fun, Args) ->
%% Have to keep end_tc/3 for backwards compatibility issues
@@ -903,15 +903,15 @@ tag(_Other) ->
ok.
%%%-----------------------------------------------------------------
-%%% @spec error_notification(Mod,Func,Args,Error) -> ok
+%%% -spec error_notification(Mod,Func,Args,Error) -> ok
%%% Mod = atom()
%%% Func = atom()
%%% Args = list()
%%% Error = term()
%%%
-%%% @doc This function is called as the result of testcase
-%%% <code>Func</code> in suite <code>Mod</code> crashing.
-%%% <code>Error</code> specifies the reason for failing.
+%%% This function is called as the result of testcase
+%%% Func in suite Mod crashing.
+%%% Error specifies the reason for failing.
error_notification(Mod,Func,_Args,{Error,Loc}) ->
ErrorSpec = case Error of
{What={_E,_R},Trace} when is_list(Trace) ->
@@ -1049,11 +1049,11 @@ group_or_func(Func, _Config) ->
Func.
%%%-----------------------------------------------------------------
-%%% @spec get_suite(Mod, Func) -> Tests
+%%% -spec get_suite(Mod, Func) -> Tests
%%%
-%%% @doc Called from test_server for every suite (<code>Func==all</code>)
-%%% and every test case. If the former, all test cases in the suite
-%%% should be returned.
+%%% Called from test_server for every suite (Func==all)
+%%% and every test case. If the former, all test cases in the suite
+%%% should be returned.
get_suite(Mod, all) ->
case catch apply(Mod, groups, []) of
@@ -1168,7 +1168,7 @@ get_all(Mod, ConfTests) ->
case code:which(Mod) of
non_existing ->
list_to_atom(atom_to_list(Mod)++
- " can not be compiled or loaded");
+ " cannot be compiled or loaded");
_ ->
list_to_atom(atom_to_list(Mod)++":all/0 is missing")
end,
@@ -1355,7 +1355,7 @@ end_per_group(GroupName, _) ->
ok.
%%%-----------------------------------------------------------------
-%%% @spec report(What,Data) -> ok
+%%% -spec report(What,Data) -> ok
report(What,Data) ->
case What of
loginfo ->
@@ -1519,14 +1519,14 @@ add_to_stats(Result) ->
ct_util:update_testdata(stats, Update).
%%%-----------------------------------------------------------------
-%%% @spec warn(What) -> true | false
+%%% -spec warn(What) -> true | false
warn(What) when What==nodes; What==processes ->
false;
warn(_What) ->
true.
%%%-----------------------------------------------------------------
-%%% @spec add_data_dir(File0, Config) -> File1
+%%% -spec add_data_dir(File0, Config) -> File1
add_data_dir(File,Config) when is_atom(File) ->
add_data_dir(atom_to_list(File),Config);
@@ -1545,7 +1545,7 @@ add_data_dir(File,Config) when is_list(File) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec get_logopts() -> [LogOpt]
+%%% -spec get_logopts() -> [LogOpt]
get_logopts() ->
case ct_util:get_testdata(logopts) of
undefined ->
@@ -1555,12 +1555,12 @@ get_logopts() ->
end.
%%%-----------------------------------------------------------------
-%%% @spec format_comment(Comment) -> HtmlComment
+%%% -spec format_comment(Comment) -> HtmlComment
format_comment(Comment) ->
"<font color=\"green\">" ++ Comment ++ "</font>".
%%%-----------------------------------------------------------------
-%%% @spec get_html_wrapper(TestName, PrintLabel, Cwd) -> Header
+%%% -spec get_html_wrapper(TestName, PrintLabel, Cwd) -> Header
get_html_wrapper(TestName, PrintLabel, Cwd, TableCols) ->
get_html_wrapper(TestName, PrintLabel, Cwd, TableCols, utf8).
@@ -1568,6 +1568,6 @@ get_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding) ->
ct_logs:get_ts_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding).
%%%-----------------------------------------------------------------
-%%% @spec get_log_dir() -> {ok,LogDir}
+%%% -spec get_log_dir() -> {ok,LogDir}
get_log_dir() ->
ct_logs:get_log_dir(true).
diff --git a/lib/common_test/src/ct_ftp.erl b/lib/common_test/src/ct_ftp.erl
index 8b02ae3a0f..93d1f88041 100644
--- a/lib/common_test/src/ct_ftp.erl
+++ b/lib/common_test/src/ct_ftp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,12 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc FTP client module (based on the FTP application).
-%%%
-%%% @type connection() = handle() | ct:target_name()
-%%% @type handle() = ct_gen_conn:handle(). Handle for a specific
-%%% ftp connection.
-
-module(ct_ftp).
%% API
@@ -42,76 +36,14 @@
%%%=================================================================
%%% API
-%%%-----------------------------------------------------------------
-%%% @spec put(KeyOrName,LocalFile,RemoteFile) -> ok | {error,Reason}
-%%% KeyOrName = Key | Name
-%%% Key = atom()
-%%% Name = ct:target_name()
-%%% LocalFile = string()
-%%% RemoteFile = string()
-%%%
-%%% @doc Open a ftp connection and send a file to the remote host.
-%%%
-%%% <p><code>LocalFile</code> and <code>RemoteFile</code> must be
-%%% absolute paths.</p>
-%%%
-%%% <p>If the target host is a "special" node, the ftp address must be
-%%% specified in the config file like this:</p>
-%%% <pre>
-%%% {node,[{ftp,IpAddr}]}.</pre>
-%%%
-%%% <p>If the target host is something else, e.g. a unix host, the
-%%% config file must also include the username and password (both
-%%% strings):</p>
-%%% <pre>
-%%% {unix,[{ftp,IpAddr},
-%%% {username,Username},
-%%% {password,Password}]}.</pre>
-%%% @see ct:require/2
put(KeyOrName,LocalFile,RemoteFile) ->
Fun = fun(Ftp) -> send(Ftp,LocalFile,RemoteFile) end,
open_and_do(KeyOrName,Fun).
-%%%-----------------------------------------------------------------
-%%% @spec get(KeyOrName,RemoteFile,LocalFile) -> ok | {error,Reason}
-%%% KeyOrName = Key | Name
-%%% Key = atom()
-%%% Name = ct:target_name()
-%%% RemoteFile = string()
-%%% LocalFile = string()
-%%%
-%%% @doc Open a ftp connection and fetch a file from the remote host.
-%%%
-%%% <p><code>RemoteFile</code> and <code>LocalFile</code> must be
-%%% absolute paths.</p>
-%%%
-%%% <p>The config file must be as for put/3.</p>
-%%% @see put/3
-%%% @see ct:require/2
get(KeyOrName,RemoteFile,LocalFile) ->
Fun = fun(Ftp) -> recv(Ftp,RemoteFile,LocalFile) end,
open_and_do(KeyOrName,Fun).
-
-%%%-----------------------------------------------------------------
-%%% @spec open(KeyOrName) -> {ok,Handle} | {error,Reason}
-%%% KeyOrName = Key | Name
-%%% Key = atom()
-%%% Name = ct:target_name()
-%%% Handle = handle()
-%%%
-%%% @doc Open an FTP connection to the specified node.
-%%% <p>You can open one connection for a particular <code>Name</code> and
-%%% use the same name as reference for all subsequent operations. If you
-%%% want the connection to be associated with <code>Handle</code> instead
-%%% (in case you need to open multiple connections to a host for example),
-%%% simply use <code>Key</code>, the configuration variable name, to
-%%% specify the target. Note that a connection that has no associated target
-%%% name can only be closed with the handle value.</p>
-%%%
-%%% <p>See <c>ct:require/2</c> for how to create a new <c>Name</c></p>
-%%%
-%%% @see ct:require/2
open(KeyOrName) ->
case ct_util:get_key_from_name(KeyOrName) of
{ok,node} ->
@@ -152,25 +84,9 @@ open(KeyOrName,Username,Password) ->
ct_gen_conn:start(KeyOrName,full_addr(Addr),{Username,Password},?MODULE)
end.
-
-%%%-----------------------------------------------------------------
-%%% @spec send(Connection,LocalFile) -> ok | {error,Reason}
-%%%
-%%% @doc Send a file over FTP.
-%%% <p>The file will get the same name on the remote host.</p>
-%%% @see send/3
send(Connection,LocalFile) ->
send(Connection,LocalFile,filename:basename(LocalFile)).
-%%%-----------------------------------------------------------------
-%%% @spec send(Connection,LocalFile,RemoteFile) -> ok | {error,Reason}
-%%% Connection = connection()
-%%% LocalFile = string()
-%%% RemoteFile = string()
-%%%
-%%% @doc Send a file over FTP.
-%%%
-%%% <p>The file will be named <code>RemoteFile</code> on the remote host.</p>
send(Connection,LocalFile,RemoteFile) ->
case get_handle(Connection) of
{ok,Pid} ->
@@ -179,24 +95,9 @@ send(Connection,LocalFile,RemoteFile) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @spec recv(Connection,RemoteFile) -> ok | {error,Reason}
-%%%
-%%% @doc Fetch a file over FTP.
-%%% <p>The file will get the same name on the local host.</p>
-%%% @see recv/3
recv(Connection,RemoteFile) ->
recv(Connection,RemoteFile,filename:basename(RemoteFile)).
-%%%-----------------------------------------------------------------
-%%% @spec recv(Connection,RemoteFile,LocalFile) -> ok | {error,Reason}
-%%% Connection = connection()
-%%% RemoteFile = string()
-%%% LocalFile = string()
-%%%
-%%% @doc Fetch a file over FTP.
-%%%
-%%% <p>The file will be named <code>LocalFile</code> on the local host.</p>
recv(Connection,RemoteFile,LocalFile) ->
case get_handle(Connection) of
{ok,Pid} ->
@@ -205,12 +106,6 @@ recv(Connection,RemoteFile,LocalFile) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @spec cd(Connection,Dir) -> ok | {error,Reason}
-%%% Connection = connection()
-%%% Dir = string()
-%%%
-%%% @doc Change directory on remote host.
cd(Connection,Dir) ->
case get_handle(Connection) of
{ok,Pid} ->
@@ -219,13 +114,6 @@ cd(Connection,Dir) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @spec ls(Connection,Dir) -> {ok,Listing} | {error,Reason}
-%%% Connection = connection()
-%%% Dir = string()
-%%% Listing = string()
-%%%
-%%% @doc List the directory Dir.
ls(Connection,Dir) ->
case get_handle(Connection) of
{ok,Pid} ->
@@ -234,12 +122,6 @@ ls(Connection,Dir) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @spec type(Connection,Type) -> ok | {error,Reason}
-%%% Connection = connection()
-%%% Type = ascii | binary
-%%%
-%%% @doc Change file transfer type
type(Connection,Type) ->
case get_handle(Connection) of
{ok,Pid} ->
@@ -248,12 +130,6 @@ type(Connection,Type) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @spec delete(Connection,File) -> ok | {error,Reason}
-%%% Connection = connection()
-%%% File = string()
-%%%
-%%% @doc Delete a file on remote host
delete(Connection,File) ->
case get_handle(Connection) of
{ok,Pid} ->
@@ -262,11 +138,6 @@ delete(Connection,File) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @spec close(Connection) -> ok | {error,Reason}
-%%% Connection = connection()
-%%%
-%%% @doc Close the FTP connection.
close(Connection) ->
case get_handle(Connection) of
{ok,Pid} ->
@@ -279,7 +150,6 @@ close(Connection) ->
%%%=================================================================
%%% Callback functions
-%% @hidden
init(KeyOrName,{IP,Port},{Username,Password}) ->
case ftp_connect(IP,Port,Username,Password) of
{ok,FtpPid} ->
@@ -305,7 +175,6 @@ ftp_connect(IP,Port,Username,Password) ->
{error,{open,Reason}}
end.
-%% @hidden
handle_msg({send,LocalFile,RemoteFile},State) ->
log(heading(send,State#state.target_name),
"LocalFile: ~tp\nRemoteFile: ~tp\n",[LocalFile,RemoteFile]),
@@ -333,11 +202,9 @@ handle_msg({delete,File},State) ->
Result = ftp:delete(State#state.ftp_pid,File),
{Result,State}.
-%% @hidden
reconnect(_Addr,_State) ->
{error,no_reconnection_of_ftp}.
-%% @hidden
terminate(FtpPid,State) ->
log(heading(terminate,State#state.target_name),
"Closing FTP connection.\nHandle: ~p\n",[FtpPid]),
diff --git a/lib/common_test/src/ct_gen_conn.erl b/lib/common_test/src/ct_gen_conn.erl
index 456bfd8bd1..1ab9946d96 100644
--- a/lib/common_test/src/ct_gen_conn.erl
+++ b/lib/common_test/src/ct_gen_conn.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,9 +18,9 @@
%% %CopyrightEnd%
%%
-%%% @doc Generic connection owner process.
+%%% Generic connection owner process.
%%%
-%%% @type handle() = pid(). A handle for using a connection implemented
+%%% -type handle() = pid(). A handle for using a connection implemented
%%% with ct_gen_conn.erl.
-module(ct_gen_conn).
@@ -48,7 +48,7 @@
ct_util_server}).
%%%-----------------------------------------------------------------
-%%% @spec start(Address,InitData,CallbackMod,Opts) ->
+%%% -spec start(Address,InitData,CallbackMod,Opts) ->
%%% {ok,Handle} | {error,Reason}
%%% Name = term()
%%% CallbackMod = atom()
@@ -58,57 +58,52 @@
%%% Opt = {name,Name} | {use_existing_connection,boolean()} |
%%% {reconnect,boolean()} | {forward_messages,boolean()}
%%%
-%%% @doc Open a connection and start the generic connection owner process.
+%%% Open a connection and start the generic connection owner process.
%%%
-%%% <p>The <code>CallbackMod</code> is a specific callback module for
+%%% The CallbackMod is a specific callback module for
%%% each type of connection (e.g. telnet, ftp,...). It must export the
-%%% function <code>init/3</code> which takes the arguments
-%%% <code>Name</code>, <code>Addresse</code>) and
-%%% <code>InitData</code> and returna
-%%% <code>{ok,ConnectionPid,State}</code> or
-%%% <code>{error,Reason}</code>.</p>
+%%% function init/3 which takes the arguments
+%%% Name, Addresse) and
+%%% InitData and returna
+%%% {ok,ConnectionPid,State} or
+%%% {error,Reason}.
%%%
-%%% If no name is given, the <code>Name</code> argument in init/3 will
-%%% have the value <code>undefined</code>.
+%%% If no name is given, the Name argument in init/3 will
+%%% have the value undefined.
%%%
%%% The callback modules must also export
-%%% ```
+%%%
%%% handle_msg(Msg,From,State) -> {reply,Reply,State} |
%%% {noreply,State} |
%%% {stop,Reply,State}
%%% terminate(ConnectionPid,State) -> term()
%%% close(Handle) -> term()
-%%% '''
%%%
-%%% The <code>close/1</code> callback function is actually a callback
+%%% The close/1 callback function is actually a callback
%%% for ct_util, for closing registered connections when
-%%% ct_util_server is terminated. <code>Handle</code> is the Pid of
+%%% ct_util_server is terminated. Handle is the Pid of
%%% the ct_gen_conn process.
%%%
-%%% If option <code>reconnect</code> is <code>true</code>, then the
+%%% If option reconnect is true, then the
%%% callback must also export
-%%% ```
+%%%
%%% reconnect(Address,State) -> {ok,ConnectionPid,State}
-%%% '''
%%%
-%%% If option <code>forward_messages</code> is <ocde>true</code>, then
+%%% If option forward_messages is <ocde>true, then
%%% the callback must also export
-%%% ```
+%%%
%%% handle_msg(Msg,State) -> {noreply,State} | {stop,State}
-%%% '''
%%%
%%% An old interface still exists. This is used by ct_telnet, ct_ftp
%%% and ct_ssh. The start function then has an explicit
-%%% <code>Name</code> argument, and no <code>Opts</code> argument. The
+%%% Name argument, and no Opts argument. The
%%% callback must export:
%%%
-%%% ```
%%% init(Name,Address,InitData) -> {ok,ConnectionPid,State}
%%% handle_msg(Msg,State) -> {Reply,State}
%%% reconnect(Address,State) -> {ok,ConnectionPid,State}
%%% terminate(ConnectionPid,State) -> term()
%%% close(Handle) -> term()
-%%% '''
%%%
start(Address,InitData,CallbackMod,Opts) when is_list(Opts) ->
do_start(Address,InitData,CallbackMod,Opts);
@@ -116,73 +111,73 @@ start(Name,Address,InitData,CallbackMod) ->
do_start(Address,InitData,CallbackMod,[{name,Name},{old,true}]).
%%%-----------------------------------------------------------------
-%%% @spec stop(Handle) -> ok
+%%% -spec stop(Handle) -> ok
%%% Handle = handle()
%%%
-%%% @doc Close the connection and stop the process managing it.
+%%% Close the connection and stop the process managing it.
stop(Handle) ->
call(Handle,stop,5000).
%%%-----------------------------------------------------------------
-%%% @spec get_conn_pid(Handle) -> ok
+%%% -spec get_conn_pid(Handle) -> ok
%%% Handle = handle()
%%%
-%%% @doc Return the connection pid associated with Handle
+%%% Return the connection pid associated with Handle
get_conn_pid(Handle) ->
call(Handle,get_conn_pid).
%%%-----------------------------------------------------------------
-%%% @spec log(Heading,Format,Args) -> ok
+%%% -spec log(Heading,Format,Args) -> ok
%%%
-%%% @doc Log activities on the current connection (tool-internal use only).
-%%% @see ct_logs:log/3
+%%% Log activities on the current connection (tool-internal use only).
+%%% See ct_logs:log/3
log(Heading,Format,Args) ->
log(log,[Heading,Format,Args]).
%%%-----------------------------------------------------------------
-%%% @spec start_log(Heading) -> ok
+%%% -spec start_log(Heading) -> ok
%%%
-%%% @doc Log activities on the current connection (tool-internal use only).
-%%% @see ct_logs:start_log/1
+%%% Log activities on the current connection (tool-internal use only).
+%%% See ct_logs:start_log/1
start_log(Heading) ->
log(start_log,[Heading]).
%%%-----------------------------------------------------------------
-%%% @spec cont_log(Format,Args) -> ok
+%%% -spec cont_log(Format,Args) -> ok
%%%
-%%% @doc Log activities on the current connection (tool-internal use only).
-%%% @see ct_logs:cont_log/2
+%%% Log activities on the current connection (tool-internal use only).
+%%% See ct_logs:cont_log/2
cont_log(Format,Args) ->
log(cont_log,[Format,Args]).
%%%-----------------------------------------------------------------
-%%% @spec cont_log_no_timestamp(Format,Args) -> ok
+%%% -spec cont_log_no_timestamp(Format,Args) -> ok
%%%
-%%% @doc Log activities on the current connection (tool-internal use only).
-%%% @see ct_logs:cont_log/2
+%%% Log activities on the current connection (tool-internal use only).
+%%% See ct_logs:cont_log/2
cont_log_no_timestamp(Format,Args) ->
log(cont_log_no_timestamp,[Format,Args]).
%%%-----------------------------------------------------------------
-%%% @spec end_log() -> ok
+%%% -spec end_log() -> ok
%%%
-%%% @doc Log activities on the current connection (tool-internal use only).
-%%% @see ct_logs:end_log/0
+%%% Log activities on the current connection (tool-internal use only).
+%%% See ct_logs:end_log/0
end_log() ->
log(end_log,[]).
%%%-----------------------------------------------------------------
-%%% @spec do_within_time(Fun,Timeout) -> FunResult | {error,Reason}
+%%% -spec do_within_time(Fun,Timeout) -> FunResult | {error,Reason}
%%% Fun = function()
%%% Timeout = integer()
%%%
-%%% @doc Execute a function within a limited time (tool-internal use only).
+%%% Execute a function within a limited time (tool-internal use only).
%%%
-%%% <p>Execute the given <code>Fun</code>, but interrupt if it takes
-%%% more than <code>Timeout</code> milliseconds.</p>
+%%% Execute the given Fun, but interrupt if it takes
+%%% more than Timeout milliseconds.
%%%
-%%% <p>The execution is also interrupted if the connection is
-%%% closed.</p>
+%%% The execution is also interrupted if the connection is
+%%% closed.
do_within_time(Fun,Timeout) ->
Self = self(),
Silent = get(silent),
diff --git a/lib/common_test/src/ct_groups.erl b/lib/common_test/src/ct_groups.erl
index 2235365a0e..d867069dce 100644
--- a/lib/common_test/src/ct_groups.erl
+++ b/lib/common_test/src/ct_groups.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,11 +18,9 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework callback module.
-%%%
-%%% <p>This module contains CT internal help functions for searching
-%%% through groups specification trees and producing resulting
-%%% tests.</p>
+%%% This module contains CT internal help functions for searching
+%%% through groups specification trees and producing resulting
+%%% tests.
-module(ct_groups).
diff --git a/lib/common_test/src/ct_hooks.erl b/lib/common_test/src/ct_hooks.erl
index bb33f0243b..49587b3edd 100644
--- a/lib/common_test/src/ct_hooks.erl
+++ b/lib/common_test/src/ct_hooks.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,10 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework test execution control module.
-%%%
-%%% <p>This module is a proxy for calling and handling common test hooks.</p>
-
-module(ct_hooks).
%% API Exports
@@ -47,14 +43,12 @@
%% API Functions
%% -------------------------------------------------------------------------
-%% @doc Called before any suites are started
-spec init(State :: term()) -> ok |
{fail, Reason :: term()}.
init(Opts) ->
call(get_builtin_hooks(Opts) ++ get_new_hooks(Opts, undefined),
ok, init, []).
-%% @doc Called after all suites are done.
-spec terminate(Hooks :: term()) ->
ok.
terminate(Hooks) ->
@@ -63,8 +57,6 @@ terminate(Hooks) ->
ct_hooks_terminate_dummy, terminate, Hooks),
ok.
-%% @doc Called as each test case is started. This includes all configuration
-%% tests.
-spec init_tc(Mod :: atom(),
FuncSpec :: atom() |
{ConfigFunc :: init_per_testcase | end_per_testcase,
@@ -104,8 +96,6 @@ init_tc(Mod, {end_per_testcase,TC}, Config) ->
init_tc(Mod, TC = error_in_suite, Config) ->
call(fun call_generic_fallback/3, Config, [pre_init_per_testcase, Mod, TC]).
-%% @doc Called as each test case is completed. This includes all configuration
-%% tests.
-spec end_tc(Mod :: atom(),
FuncSpec :: atom() |
{ConfigFunc :: init_per_testcase | end_per_testcase,
diff --git a/lib/common_test/src/ct_hooks_lock.erl b/lib/common_test/src/ct_hooks_lock.erl
index a82be288e1..be50a33e01 100644
--- a/lib/common_test/src/ct_hooks_lock.erl
+++ b/lib/common_test/src/ct_hooks_lock.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,11 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework test execution control module.
-%%%
-%%% <p>This module is a proxy for calling and handling locks in
-%%% common test hooks.</p>
-
-module(ct_hooks_lock).
-behaviour(gen_server).
@@ -42,7 +37,6 @@
%%% API
%%%===================================================================
-%% @doc Starts the server
start(Id) ->
case gen_server:start({local, ?SERVER}, ?MODULE, Id, []) of
{error,{already_started, Pid}} ->
@@ -76,12 +70,10 @@ release() ->
%%% gen_server callbacks
%%%===================================================================
-%% @doc Initiates the server
init(Id) ->
ct_util:mark_process(),
{ok, #state{ id = Id }}.
-%% @doc Handling call messages
handle_call({stop,Id}, _From, #state{ id = Id, requests = Reqs } = State) ->
_ = [gen_server:reply(Req, locker_stopped) || {Req,_ReqId} <- Reqs],
{stop, normal, stopped, State};
@@ -108,11 +100,9 @@ handle_call({release, Pid}, _From,
handle_call({release, _Pid}, _From, State) ->
{reply, not_locked, State}.
-%% @doc Handling cast messages
handle_cast(_Msg, State) ->
{noreply, State}.
-%% @doc Handling all non call/cast messages
handle_info({'DOWN',Ref,process,Pid,_},
#state{ locked = {true, Pid, Ref},
requests = [{NextFrom,NextPid}|Rest] } = State) ->
@@ -121,11 +111,9 @@ handle_info({'DOWN',Ref,process,Pid,_},
{noreply,State#state{ locked = {true, NextPid, NextRef},
requests = Rest } }.
-%% @doc This function is called by a gen_server when it is about to terminate.
terminate(_Reason, _State) ->
ok.
-%% @doc Convert process state when code is changed
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl
index 9861b1e521..07a1693d5d 100644
--- a/lib/common_test/src/ct_logs.erl
+++ b/lib/common_test/src/ct_logs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,14 +18,12 @@
%% %CopyrightEnd%
%%
-%%% @doc Logging functionality for Common Test Framework.
+%%% Logging functionality for Common Test Framework.
%%%
-%%% <p>This module implements
-%%% <ul>
-%%% <li>Internal logging of activities in Common Test Framework</li>
-%%% <li>Compilation of test results into index pages on several levels</li>
-%%% </ul>
-%%% </p>
+%%% This module implements:
+%%%
+%%% Internal logging of activities in Common Test Framework, and
+%%% Compilation of test results into index pages on several levels
-module(ct_logs).
@@ -84,17 +82,17 @@
tests = []}).
%%%-----------------------------------------------------------------
-%%% @spec init(Mode, Verbosity) -> Result
+%%% -spec init(Mode, Verbosity) -> Result
%%% Mode = normal | interactive
%%% Result = {StartTime,LogDir}
%%% StartTime = term()
%%% LogDir = string()
%%%
-%%% @doc Initiate the logging mechanism (tool-internal use only).
+%%% Initiate the logging mechanism (tool-internal use only).
%%%
-%%% <p>This function is called by ct_util.erl when testing is
-%%% started. A new directory named ct_run.&lt;timestamp&gt; is created
-%%% and all logs are stored under this directory.</p>
+%%% This function is called by ct_util.erl when testing is
+%%% started. A new directory named ct_run.<timestamp> is created
+%%% and all logs are stored under this directory.
%%%
init(Mode, Verbosity) ->
Self = self(),
@@ -129,9 +127,9 @@ datestr_from_dirname([]) ->
"".
%%%-----------------------------------------------------------------
-%%% @spec close(Info, StartDir) -> ok
+%%% -spec close(Info, StartDir) -> ok
%%%
-%%% @doc Create index pages with test results and close the CT Log
+%%% Create index pages with test results and close the CT Log
%%% (tool-internal use only).
close(Info, StartDir) ->
%% close executes on the ct_util process, not on the logger process
@@ -204,22 +202,22 @@ close(Info, StartDir) ->
ok.
%%%-----------------------------------------------------------------
-%%% @spec set_stylesheet(TC,SSFile) -> ok
+%%% -spec set_stylesheet(TC,SSFile) -> ok
set_stylesheet(TC, SSFile) ->
cast({set_stylesheet,TC,SSFile}).
%%%-----------------------------------------------------------------
-%%% @spec clear_stylesheet(TC) -> ok
+%%% -spec clear_stylesheet(TC) -> ok
clear_stylesheet(TC) ->
cast({clear_stylesheet,TC}).
%%%-----------------------------------------------------------------
-%%% @spec get_log_dir() -> {ok,Dir} | {error,Reason}
+%%% -spec get_log_dir() -> {ok,Dir} | {error,Reason}
get_log_dir() ->
get_log_dir(false).
%%%-----------------------------------------------------------------
-%%% @spec get_log_dir(ReturnAbsName) -> {ok,Dir} | {error,Reason}
+%%% -spec get_log_dir(ReturnAbsName) -> {ok,Dir} | {error,Reason}
get_log_dir(ReturnAbsName) ->
case call({get_log_dir,ReturnAbsName}) of
{error,does_not_exist} when ReturnAbsName == true ->
@@ -278,58 +276,58 @@ get_format_args(Content) ->
end, Content).
%%%-----------------------------------------------------------------
-%%% @spec init_tc(RefreshLog) -> ok
+%%% -spec init_tc(RefreshLog) -> ok
%%%
-%%% @doc Test case initiation (tool-internal use only).
+%%% Test case initiation (tool-internal use only).
%%%
-%%% <p>This function is called by ct_framework:init_tc/3</p>
+%%% This function is called by ct_framework:init_tc/3
init_tc(RefreshLog) ->
call({init_tc,self(),group_leader(),RefreshLog}),
tc_io_format(group_leader(), xhtml("", "<br />"), []),
ok.
%%%-----------------------------------------------------------------
-%%% @spec end_tc(TCPid) -> ok
+%%% -spec end_tc(TCPid) -> ok
%%%
-%%% @doc Test case clean up (tool-internal use only).
+%%% Test case clean up (tool-internal use only).
%%%
-%%% <p>This function is called by ct_framework:end_tc/3</p>
+%%% This function is called by ct_framework:end_tc/3
end_tc(TCPid) ->
%% use call here so that the TC process will wait and receive
%% possible exit signals from ct_logs before end_tc returns ok
call({end_tc,TCPid}).
%%%-----------------------------------------------------------------
-%%% @spec register_groupleader(Pid,GroupLeader) -> ok
+%%% -spec register_groupleader(Pid,GroupLeader) -> ok
%%%
-%%% @doc To enable logging to a group leader (tool-internal use only).
+%%% To enable logging to a group leader (tool-internal use only).
%%%
-%%% <p>This function is called by ct_framework:report/2</p>
+%%% This function is called by ct_framework:report/2
register_groupleader(Pid,GroupLeader) ->
call({register_groupleader,Pid,GroupLeader}),
ok.
%%%-----------------------------------------------------------------
-%%% @spec unregister_groupleader(Pid) -> ok
+%%% -spec unregister_groupleader(Pid) -> ok
%%%
-%%% @doc To disable logging to a group leader (tool-internal use only).
+%%% To disable logging to a group leader (tool-internal use only).
%%%
-%%% <p>This function is called by ct_framework:report/2</p>
+%%% This function is called by ct_framework:report/2
unregister_groupleader(Pid) ->
call({unregister_groupleader,Pid}),
ok.
%%%-----------------------------------------------------------------
-%%% @spec log(Heading,Format,Args) -> ok
+%%% -spec log(Heading,Format,Args) -> ok
%%%
-%%% @doc Log internal activity (tool-internal use only).
+%%% Log internal activity (tool-internal use only).
%%%
-%%% <p>This function writes an entry to the currently active log,
-%%% i.e. either the CT log or a test case log.</p>
+%%% This function writes an entry to the currently active log,
+%%% i.e. either the CT log or a test case log.
%%%
-%%% <p><code>Heading</code> is a short string indicating what type of
-%%% activity it is. <code>Format</code> and <code>Args</code> is the
-%%% data to log (as in <code>io:format(Format,Args)</code>).</p>
+%%% Heading is a short string indicating what type of
+%%% activity it is. Format and Args is the
+%%% data to log (as in io:format(Format,Args)).
log(Heading,Format,Args) ->
cast({log,sync,self(),group_leader(),ct_internal,?MAX_IMPORTANCE,
[{hd,int_header(),[log_timestamp(?now),Heading]},
@@ -339,32 +337,29 @@ log(Heading,Format,Args) ->
ok.
%%%-----------------------------------------------------------------
-%%% @spec start_log(Heading) -> ok
+%%% -spec start_log(Heading) -> ok
%%%
-%%% @doc Starts the logging of an activity (tool-internal use only).
+%%% Starts the logging of an activity (tool-internal use only).
%%%
-%%% <p>This function must be used in combination with
-%%% <code>cont_log/2</code> and <code>end_log/0</code>. The intention
-%%% is to call <code>start_log</code> once, then <code>cont_log</code>
-%%% any number of times and finally <code>end_log</code> once.</p>
+%%% This function must be used in combination with
+%%% cont_log/2 and end_log/0. The intention
+%%% is to call start_log once, then cont_log
+%%% any number of times and finally end_log once.
%%%
-%%% <p>For information about the parameters, see <code>log/3</code>.</p>
+%%% For information about the parameters, see log/3.
%%%
-%%% @see log/3
-%%% @see cont_log/2
-%%% @see end_log/0
+%%% See log/3, cont_log/2, and end_log/0.
start_log(Heading) ->
cast({log,sync,self(),group_leader(),ct_internal,?MAX_IMPORTANCE,
[{hd,int_header(),[log_timestamp(?now),Heading]}],false}),
ok.
%%%-----------------------------------------------------------------
-%%% @spec cont_log(Format,Args) -> ok
+%%% -spec cont_log(Format,Args) -> ok
%%%
-%%% @doc Adds information about an activity (tool-internal use only).
+%%% Adds information about an activity (tool-internal use only).
%%%
-%%% @see start_log/1
-%%% @see end_log/0
+%%% See start_log/1 and end_log/0.
cont_log([],[]) ->
ok;
cont_log(Format,Args) ->
@@ -374,12 +369,11 @@ cont_log(Format,Args) ->
ok.
%%%-----------------------------------------------------------------
-%%% @spec cont_log_no_timestamp(Format,Args) -> ok
+%%% -spec cont_log_no_timestamp(Format,Args) -> ok
%%%
-%%% @doc Adds information about an activity (tool-internal use only).
+%%% Adds information about an activity (tool-internal use only).
%%%
-%%% @see start_log/1
-%%% @see end_log/0
+%%% See start_log/1 and end_log/0.
cont_log_no_timestamp([],[]) ->
ok;
cont_log_no_timestamp(Format,Args) ->
@@ -388,12 +382,11 @@ cont_log_no_timestamp(Format,Args) ->
ok.
%%%-----------------------------------------------------------------
-%%% @spec end_log() -> ok
+%%% -spec end_log() -> ok
%%%
-%%% @doc Ends the logging of an activity (tool-internal use only).
+%%% Ends the logging of an activity (tool-internal use only).
%%%
-%%% @see start_log/1
-%%% @see cont_log/2
+%%% See start_log/1 and cont_log/2.
end_log() ->
cast({log,sync,self(),group_leader(),ct_internal,?MAX_IMPORTANCE,
[{ft,int_footer(), []}],false}),
@@ -401,15 +394,15 @@ end_log() ->
%%%-----------------------------------------------------------------
-%%% @spec add_external_logs(Logs) -> ok
+%%% -spec add_external_logs(Logs) -> ok
%%% Logs = [Log]
%%% Log = string()
%%%
-%%% @doc Print a link to each given <code>Log</code> in the test case
+%%% Print a link to each given Log in the test case
%%% log.
%%%
-%%% <p>The given <code>Logs</code> must exist in the priv dir of the
-%%% calling test suite.</p>
+%%% The given Logs must exist in the priv dir of the
+%%% calling test suite.
add_external_logs(Logs) ->
start_log("External Logs"),
[cont_log("<a href=\"~ts\">~ts</a>\n",
@@ -417,12 +410,12 @@ add_external_logs(Logs) ->
end_log().
%%%-----------------------------------------------------------------
-%%% @spec add_link(Heading,File,Type) -> ok
+%%% -spec add_link(Heading,File,Type) -> ok
%%% Heading = string()
%%% File = string()
%%% Type = string()
%%%
-%%% @doc Print a link to a given file stored in the priv_dir of the
+%%% Print a link to a given file stored in the priv_dir of the
%%% calling test suite.
add_link(Heading,File,Type) ->
log(Heading,"<a href=\"~ts\" type=~tp>~ts</a>\n",
@@ -430,25 +423,25 @@ add_link(Heading,File,Type) ->
%%%-----------------------------------------------------------------
-%%% @spec tc_log(Category,Format,Args) -> ok
-%%% @equiv tc_log(Category,?STD_IMPORTANCE,Format,Args)
+%%% -spec tc_log(Category,Format,Args) -> ok
+%%% Equivalent to tc_log(Category,?STD_IMPORTANCE,Format,Args)
tc_log(Category,Format,Args) ->
tc_log(Category,?STD_IMPORTANCE,"User",Format,Args,[]).
%%%-----------------------------------------------------------------
-%%% @spec tc_log(Category,Importance,Format,Args) -> ok
-%%% @equiv tc_log(Category,Importance,"User",Format,Args)
+%%% -spec tc_log(Category,Importance,Format,Args) -> ok
+%%% Equivalent to tc_log(Category,Importance,"User",Format,Args)
tc_log(Category,Importance,Format,Args) ->
tc_log(Category,Importance,"User",Format,Args,[]).
%%%-----------------------------------------------------------------
-%%% @spec tc_log(Category,Importance,Format,Args) -> ok
-%%% @equiv tc_log(Category,Importance,"User",Format,Args)
+%%% -spec tc_log(Category,Importance,Format,Args) -> ok
+%%% Equivalent to tc_log(Category,Importance,"User",Format,Args)
tc_log(Category,Importance,Format,Args,Opts) ->
tc_log(Category,Importance,"User",Format,Args,Opts).
%%%-----------------------------------------------------------------
-%%% @spec tc_log(Category,Importance,Heading,Format,Args,Opts) -> ok
+%%% -spec tc_log(Category,Importance,Heading,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
%%% Heading = string()
@@ -456,11 +449,11 @@ tc_log(Category,Importance,Format,Args,Opts) ->
%%% Args = list()
%%% Opts = list()
%%%
-%%% @doc Printout from a testcase.
+%%% Printout from a testcase.
%%%
-%%% <p>This function is called by <code>ct</code> when logging
+%%% This function is called by ct when logging
%%% stuff directly from a testcase (i.e. not from within the CT
-%%% framework).</p>
+%%% framework).
tc_log(Category,Importance,Heading,Format,Args,Opts) ->
Data =
case lists:member(no_css, Opts) of
@@ -481,26 +474,26 @@ tc_log(Category,Importance,Heading,Format,Args,Opts) ->
ok.
%%%-----------------------------------------------------------------
-%%% @spec tc_log_async(Category,Format,Args) -> ok
-%%% @equiv tc_log_async(Category,?STD_IMPORTANCE,"User",Format,Args)
+%%% -spec tc_log_async(Category,Format,Args) -> ok
+%%% Equivalent to tc_log_async(Category,?STD_IMPORTANCE,"User",Format,Args)
tc_log_async(Category,Format,Args) ->
tc_log_async(Category,?STD_IMPORTANCE,"User",Format,Args).
%%%-----------------------------------------------------------------
-%%% @spec tc_log_async(Category,Importance,Format,Args) -> ok
+%%% -spec tc_log_async(Category,Importance,Format,Args) -> ok
%%% Category = atom()
%%% Importance = integer()
%%% Heading = string()
%%% Format = string()
%%% Args = list()
%%%
-%%% @doc Internal use only.
+%%% Internal use only.
%%%
-%%% <p>This function is used to perform asynchronous printouts
+%%% This function is used to perform asynchronous printouts
%%% towards the test server IO handler. This is necessary in order
%%% to avoid deadlocks when e.g. the hook that handles SASL printouts
%%% prints to the test case log file at the same time test server
-%%% asks ct_logs for an html wrapper.</p>
+%%% asks ct_logs for an html wrapper.
tc_log_async(Category,Importance,Heading,Format,Args) ->
cast({log,async,self(),group_leader(),Category,Importance,
[{hd,div_header(Category,Heading),[]},
@@ -509,29 +502,29 @@ tc_log_async(Category,Importance,Heading,Format,Args) ->
true}),
ok.
%%%-----------------------------------------------------------------
-%%% @spec tc_print(Category,Format,Args)
-%%% @equiv tc_print(Category,?STD_IMPORTANCE,Format,Args,[])
+%%% -spec tc_print(Category,Format,Args)
+%%% Equivalent to tc_print(Category,?STD_IMPORTANCE,Format,Args,[])
tc_print(Category,Format,Args) ->
tc_print(Category,?STD_IMPORTANCE,Format,Args,[]).
%%%-----------------------------------------------------------------
-%%% @spec tc_print(Category,Importance,Format,Args)
-%%% @equiv tc_print(Category,Importance,Format,Args,[])
+%%% -spec tc_print(Category,Importance,Format,Args)
+%%% Equivalent to tc_print(Category,Importance,Format,Args,[])
tc_print(Category,Importance,Format,Args) ->
tc_print(Category,Importance,Format,Args,[]).
%%%-----------------------------------------------------------------
-%%% @spec tc_print(Category,Importance,Format,Args,Opts) -> ok
+%%% -spec tc_print(Category,Importance,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
%%% Format = string()
%%% Args = list()
%%% Opts = list()
%%%
-%%% @doc Console printout from a testcase.
+%%% Console printout from a testcase.
%%%
-%%% <p>This function is called by <code>ct</code> when printing
-%%% stuff from a testcase on the user console.</p>
+%%% This function is called by ct when printing
+%%% stuff from a testcase on the user console.
tc_print(Category,Importance,Format,Args,Opts) ->
VLvl = case ct_util:get_verbosity(Category) of
undefined ->
@@ -572,44 +565,44 @@ get_header(Heading) ->
%%%-----------------------------------------------------------------
-%%% @spec tc_pal(Category,Format,Args) -> ok
-%%% @equiv tc_pal(Category,?STD_IMPORTANCE,Format,Args,[]) -> ok
+%%% -spec tc_pal(Category,Format,Args) -> ok
+%%% Equivalent to tc_pal(Category,?STD_IMPORTANCE,Format,Args,[]) -> ok
tc_pal(Category,Format,Args) ->
tc_pal(Category,?STD_IMPORTANCE,Format,Args,[]).
%%%-----------------------------------------------------------------
-%%% @spec tc_pal(Category,Importance,Format,Args) -> ok
-%%% @equiv tc_pal(Category,Importance,Format,Args,[]) -> ok
+%%% -spec tc_pal(Category,Importance,Format,Args) -> ok
+%%% Equivalent to tc_pal(Category,Importance,Format,Args,[]) -> ok
tc_pal(Category,Importance,Format,Args) ->
tc_pal(Category,Importance,Format,Args,[]).
%%%-----------------------------------------------------------------
-%%% @spec tc_pal(Category,Importance,Format,Args,Opts) -> ok
+%%% -spec tc_pal(Category,Importance,Format,Args,Opts) -> ok
%%% Category = atom()
%%% Importance = integer()
%%% Format = string()
%%% Args = list()
%%% Opts = list()
%%%
-%%% @doc Print and log from a testcase.
+%%% Print and log from a testcase.
%%%
-%%% <p>This function is called by <code>ct</code> when logging
+%%% This function is called by ct when logging
%%% stuff directly from a testcase. The info is written both in the
-%%% log and on the console.</p>
+%%% log and on the console.
tc_pal(Category,Importance,Format,Args,Opts) ->
tc_print(Category,Importance,Format,Args,Opts),
tc_log(Category,Importance,"User",Format,Args,[esc_chars|Opts]).
%%%-----------------------------------------------------------------
-%%% @spec ct_log(Category,Format,Args) -> ok
+%%% -spec ct_log(Category,Format,Args) -> ok
%%% Category = atom()
%%% Format = string()
%%% Args = list()
%%%
-%%% @doc Print to the ct framework log
+%%% Print to the ct framework log
%%%
-%%% <p>This function is called by internal ct functions to
-%%% force logging to the ct framework log</p>
+%%% This function is called by internal ct functions to
+%%% force logging to the ct framework log
ct_log(Category,Format,Args) ->
cast({ct_log,[{hd,div_header(Category),[]},
{Format,Args},
@@ -2993,13 +2986,13 @@ rm_files([]) ->
ok.
%%%-----------------------------------------------------------------
-%%% @spec simulate() -> pid()
+%%% -spec simulate() -> pid()
%%%
-%%% @doc Simulate the logger process.
+%%% Simulate the logger process.
%%%
-%%% <p>Simulate the logger process - for use when testing code using
+%%% Simulate the logger process - for use when testing code using
%%% ct_logs logging mechanism without using the ct
-%%% environment. (E.g. when testing code with ts)</p>
+%%% environment. (E.g. when testing code with ts)
simulate() ->
cast(stop),
S = self(),
@@ -3027,9 +3020,7 @@ simulate_logger_loop() ->
end.
%%%-----------------------------------------------------------------
-%%% @spec notify_and_lock_file(Files) -> ok
-%%%
-%%% @doc
+%%% -spec notify_and_lock_file(Files) -> ok
%%%
notify_and_lock_file(File) ->
case ct_event:is_alive() of
@@ -3042,9 +3033,7 @@ notify_and_lock_file(File) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec notify_and_unlock_file(Files) -> ok
-%%%
-%%% @doc
+%%% -spec notify_and_unlock_file(Files) -> ok
%%%
notify_and_unlock_file(File) ->
case ct_event:is_alive() of
@@ -3057,9 +3046,7 @@ notify_and_unlock_file(File) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec get_run_dirs(Dir) -> [string()] | false
-%%%
-%%% @doc
+%%% -spec get_run_dirs(Dir) -> [string()] | false
%%%
get_run_dirs(Dir) ->
case filelib:wildcard(filename:join(Dir, "run.[1-2]*")) of
@@ -3070,9 +3057,7 @@ get_run_dirs(Dir) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec xhtml(HTML, XHTML) -> HTML | XHTML
-%%%
-%%% @doc
+%%% -spec xhtml(HTML, XHTML) -> HTML | XHTML
%%%
xhtml(HTML, XHTML) when is_function(HTML),
is_function(XHTML) ->
@@ -3087,9 +3072,7 @@ xhtml(HTML, XHTML) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec odd_or_even() -> "odd" | "even"
-%%%
-%%% @doc
+%%% -spec odd_or_even() -> "odd" | "even"
%%%
odd_or_even() ->
case get(odd_or_even) of
@@ -3102,9 +3085,7 @@ odd_or_even() ->
end.
%%%-----------------------------------------------------------------
-%%% @spec basic_html() -> true | false
-%%%
-%%% @doc
+%%% -spec basic_html() -> true | false
%%%
basic_html() ->
case application:get_env(common_test, basic_html) of
@@ -3115,9 +3096,7 @@ basic_html() ->
end.
%%%-----------------------------------------------------------------
-%%% @spec locate_priv_file(FileName) -> PrivFile
-%%%
-%%% @doc
+%%% -spec locate_priv_file(FileName) -> PrivFile
%%%
locate_priv_file(FileName) ->
{ok,CWD} = file:get_cwd(),
@@ -3147,13 +3126,13 @@ locate_priv_file(FileName) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec make_relative(AbsDir, Cwd) -> RelDir
+%%% -spec make_relative(AbsDir, Cwd) -> RelDir
%%%
-%%% @doc Return directory path to File (last element of AbsDir), which
-%%% is the path relative to Cwd. Examples when Cwd == "/ldisk/test/logs":
-%%% make_relative("/ldisk/test/logs/run/trace.log") -> "run/trace.log"
-%%% make_relative("/ldisk/test/trace.log") -> "../trace.log"
-%%% make_relative("/ldisk/test/logs/trace.log") -> "trace.log"
+%%% Return directory path to File (last element of AbsDir), which
+%%% is the path relative to Cwd. Examples when Cwd == "/ldisk/test/logs":
+%%% make_relative("/ldisk/test/logs/run/trace.log") -> "run/trace.log"
+%%% make_relative("/ldisk/test/trace.log") -> "../trace.log"
+%%% make_relative("/ldisk/test/logs/trace.log") -> "trace.log"
make_relative(AbsDir) ->
{ok,Cwd} = file:get_cwd(),
make_relative(AbsDir, Cwd).
@@ -3177,11 +3156,9 @@ make_relative1(DirTs, CwdTs) ->
Ups ++ DirTs.
%%%-----------------------------------------------------------------
-%%% @spec get_ts_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding)
+%%% -spec get_ts_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding)
%%% -> {Mode,Header,Footer}
%%%
-%%% @doc
-%%%
get_ts_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding) ->
get_ts_html_wrapper(TestName, undefined, PrintLabel, Cwd, TableCols, Encoding).
diff --git a/lib/common_test/src/ct_master.erl b/lib/common_test/src/ct_master.erl
index e2ea525cdd..fd33ee2280 100644
--- a/lib/common_test/src/ct_master.erl
+++ b/lib/common_test/src/ct_master.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,9 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc Distributed test execution control for Common Test.
-%%% <p>This module exports functions for running Common Test nodes
-%%% on multiple hosts in parallel.</p>
-module(ct_master).
-export([run/1,run/3,run/4]).
@@ -45,50 +42,14 @@
blocked=[]
}).
-%%%-----------------------------------------------------------------
-%%% @spec run_test(Node,Opts) -> ok
-%%% Node = atom()
-%%% Opts = [OptTuples]
-%%% OptTuples = {config,CfgFiles} | {dir,TestDirs} | {suite,Suites} |
-%%% {testcase,Cases} | {spec,TestSpecs} | {allow_user_terms,Bool} |
-%%% {logdir,LogDir} | {event_handler,EventHandlers} |
-%%% {silent_connections,Conns} | {cover,CoverSpecFile} |
-%%% {cover_stop,Bool} | {userconfig, UserCfgFiles}
-%%% CfgFiles = string() | [string()]
-%%% TestDirs = string() | [string()]
-%%% Suites = atom() | [atom()]
-%%% Cases = atom() | [atom()]
-%%% TestSpecs = string() | [string()]
-%%% LogDir = string()
-%%% EventHandlers = EH | [EH]
-%%% EH = atom() | {atom(),InitArgs} | {[atom()],InitArgs}
-%%% InitArgs = [term()]
-%%% Conns = all | [atom()]
-%%%
-%%% @doc Tests are spawned on <code>Node</code> using <code>ct:run_test/1</code>.
run_test(Node,Opts) ->
run_test([{Node,Opts}]).
-%%% @hidden
run_test({Node,Opts}) ->
run_test([{Node,Opts}]);
run_test(NodeOptsList) when is_list(NodeOptsList) ->
start_master(NodeOptsList).
-%%%-----------------------------------------------------------------
-%%% @spec run(TestSpecs,AllowUserTerms,InclNodes,ExclNodes) -> ok
-%%% TestSpecs = string() | [SeparateOrMerged]
-%%% SeparateOrMerged = string() | [string()]
-%%% AllowUserTerms = bool()
-%%% InclNodes = [atom()]
-%%% ExclNodes = [atom()]
-%%%
-%%% @doc Tests are spawned on the nodes as specified in <code>TestSpecs</code>.
-%%% Each specification in TestSpec will be handled separately. It is however
-%%% possible to also specify a list of specifications that should be merged
-%%% into one before the tests are executed. Any test without a particular node
-%%% specification will also be executed on the nodes in <code>InclNodes</code>.
-%%% Nodes in the <code>ExclNodes</code> list will be excluded from the test.
run([TS|TestSpecs],AllowUserTerms,InclNodes,ExclNodes) when is_list(TS),
is_list(InclNodes),
is_list(ExclNodes) ->
@@ -128,22 +89,9 @@ run(TS,AllowUserTerms,InclNodes,ExclNodes) when is_list(InclNodes),
is_list(ExclNodes) ->
run([TS],AllowUserTerms,InclNodes,ExclNodes).
-%%%-----------------------------------------------------------------
-%%% @spec run(TestSpecs,InclNodes,ExclNodes) -> ok
-%%% TestSpecs = string() | [SeparateOrMerged]
-%%% SeparateOrMerged = string() | [string()]
-%%% InclNodes = [atom()]
-%%% ExclNodes = [atom()]
-%%%
-%%% @equiv run(TestSpecs,false,InclNodes,ExclNodes)
run(TestSpecs,InclNodes,ExclNodes) ->
run(TestSpecs,false,InclNodes,ExclNodes).
-%%%-----------------------------------------------------------------
-%%% @spec run(TestSpecs) -> ok
-%%% TestSpecs = string() | [SeparateOrMerged]
-%%%
-%%% @equiv run(TestSpecs,false,[],[])
run(TestSpecs=[TS|_]) when is_list(TS) ->
run(TestSpecs,false,[],[]);
run(TS) ->
@@ -156,15 +104,6 @@ exclude_nodes([],RunSkipPerNode) ->
RunSkipPerNode.
-%%%-----------------------------------------------------------------
-%%% @spec run_on_node(TestSpecs,AllowUserTerms,Node) -> ok
-%%% TestSpecs = string() | [SeparateOrMerged]
-%%% SeparateOrMerged = string() | [string()]
-%%% AllowUserTerms = bool()
-%%% Node = atom()
-%%%
-%%% @doc Tests are spawned on <code>Node</code> according to
-%%% <code>TestSpecs</code>.
run_on_node([TS|TestSpecs],AllowUserTerms,Node) when is_list(TS),is_atom(Node) ->
case catch ct_testspec:collect_tests_from_file([TS],[Node],
AllowUserTerms) of
@@ -194,13 +133,6 @@ run_on_node([],_,_) ->
run_on_node(TS,AllowUserTerms,Node) when is_atom(Node) ->
run_on_node([TS],AllowUserTerms,Node).
-%%%-----------------------------------------------------------------
-%%% @spec run_on_node(TestSpecs,Node) -> ok
-%%% TestSpecs = string() | [SeparateOrMerged]
-%%% SeparateOrMerged = string() | [string()]
-%%% Node = atom()
-%%%
-%%% @equiv run_on_node(TestSpecs,false,Node)
run_on_node(TestSpecs,Node) ->
run_on_node(TestSpecs,false,Node).
@@ -264,64 +196,25 @@ run_all([],AllLogDirs,_,AllEvHs,_AllIncludes,
ok.
-%%%-----------------------------------------------------------------
-%%% @spec abort() -> ok
-%%%
-%%% @doc Stops all running tests.
abort() ->
call(abort).
-%%%-----------------------------------------------------------------
-%%% @spec abort(Nodes) -> ok
-%%% Nodes = atom() | [atom()]
-%%%
-%%% @doc Stops tests on specified nodes.
abort(Nodes) when is_list(Nodes) ->
call({abort,Nodes});
abort(Node) when is_atom(Node) ->
abort([Node]).
-%%%-----------------------------------------------------------------
-%%% @spec progress() -> [{Node,Status}]
-%%% Node = atom()
-%%% Status = finished_ok | ongoing | aborted | {error,Reason}
-%%% Reason = term()
-%%%
-%%% @doc Returns test progress. If <code>Status</code> is <code>ongoing</code>,
-%%% tests are running on the node and have not yet finished.
progress() ->
call(progress).
-%%%-----------------------------------------------------------------
-%%% @spec get_event_mgr_ref() -> MasterEvMgrRef
-%%% MasterEvMgrRef = atom()
-%%%
-%%% @doc <p>Call this function in order to get a reference to the
-%%% CT master event manager. The reference can be used to e.g.
-%%% add a user specific event handler while tests are running.
-%%% Example:
-%%% <c>gen_event:add_handler(ct_master:get_event_mgr_ref(), my_ev_h, [])</c></p>
get_event_mgr_ref() ->
?CT_MEVMGR_REF.
-%%%-----------------------------------------------------------------
-%%% @spec basic_html(Bool) -> ok
-%%% Bool = true | false
-%%%
-%%% @doc If set to true, the ct_master logs will be written on a
-%%% primitive html format, not using the Common Test CSS style
-%%% sheet.
basic_html(Bool) ->
application:set_env(common_test_master, basic_html, Bool),
ok.
-%%%-----------------------------------------------------------------
-%%% @spec esc_chars(Bool) -> ok
-%%% Bool = true | false
-%%%
-%%% @doc If set to false, the ct_master logs will be written without
-%%% special characters being escaped in the HTML logs.
esc_chars(Bool) ->
application:set_env(common_test_master, esc_chars, Bool),
ok.
@@ -340,7 +233,6 @@ start_master(NodeOptsList,EvHandlers,MasterLogDir,LogDirs,InitOptions,Specs) ->
{Master,Result} -> Result
end.
-%%% @hidden
init_master(Parent,NodeOptsList,EvHandlers,MasterLogDir,LogDirs,
InitOptions,Specs) ->
case whereis(ct_master) of
@@ -687,7 +579,6 @@ refresh_logs([],Refreshed) ->
%%%-----------------------------------------------------------------
%%% NODE CONTROLLER, runs and controls tests on a test node.
%%%-----------------------------------------------------------------
-%%% @hidden
init_node_ctrl(MasterPid,Cookie,Opts) ->
%% make sure tests proceed even if connection to master is lost
process_flag(trap_exit, true),
@@ -742,7 +633,6 @@ start_ct_event() ->
%%%-----------------------------------------------------------------
%%% Event handling
%%%-----------------------------------------------------------------
-%%% @hidden
status(MasterPid,Event=#event{name=start_make}) ->
call(MasterPid,Event);
status(MasterPid,Event=#event{name=finished_make}) ->
diff --git a/lib/common_test/src/ct_master_event.erl b/lib/common_test/src/ct_master_event.erl
index bd4d1efc92..a6ec5a7a75 100644
--- a/lib/common_test/src/ct_master_event.erl
+++ b/lib/common_test/src/ct_master_event.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,13 +18,13 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework Event Handler
+%%% Common Test Framework Event Handler
%%%
-%%% <p>This module implements an event handler that the CT Master
+%%% This module implements an event handler that the CT Master
%%% uses to handle status and progress notifications sent to the
%%% master node during test runs. This module may be used as a
%%% template for other event handlers that can be plugged in to
-%%% handle logging and reporting on the master node.</p>
+%%% handle logging and reporting on the master node.
-module(ct_master_event).
-behaviour(gen_event).
diff --git a/lib/common_test/src/ct_master_logs.erl b/lib/common_test/src/ct_master_logs.erl
index 1308720823..ea6f93b565 100644
--- a/lib/common_test/src/ct_master_logs.erl
+++ b/lib/common_test/src/ct_master_logs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,10 +18,10 @@
%% %CopyrightEnd%
%%
-%%% @doc Logging functionality for Common Test Master.
+%%% Logging functionality for Common Test Master.
%%%
-%%% <p>This module implements a logger for the master
-%%% node.</p>
+%%% This module implements a logger for the master
+%%% node.
-module(ct_master_logs).
-export([start/2, make_all_runs_index/0, log/3, nodedir/2,
diff --git a/lib/common_test/src/ct_master_status.erl b/lib/common_test/src/ct_master_status.erl
index b27fdd341e..cb01220121 100644
--- a/lib/common_test/src/ct_master_status.erl
+++ b/lib/common_test/src/ct_master_status.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,12 +18,12 @@
%% %CopyrightEnd%
%%
-%%% @doc Logging functionality for Common Test Master.
+%%% doc Logging functionality for Common Test Master.
%%%
-%%% <p>This module keeps a list of <code>{Node,Status}</code>
+%%% This module keeps a list of {Node,Status}
%%% tuples. It is possible to anytime during a test run get
%%% a snapshot of the test status. The module is an event
-%%% handler for the master event manager.</p>
+%%% handler for the master event manager.
-module(ct_master_status).
-behaviour(gen_event).
diff --git a/lib/common_test/src/ct_netconfc.hrl b/lib/common_test/src/ct_netconfc.hrl
index 5eeeafa318..1d81c762ba 100644
--- a/lib/common_test/src/ct_netconfc.hrl
+++ b/lib/common_test/src/ct_netconfc.hrl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,9 +24,7 @@
%% This file defines constant values and records used by the
%% netconf client ct_netconfc.
%%
-%% @author Support
-%% @doc Netconf Client Interface.
-%% @end
+%% Netconf Client Interface.
%%----------------------------------------------------------------------
%%----------------------------------------------------------------------
diff --git a/lib/common_test/src/ct_property_test.erl b/lib/common_test/src/ct_property_test.erl
index 94ccb59af9..f51f454d08 100644
--- a/lib/common_test/src/ct_property_test.erl
+++ b/lib/common_test/src/ct_property_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -28,46 +28,6 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%% @doc EXPERIMENTAL support in common-test for calling property based tests.
-%%%
-%%% <p>This module is a first step towards running Property Based testing in the
-%%% Common Test framework. A property testing tool like QuickCheck or PropEr is
-%%% assumed to be installed.</p>
-%%%
-%%% <p>The idea is to have a common_test testsuite calling a property testing
-%%% tool with special property test suites as defined by that tool. In this manual
-%%% we assume the usual Erlang Application directory structure. The tests are
-%%% collected in the application's <c>test</c> directory. The test directory
-%%% has a sub-directory called <c>property_test</c> where everything needed for
-%%% the property tests are collected.</p>
-%%%
-%%% <p>A typical ct test suite using <c>ct_property_test</c> is organized as follows:
-%%% </p>
-%%% ```
-%%% -include_lib("common_test/include/ct.hrl").
-%%%
-%%% all() -> [prop_ftp_case].
-%%%
-%%% init_per_suite(Config) ->
-%%% ct_property_test:init_per_suite(Config).
-%%%
-%%% %%%---- test case
-%%% prop_ftp_case(Config) ->
-%%% ct_property_test:quickcheck(
-%%% ftp_simple_client_server:prop_ftp(Config),
-%%% Config
-%%% ).
-%%% '''
-%%%
-%%% <warning>
-%%% <p>
-%%% This is experimental code which may be changed or removed
-%%% anytime without any warning.
-%%% </p>
-%%% </warning>
-%%%
-%%% @end
-
-module(ct_property_test).
%% API
@@ -76,19 +36,6 @@
-include_lib("common_test/include/ct.hrl").
-%%%-----------------------------------------------------------------
-%%% @spec init_per_suite(Config) -> Config | {skip,Reason}
-%%%
-%%% @doc Initializes Config for property testing.
-%%%
-%%% <p>The function investigates if support is available for either Quickcheck, PropEr,
-%%% or Triq.
-%%% The options <c>{property_dir,AbsPath}</c> and
-%%% <c>{property_test_tool,Tool}</c> is set in the Config returned.</p>
-%%% <p>The function is intended to be called in the init_per_suite in the test suite.</p>
-%%% <p>The property tests are assumed to be in the subdirectory <c>property_test</c>.</p>
-%%% @end
-
init_per_suite(Config) ->
case which_module_exists([eqc,proper,triq]) of
{ok,ToolModule} ->
@@ -108,14 +55,6 @@ init_per_suite(Config) ->
{skip, "No property testing tool found"}
end.
-%%%-----------------------------------------------------------------
-%%% @spec quickcheck(Property, Config) -> true | {fail,Reason}
-%%%
-%%% @doc Call quickcheck and return the result in a form suitable for common_test.
-%%%
-%%% <p>The function is intended to be called in the test cases in the test suite.</p>
-%%% @end
-
quickcheck(Property, Config) ->
Tool = proplists:get_value(property_test_tool,Config),
F = function_name(quickcheck, Tool),
diff --git a/lib/common_test/src/ct_release_test.erl b/lib/common_test/src/ct_release_test.erl
index 4af9afb45b..ac3dcab7c9 100644
--- a/lib/common_test/src/ct_release_test.erl
+++ b/lib/common_test/src/ct_release_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2014-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@
%% %CopyrightEnd%
%%
%%-----------------------------------------------------------------
-%% @doc EXPERIMENTAL support for testing of upgrade.
+%% EXPERIMENTAL support for testing of upgrade.
%%
%% This is a library module containing support for test of release
%% related activities in one or more applications. Currenty it
@@ -27,7 +27,7 @@
%% == Configuration ==
%%
%% In order to find version numbers of applications to upgrade from,
-%% `{@module}' needs to access and start old OTP
+%% ct_release_test needs to access and start old OTP
%% releases. A `common_test' configuration file can be used for
%% specifying the location of such releases, for example:
%%
@@ -39,48 +39,45 @@
%% The configuration file should preferably point out the latest patch
%% level on each major release.
%%
-%% If no such configuration file is given, {@link init/1} will return
-%% `{skip,Reason}' and any attempt at running {@link upgrade/4}
+%% If no such configuration file is given, init/1 will return
+%% {skip,Reason} and any attempt at running upgrade/4
%% will fail.
%%
%% == Callback functions ==
%%
-%% The following functions should be exported from a {@module}
+%% The following functions should be exported from a ct_release_test
%% callback module.
%%
%% All callback functions are called on the node where the upgrade is
%% executed.
%%
-%% <dl>
-%% <dt>Module:upgrade_init(CtData,State) -> NewState</dt>
-%% <dd>Types:
+%% Module:upgrade_init(CtData,State) -> NewState
+%% Types:
%%
-%% <b><code>CtData = {@link ct_data()}</code></b><br/>
-%% <b><code>State = NewState = cb_state()</code></b>
+%% CtData = ct_data()
+%% State = NewState = cb_state()
%%
%% Initialyze system before upgrade test starts.
%%
%% This function is called before the upgrade is started. All
-%% applications given in {@link upgrade/4} are already started by
+%% applications given in upgrade/4 are already started by
%% the boot script, so this callback is intended for additional
%% initialization, if necessary.
%%
-%% <code>CtData</code> is an opaque data structure which shall be used
-%% in any call to <code>ct_release_test</code> inside the callback.
+%% CtData is an opaque data structure which shall be used
+%% in any call to ct_release_test inside the callback.
%%
%% Example:
%%
-%% ```
%% upgrade_init(CtData,State) ->
%% {ok,{FromVsn,ToVsn}} = ct_release_test:get_app_vsns(CtData,myapp),
-%% open_connection(State).'''
-%% </dd>
+%% open_connection(State).
%%
-%% <dt>Module:upgrade_upgraded(CtData,State) -> NewState</dt>
-%% <dd>Types:
+%% Module:upgrade_upgraded(CtData,State) -> NewState
+%% Types:
%%
-%% <b><code>CtData = {@link ct_data()}</code></b><br/>
-%% <b><code>State = NewState = cb_state()</code></b>
+%% CtData = ct_data()
+%% State = NewState = cb_state()
%%
%% Check that upgrade was successful.
%%
@@ -89,21 +86,19 @@
%% been made permanent. It allows application specific checks to
%% ensure that the upgrade was successful.
%%
-%% <code>CtData</code> is an opaque data structure which shall be used
-%% in any call to <code>ct_release_test</code> inside the callback.
+%% CtData is an opaque data structure which shall be used
+%% in any call to ct_release_test inside the callback.
%%
%% Example:
%%
-%% ```
%% upgrade_upgraded(CtData,State) ->
-%% check_connection_still_open(State).'''
-%% </dd>
+%% check_connection_still_open(State).
%%
-%% <dt>Module:upgrade_downgraded(CtData,State) -> NewState</dt>
-%% <dd>Types:
+%% Module:upgrade_downgraded(CtData,State) -> NewState
+%% Types:
%%
-%% <b><code>CtData = {@link ct_data()}</code></b><br/>
-%% <b><code>State = NewState = cb_state()</code></b>
+%% CtData = ct_data()
+%% State = NewState = cb_state()
%%
%% Check that downgrade was successful.
%%
@@ -112,17 +107,13 @@
%% made permanent. It allows application specific checks to ensure
%% that the downgrade was successful.
%%
-%% <code>CtData</code> is an opaque data structure which shall be used
-%% in any call to <code>ct_release_test</code> inside the callback.
+%% CtData is an opaque data structure which shall be used
+%% in any call to ct_release_test inside the callback.
%%
%% Example:
%%
-%% ```
%% upgrade_downgraded(CtData,State) ->
-%% check_connection_closed(State).'''
-%% </dd>
-%% </dl>
-%% @end
+%% check_connection_closed(State).
%%-----------------------------------------------------------------
-module(ct_release_test).
@@ -152,7 +143,7 @@
Config :: config(),
Result :: config() | SkipOrFail,
SkipOrFail :: {skip,Reason} | {fail,Reason}.
-%% @doc Initialize `{@module}'.
+%% Initialize ct_release_test.
%%
%% This function can be called from any of the
%% `init_per_*' functions in the test suite. It updates
@@ -161,16 +152,15 @@
%% returned configuration must therefore also be returned from
%% the calling `init_per_*'.
%%
-%% If the initialization fails, e.g. if a required release can
-%% not be found, the function returns `{skip,Reason}'. In
+%% If the initialization fails, e.g. if a required release
+%% cannot be found, the function returns `{skip,Reason}'. In
%% this case the other test support functions in this mudule
-%% can not be used.
+%% cannot be used.
%%
%% Example:
%%
-%% ```
%% init_per_suite(Config) ->
-%% ct_release_test:init(Config).'''
+%% ct_release_test:init(Config).
%%
init(Config) ->
try init_upgrade_test() of
@@ -194,47 +184,42 @@ init(Config) ->
Callback :: {module(),InitState},
InitState :: cb_state(),
Config :: config().
-%% @doc Test upgrade of the given application(s).
+%% Test upgrade of the given application(s).
%%
%% This function can be called from a test case. It requires that
-%% `Config' has been initialized by calling {@link
-%% init/1} prior to this, for example from `init_per_suite/1'.
+%% `Config' has been initialized by calling
+%% init/1 prior to this, for example from `init_per_suite/1'.
%%
%% Upgrade tests are performed as follows:
%%
-%% <ol>
-%% <li>Figure out which OTP release to test upgrade
+%% Figure out which OTP release to test upgrade
%% from. Start a node running that release and find the
%% application versions on that node. Terminate the
-%% node.</li>
-%% <li>Figure out all dependencies for the applications under
-%% test.</li>
-%% <li>Create a release containing the core
+%% node.
+%% Figure out all dependencies for the applications under
+%% test.
+%% Create a release containing the core
%% applications `kernel', `stdlib' and `sasl'
%% in addition to the application(s) under test and all
%% dependencies of these. The versions of the applications
%% under test will be the ones found on the OTP release to
%% upgrade from. The versions of all other applications will
%% be those found on the current node, i.e. the common_test
-%% node. This is the "From"-release.</li>
-%% <li>Create another release containing the same
+%% node. This is the "From"-release.
+%% Create another release containing the same
%% applications as in the previous step, but with all
%% application versions taken from the current node. This is
-%% the "To"-release.</li>
-%% <li>Install the "From"-release and start a new node
-%% running this release.</li>
-%% <li>Perform the upgrade test and allow customized
+%% the "To"-release.
+%% Install the "From"-release and start a new node
+%% running this release.
+%% Perform the upgrade test and allow customized
%% control by using callbacks:
-%% <ol>
-%% <li>Callback: `upgrade_init/2'</li>
-%% <li>Unpack the new release</li>
-%% <li>Install the new release</li>
-%% <li>Callback: `upgrade_upgraded/2'</li>
-%% <li>Install the original release</li>
-%% <li>Callback: `upgrade_downgraded/2'</li>
-%% </ol>
-%% </li>
-%% </ol>
+%% Callback: `upgrade_init/2'
+%% Unpack the new release
+%% Install the new release
+%% Callback: `upgrade_upgraded/2'
+%% Install the original release
+%% Callback: `upgrade_downgraded/2'
%%
%% `App' or `Apps'
%% specifies the applications under test, i.e. the applications
@@ -244,27 +229,25 @@ init(Config) ->
%%
%% `Level' specifies which OTP release to
%% pick the "From" versions from.
-%% <dl>
-%% <dt>major</dt>
-%% <dd>From verions are picked from the previous major
+%% major
+%% From verions are picked from the previous major
%% release. For example, if the test is run on an OTP-17
-%% node, `{@module}' will pick the application
+%% node, ct_release_test will pick the application
%% "From" versions from an OTP installation running OTP
-%% R16B.</dd>
+%% R16B.
%%
-%% <dt>minor</dt>
-%% <dd>From verions are picked from the current major
+%% minor
+%% From verions are picked from the current major
%% release. For example, if the test is run on an OTP-17
-%% node, `{@module}' will pick the application
+%% node, ct_release_test will pick the application
%% "From" versions from an OTP installation running an
-%% earlier patch level of OTP-17.</dd>
-%% </dl>
+%% earlier patch level of OTP-17.
%%
%% The application "To" versions are allways picked from the
%% current node, i.e. the common_test node.
%%
%% `Callback' specifies the module (normally the
-%% test suite) which implements the {@section Callback functions}, and
+%% test suite) which implements the Callback functions, and
%% the initial value of the `State' variable used in these
%% functions.
%%
@@ -273,10 +256,8 @@ init(Config) ->
%%
%% Example:
%%
-%% ```
%% minor_upgrade(Config) ->
%% ct_release_test:upgrade(ssl,minor,{?MODULE,[]},Config).
-%% '''
%%
upgrade(App,Level,Callback,Config) when is_atom(App) ->
upgrade([App],Level,Callback,Config);
@@ -318,10 +299,10 @@ upgrade(Apps,Level,Callback,Config) ->
-spec cleanup(Config) -> Result when
Config :: config(),
Result :: config().
-%% @doc Clean up after tests.
+%% Clean up after tests.
%%
%% This function shall be called from the `end_per_*' function
-%% complementing the `init_per_*' function where {@link init/1}
+%% complementing the `init_per_*' function where init/1
%% is called.
%%
%% It cleans up after the test, for example kills hanging
@@ -329,9 +310,8 @@ upgrade(Apps,Level,Callback,Config) ->
%%
%% Example:
%%
-%% ```
%% end_per_suite(Config) ->
-%% ct_release_test:cleanup(Config).'''
+%% ct_release_test:cleanup(Config).
%%
cleanup(Config) ->
AllNodes = [node_name(?testnode)|nodes()],
@@ -352,15 +332,15 @@ cleanup(Config) ->
From :: string(),
To :: string(),
Reason :: {app_not_found,App}.
-%% @doc Get versions involved in this upgrade for the given application.
+%% Get versions involved in this upgrade for the given application.
%%
%% This function can be called from inside any of the callback
%% functions. It returns the old (From) and new (To) versions involved
%% in the upgrade/downgrade test for the given application.
%%
-%% <code>CtData</code> must be the first argument received in the
+%% CtData must be the first argument received in the
%% calling callback function - an opaque data structure set by
-%% <code>ct_release_tests</code>.
+%% ct_release_tests.
get_app_vsns(#ct_data{from=FromApps,to=ToApps},App) ->
case {lists:keyfind(App,1,FromApps),lists:keyfind(App,1,ToApps)} of
{{App,FromVsn,_},{App,ToVsn,_}} ->
@@ -380,16 +360,16 @@ get_app_vsns(#ct_data{from=FromApps,to=ToApps},App) ->
Down :: [Instr],
Instr :: term(),
Reason :: {app_not_found,App} | {vsn_not_found,{App,From}}.
-%% @doc Get appup instructions for the given application.
+%% Get appup instructions for the given application.
%%
%% This function can be called from inside any of the callback
%% functions. It reads the appup file for the given application and
%% returns the instructions for upgrade and downgrade for the versions
%% in the test.
%%
-%% <code>CtData</code> must be the first argument received in the
+%% CtData must be the first argument received in the
%% calling callback function - an opaque data structure set by
-%% <code>ct_release_tests</code>.
+%% ct_release_tests.
%%
%% See reference manual for appup files for types definitions for the
%% instructions.
@@ -446,7 +426,7 @@ init_upgrade_test(Level) ->
case OldRel of
false ->
ct:log("Release ~tp is not available."
- " Upgrade on '~p' level can not be tested.",
+ " Upgrade on '~p' level cannot be tested.",
[FromVsn,Level]),
undefined;
_ ->
@@ -548,7 +528,7 @@ target_system(Apps,CreateDir,InstallDir,{FromVsn,_,AllAppsVsns,Path}) ->
{path,Path}]]),
%% Unpack the tar to complete the installation
- erl_tar:extract(RelName ++ ".tar.gz", [{cwd, InstallDir}, compressed]),
+ ok = erl_tar:extract(RelName ++ ".tar.gz", [{cwd, InstallDir}, compressed]),
%% Add bin and log dirs
BinDir = filename:join([InstallDir, "bin"]),
@@ -574,11 +554,11 @@ target_system(Apps,CreateDir,InstallDir,{FromVsn,_,AllAppsVsns,Path}) ->
%% create start_erl.data, sys.config and start.src
StartErlData = filename:join([InstallDir, "releases", "start_erl.data"]),
- write_file(StartErlData, io_lib:fwrite("~s ~s~n", [ErtsVsn, FromVsn])),
+ ok = write_file(StartErlData, io_lib:fwrite("~s ~s~n", [ErtsVsn, FromVsn])),
SysConfig = filename:join([InstallDir, "releases", FromVsn, "sys.config"]),
- write_file(SysConfig, "[]."),
+ ok = write_file(SysConfig, "[]."),
StartSrc = filename:join(ErtsBinDir,"start.src"),
- write_file(StartSrc,start_script()),
+ ok = write_file(StartSrc,start_script()),
ok = file:change_mode(StartSrc,8#0755),
%% Make start_erl executable
@@ -640,7 +620,7 @@ upgrade_system(Apps, FromRel, CreateDir, InstallDir, {_,ToVsn,_,_}) ->
[{path,[FromPath]},
{outdir,CreateDir}]]),
SysConfig = filename:join([CreateDir, "sys.config"]),
- write_file(SysConfig, "[]."),
+ ok = write_file(SysConfig, "[]."),
ok = systools(make_tar,[RelName,[{erts,code:root_dir()}]]),
@@ -878,7 +858,7 @@ subst_file(Src, Dest, Vars, Opts) ->
{ok, Bin} = file:read_file(Src),
Conts = unicode:characters_to_list(Bin),
NConts = subst(Conts, Vars),
- write_file(Dest, NConts),
+ ok = write_file(Dest, NConts),
case lists:member(preserve, Opts) of
true ->
{ok, FileInfo} = file:read_file_info(Src),
diff --git a/lib/common_test/src/ct_repeat.erl b/lib/common_test/src/ct_repeat.erl
index 177ef37d1f..8b1c7d47bb 100644
--- a/lib/common_test/src/ct_repeat.erl
+++ b/lib/common_test/src/ct_repeat.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,14 +18,14 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework module that handles repeated test runs
+%%% doc Common Test Framework module that handles repeated test runs
%%%
-%%% <p>This module exports functions for repeating tests. The following
+%%% This module exports functions for repeating tests. The following
%%% start flags (or equivalent ct:run_test/1 options) are supported:
%%% -until <StopTime>, StopTime = YYMoMoDDHHMMSS | HHMMSS
%%% -duration <DurTime>, DurTime = HHMMSS
%%% -force_stop [skip_rest]
-%%% -repeat <N>, N = integer()</p>
+%%% -repeat <N>, N = integer()
-module(ct_repeat).
diff --git a/lib/common_test/src/ct_rpc.erl b/lib/common_test/src/ct_rpc.erl
index b4a0bc9d74..cef5ad14e5 100644
--- a/lib/common_test/src/ct_rpc.erl
+++ b/lib/common_test/src/ct_rpc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,8 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test specific layer on Erlang/OTP rpc.
-
-module(ct_rpc).
%%% API
@@ -29,49 +27,12 @@
%%%=========================================================================
%%% API
%%%=========================================================================
-%%% @spec app_node(App, Candidates) -> NodeName
-%%%
-%%% App = atom()
-%%% Candidates = [NodeName]
-%%% NodeName = atom()
-%%%
-%%% @doc From a set of candidate nodes determines which of them is
-%%% running the application App. If none of the candidate nodes
-%%% is running the application the function will make the test case
-%%% calling this function fail. This function is the same as calling
-%%% <code>app_node(App, Candidates, true)</code>.
-%%%
app_node(App, Candidates) ->
app_node(App, Candidates, true, []).
-%%% @spec app_node(App, Candidates, FailOnBadRPC) -> NodeName
-%%%
-%%% App = atom()
-%%% Candidates = [NodeName]
-%%% NodeName = atom()
-%%% FailOnBadRPC = true | false
-%%%
-%%% @doc Same as <code>app_node/2</code> only the <code>FailOnBadRPC</code>
-%%% argument will determine if the search for a candidate node should
-%%% stop or not if <code>badrpc</code> is received at some point.
-%%%
app_node(App, Candidates, FailOnBadRPC) ->
app_node(App, Candidates, FailOnBadRPC, []).
-%%% @spec app_node(App, Candidates, FailOnBadRPC, Cookie) -> NodeName
-%%%
-%%% App = atom()
-%%% Candidates = [NodeName]
-%%% NodeName = atom()
-%%% FailOnBadRPC = true | false
-%%% Cookie = atom()
-%%%
-%%% @doc Same as <code>app_node/2</code> only the <code>FailOnBadRPC</code>
-%%% argument will determine if the search for a candidate node should
-%%% stop or not if <code>badrpc</code> is received at some point.
-%%% The cookie on the client node will be set to <code>Cookie</code>
-%%% for this rpc operation (use to match the server node cookie).
-%%%
app_node(App, [], _, _) ->
ct:fail({application_not_running, App});
@@ -96,49 +57,12 @@ app_node(App, _Candidates = [CandidateNode | Nodes], FailOnBadRPC, Cookie) ->
end
end.
-%%% @spec call(Node, Module, Function, Args) -> term() | {badrpc, Reason}
-%%%
-%%% @doc Same as call(Node, Module, Function, Args, infinity)
-%%%
call(Node, Module, Function, Args) ->
call(Node, Module, Function, Args, infinity, []).
-%%% @spec call(Node, Module, Function, Args, TimeOut) ->
-%%% term() | {badrpc, Reason}
-%%% Node = NodeName | {Fun, FunArgs}
-%%% Fun = fun()
-%%% FunArgs = term()
-%%% NodeName = atom()
-%%% Module = atom()
-%%% Function = atom()
-%%% Args = [term()]
-%%% Reason = timeout | term()
-%%%
-%%% @doc Evaluates apply(Module, Function, Args) on the node Node.
-%%% Returns whatever Function returns or {badrpc, Reason} if the
-%%% remote procedure call fails. If Node is {Fun, FunArgs} applying
-%%% Fun to FunArgs should return a node name.
call(Node, Module, Function, Args, TimeOut) ->
call(Node, Module, Function, Args, TimeOut, []).
-%%% @spec call(Node, Module, Function, Args, TimeOut, Cookie) ->
-%%% term() | {badrpc, Reason}
-%%% Node = NodeName | {Fun, FunArgs}
-%%% Fun = fun()
-%%% FunArgs = term()
-%%% NodeName = atom()
-%%% Module = atom()
-%%% Function = atom()
-%%% Args = [term()]
-%%% Reason = timeout | term()
-%%% Cookie = atom()
-%%%
-%%% @doc Evaluates apply(Module, Function, Args) on the node Node.
-%%% Returns whatever Function returns or {badrpc, Reason} if the
-%%% remote procedure call fails. If Node is {Fun, FunArgs} applying
-%%% Fun to FunArgs should return a node name.
-%%% The cookie on the client node will be set to <code>Cookie</code>
-%%% for this rpc operation (use to match the server node cookie).
call({Fun, FunArgs}, Module, Function, Args, TimeOut, Cookie) ->
Node = Fun(FunArgs),
call(Node, Module, Function, Args, TimeOut, Cookie);
@@ -148,42 +72,9 @@ call(Node, Module, Function, Args, TimeOut, Cookie) when is_atom(Node) ->
_ = set_the_cookie(Cookie0),
Result.
-%%% @spec cast(Node, Module, Function, Args) -> ok
-%%% Node = NodeName | {Fun, FunArgs}
-%%% Fun = fun()
-%%% FunArgs = term()
-%%% NodeName = atom()
-%%% Module = atom()
-%%% Function = atom()
-%%% Args = [term()]
-%%% Reason = timeout | term()
-%%%
-%%% @doc Evaluates apply(Module, Function, Args) on the node Node.
-%%% No response is delivered and the process which makes the call is
-%%% not suspended until the evaluation is compleated as in the case of
-%%% call/[3,4]. If Node is {Fun, FunArgs} applying
-%%% Fun to FunArgs should return a node name.
cast(Node, Module, Function, Args) ->
cast(Node, Module, Function, Args, []).
-%%% @spec cast(Node, Module, Function, Args, Cookie) -> ok
-%%% Node = NodeName | {Fun, FunArgs}
-%%% Fun = fun()
-%%% FunArgs = term()
-%%% NodeName = atom()
-%%% Module = atom()
-%%% Function = atom()
-%%% Args = [term()]
-%%% Reason = timeout | term()
-%%% Cookie = atom()
-%%%
-%%% @doc Evaluates apply(Module, Function, Args) on the node Node.
-%%% No response is delivered and the process which makes the call is
-%%% not suspended until the evaluation is compleated as in the case of
-%%% call/[3,4]. If Node is {Fun, FunArgs} applying
-%%% Fun to FunArgs should return a node name.
-%%% The cookie on the client node will be set to <code>Cookie</code>
-%%% for this rpc operation (use to match the server node cookie).
cast({Fun, FunArgs}, Module, Function, Args, Cookie) ->
Node = Fun(FunArgs),
cast(Node, Module, Function, Args, Cookie);
@@ -196,7 +87,6 @@ cast(Node, Module, Function, Args, Cookie) when is_atom(Node) ->
%%%---------- Internal -----------
-%%% @hidden
set_the_cookie([]) ->
[];
set_the_cookie(Cookie) ->
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index afc5fee4f7..c9d406f1fd 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,11 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework test execution control module.
-%%%
-%%% <p>This module exports functions for installing and running tests
-%%% withing the Common Test Framework.</p>
-
-module(ct_run).
%% Script interface
@@ -84,17 +79,6 @@
tests,
starter}).
-%%%-----------------------------------------------------------------
-%%% @spec script_start() -> term()
-%%%
-%%% @doc Start tests via the ct_run program or script.
-%%%
-%%% <p>Example:<br/><code>./ct_run -config config.ctc -dir
-%%% $TEST_DIR</code></p>
-%%%
-%%% <p>Example:<br/><code>./ct_run -config config.ctc -suite
-%%% $SUITE_PATH/$SUITE_NAME [-case $CASE_NAME]</code></p>
-%%%
script_start() ->
process_flag(trap_exit, true),
Init = init:get_arguments(),
@@ -799,9 +783,6 @@ script_start4(#opts{shell = true, cover = Cover}, _) ->
script_start4(Opts = #opts{tests = Tests}, Args) ->
do_run(Tests, [], Opts, Args).
-%%%-----------------------------------------------------------------
-%%% @spec script_usage() -> ok
-%%% @doc Print usage information for <code>ct_run</code>.
script_usage() ->
io:format("\nUsage:\n\n"),
io:format("Run tests from command line:\n\n"
@@ -885,9 +866,6 @@ script_usage() ->
"\n\t [-basic_html]"
"\n\t [-no_esc_chars]\n\n").
-%%%-----------------------------------------------------------------
-%%% @hidden
-%%% @equiv ct:install/1
install(Opts) ->
install(Opts, ".").
@@ -931,15 +909,6 @@ install(Opts, LogDir) ->
variables_file_name(Dir) ->
filename:join(Dir, "variables-"++atom_to_list(node())).
-%%%-----------------------------------------------------------------
-%%% @spec run_test(Opts) -> Result
-%%% Opts = [tuple()]
-%%% Result = [TestResult] | {error,Reason}
-%%%
-%%% @doc Start tests from the erlang shell or from an erlang program.
-%%% @equiv ct:run_test/1
-%%%-----------------------------------------------------------------
-
run_test(StartOpt) when is_tuple(StartOpt) ->
run_test([StartOpt]);
@@ -1427,14 +1396,6 @@ run_dir(Opts = #opts{logdir = LogDir,
exit({error,{incorrect_start_options,{Dir,Suite,GsAndCs}}})
end.
-%%%-----------------------------------------------------------------
-%%% @spec run_testspec(TestSpec) -> Result
-%%% TestSpec = [term()]
-%%%
-%%% @doc Run test specified by <code>TestSpec</code>. The terms are
-%%% the same as those used in test specification files.
-%%% @equiv ct:run_testspec/1
-%%%-----------------------------------------------------------------
run_testspec(TestSpec) ->
CTPid = spawn(run_testspec1_fun(TestSpec)),
Ref = monitor(process, CTPid),
@@ -1634,9 +1595,6 @@ delistify([E]) -> E;
delistify(E) -> E.
-%%%-----------------------------------------------------------------
-%%% @hidden
-%%% @equiv ct:run/3
run(TestDir, Suite, Cases) ->
case install([]) of
ok ->
@@ -1645,9 +1603,6 @@ run(TestDir, Suite, Cases) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @hidden
-%%% @equiv ct:run/2
run(TestDir, Suite) when is_list(TestDir), is_integer(hd(TestDir)) ->
case install([]) of
ok ->
@@ -1656,9 +1611,6 @@ run(TestDir, Suite) when is_list(TestDir), is_integer(hd(TestDir)) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @hidden
-%%% @equiv ct:run/1
run(TestDirs) ->
case install([]) of
ok ->
@@ -1957,7 +1909,8 @@ auto_compile(TestSuites) ->
SuiteMakeErrors =
lists:flatmap(fun({TestDir,Suite} = TS) ->
case run_make(suites, TestDir,
- Suite, UserInclude) of
+ Suite, UserInclude,
+ [nowarn_export_all]) of
{error,{make_failed,Bad}} ->
[{TS,Bad}];
{error,_} ->
@@ -1975,7 +1928,7 @@ auto_compile(TestSuites) ->
case lists:member(Dir, Done) of
false ->
Failed1 =
- case run_make(helpmods, Dir, Suite, UserInclude) of
+ case run_make(helpmods, Dir, Suite, UserInclude, []) of
{error,{make_failed,BadMods}} ->
[{{Dir,all},BadMods}|Failed];
{error,_} ->
@@ -2068,16 +2021,9 @@ get_bad_suites([], BadSuites) ->
BadSuites.
-
-%%%-----------------------------------------------------------------
-%%% @hidden
-%%% @equiv ct:step/3
step(TestDir, Suite, Case) ->
step(TestDir, Suite, Case, []).
-%%%-----------------------------------------------------------------
-%%% @hidden
-%%% @equiv ct:step/4
step(TestDir, Suite, Case, Opts) when is_list(TestDir),
is_atom(Suite), is_atom(Case),
Suite =/= all, Case =/= all ->
@@ -2724,12 +2670,12 @@ get_name(Dir) ->
run_make(TestDir, Mod, UserInclude) ->
- run_make(suites, TestDir, Mod, UserInclude).
+ run_make(suites, TestDir, Mod, UserInclude, [nowarn_export_all]).
-run_make(Targets, TestDir0, Mod, UserInclude) when is_list(Mod) ->
- run_make(Targets, TestDir0, list_to_atom(Mod), UserInclude);
+run_make(Targets, TestDir0, Mod, UserInclude, COpts) when is_list(Mod) ->
+ run_make(Targets, TestDir0, list_to_atom(Mod), UserInclude, COpts);
-run_make(Targets, TestDir0, Mod, UserInclude) ->
+run_make(Targets, TestDir0, Mod, UserInclude, COpts) ->
case locate_test_dir(TestDir0, Mod) of
{ok,TestDir} ->
%% send a start_make notification which may suspend
@@ -2744,7 +2690,7 @@ run_make(Targets, TestDir0, Mod, UserInclude) ->
XmerlInclude = get_dir(xmerl, "include"),
ErlFlags = UserInclude ++ [{i,CtInclude},
{i,XmerlInclude},
- debug_info],
+ debug_info] ++ COpts,
Result =
if Mod == all ; Targets == helpmods ->
case (catch ct_make:all([noexec|ErlFlags])) of
diff --git a/lib/common_test/src/ct_slave.erl b/lib/common_test/src/ct_slave.erl
index 0c16ad5980..dde33440be 100644
--- a/lib/common_test/src/ct_slave.erl
+++ b/lib/common_test/src/ct_slave.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -17,13 +17,6 @@
%%
%% %CopyrightEnd%
-%%% @doc Common Test Framework functions for starting and stopping nodes for
-%%% Large Scale Testing.
-%%%
-%%% <p>This module exports functions which are used by the Common Test Master
-%%% to start and stop "slave" nodes. It is the default callback module for the
-%%% <code>{init, node_start}</code> term of the Test Specification.</p>
-
%%----------------------------------------------------------------------
%% File : ct_slave.erl
%% Description : CT module for starting nodes for large-scale testing.
@@ -41,42 +34,9 @@
kill_if_fail, erl_flags, env, ssh_port, ssh_opts,
stop_timeout}).
-%%%-----------------------------------------------------------------
-%%% @spec start(Node) -> Result
-%%% Node = atom()
-%%% Result = {ok, NodeName} |
-%%% {error, Reason, NodeName}
-%%% Reason = already_started |
-%%% started_not_connected |
-%%% boot_timeout |
-%%% init_timeout |
-%%% startup_timeout |
-%%% not_alive
-%%% NodeName = atom()
-%%% @doc Starts an Erlang node with name <code>Node</code> on the local host.
-%%% @see start/3
start(Node) ->
start(gethostname(), Node).
-%%%-----------------------------------------------------------------
-%%% @spec start(HostOrNode, NodeOrOpts) -> Result
-%%% HostOrNode = atom()
-%%% NodeOrOpts = atom() | list()
-%%% Result = {ok, NodeName} |
-%%% {error, Reason, NodeName}
-%%% Reason = already_started |
-%%% started_not_connected |
-%%% boot_timeout |
-%%% init_timeout |
-%%% startup_timeout |
-%%% not_alive
-%%% NodeName = atom()
-%%% @doc Starts an Erlang node with default options on a specified
-%%% host, or on the local host with specified options. That is,
-%%% the call is interpreted as <code>start(Host, Node)</code> when the
-%%% second argument is atom-valued and <code>start(Node, Opts)</code>
-%%% when it's list-valued.
-%%% @see start/3
start(_HostOrNode = Node, _NodeOrOpts = Opts) %% match to satiate edoc
when is_list(Opts) ->
start(gethostname(), Node, Opts);
@@ -84,104 +44,6 @@ start(_HostOrNode = Node, _NodeOrOpts = Opts) %% match to satiate edoc
start(Host, Node) ->
start(Host, Node, []).
-%%%-----------------------------------------------------------------
-%%% @spec start(Host, Node, Opts) -> Result
-%%% Node = atom()
-%%% Host = atom()
-%%% Opts = [OptTuples]
-%%% OptTuples = {username, Username} |
-%%% {password, Password} |
-%%% {boot_timeout, BootTimeout} | {init_timeout, InitTimeout} |
-%%% {startup_timeout, StartupTimeout} |
-%%% {startup_functions, StartupFunctions} |
-%%% {monitor_master, Monitor} |
-%%% {kill_if_fail, KillIfFail} |
-%%% {erl_flags, ErlangFlags} |
-%%% {env, [{EnvVar,Value}]}
-%%% Username = string()
-%%% Password = string()
-%%% BootTimeout = integer()
-%%% InitTimeout = integer()
-%%% StartupTimeout = integer()
-%%% StartupFunctions = [StartupFunctionSpec]
-%%% StartupFunctionSpec = {Module, Function, Arguments}
-%%% Module = atom()
-%%% Function = atom()
-%%% Arguments = [term]
-%%% Monitor = bool()
-%%% KillIfFail = bool()
-%%% ErlangFlags = string()
-%%% EnvVar = string()
-%%% Value = string()
-%%% Result = {ok, NodeName} |
-%%% {error, Reason, NodeName}
-%%% Reason = already_started |
-%%% started_not_connected |
-%%% boot_timeout |
-%%% init_timeout |
-%%% startup_timeout |
-%%% not_alive
-%%% NodeName = atom()
-%%% @doc Starts an Erlang node with name <code>Node</code> on host
-%%% <code>Host</code> as specified by the combination of options in
-%%% <code>Opts</code>.
-%%%
-%%% <p>Options <code>Username</code> and <code>Password</code> will be used
-%%% to log in onto the remote host <code>Host</code>.
-%%% Username, if omitted, defaults to the current user name,
-%%% and password is empty by default.</p>
-%%%
-%%% <p>A list of functions specified in the <code>Startup</code> option will be
-%%% executed after startup of the node. Note that all used modules should be
-%%% present in the code path on the <code>Host</code>.</p>
-%%%
-%%% <p>The timeouts are applied as follows:</p>
-%%% <list>
-%%% <item>
-%%% <code>BootTimeout</code> - time to start the Erlang node, in seconds.
-%%% Defaults to 3 seconds. If node does not become pingable within this time,
-%%% the result <code>{error, boot_timeout, NodeName}</code> is returned;
-%%% </item>
-%%% <item>
-%%% <code>InitTimeout</code> - time to wait for the node until it calls the
-%%% internal callback function informing master about successfull startup.
-%%% Defaults to one second.
-%%% In case of timed out message the result
-%%% <code>{error, init_timeout, NodeName}</code> is returned;
-%%% </item>
-%%% <item>
-%%% <code>StartupTimeout</code> - time to wait intil the node finishes to run
-%%% the <code>StartupFunctions</code>. Defaults to one second.
-%%% If this timeout occurs, the result
-%%% <code>{error, startup_timeout, NodeName}</code> is returned.
-%%% </item>
-%%% </list>
-%%%
-%%% <p>Option <code>monitor_master</code> specifies, if the slave node should be
-%%% stopped in case of master node stop. Defaults to false.</p>
-%%%
-%%% <p>Option <code>kill_if_fail</code> specifies, if the slave node should be
-%%% killed in case of a timeout during initialization or startup.
-%%% Defaults to true. Note that node also may be still alive it the boot
-%%% timeout occurred, but it will not be killed in this case.</p>
-%%%
-%%% <p>Option <code>erlang_flags</code> specifies, which flags will be added
-%%% to the parameters of the <code>erl</code> executable.</p>
-%%%
-%%% <p>Option <code>env</code> specifies a list of environment variables
-%%% that will extended the environment.</p>
-%%%
-%%% <p>Special return values are:</p>
-%%% <list>
-%%% <item><code>{error, already_started, NodeName}</code> - if the node with
-%%% the given name is already started on a given host;</item>
-%%% <item><code>{error, started_not_connected, NodeName}</code> - if node is
-%%% started, but not connected to the master node.</item>
-%%% <item><code>{error, not_alive, NodeName}</code> - if node on which the
-%%% <code>ct_slave:start/3</code> is called, is not alive. Note that
-%%% <code>NodeName</code> is the name of current node in this case.</item>
-%%% </list>
-%%%
start(Host, Node, Opts) ->
ENode = enodename(Host, Node),
case erlang:is_alive() of
@@ -199,36 +61,9 @@ start(Host, Node, Opts) ->
end
end.
-%%%-----------------------------------------------------------------
-%%% @spec stop(Node) -> Result
-%%% Node = atom()
-%%% Result = {ok, NodeName} |
-%%% {error, Reason, NodeName}
-%%% Reason = not_started |
-%%% not_connected |
-%%% stop_timeout
-%%% NodeName = atom()
-%%% @doc Stops the running Erlang node with name <code>Node</code> on
-%%% the localhost.
stop(Node) ->
stop(gethostname(), Node).
-%%%-----------------------------------------------------------------
-%%% @spec stop(HostOrNode, NodeOrOpts) -> Result
-%%% HostOrNode = atom()
-%%% NodeOrOpts = atom() | list()
-%%% Result = {ok, NodeName} |
-%%% {error, Reason, NodeName}
-%%% Reason = not_started |
-%%% not_connected |
-%%% stop_timeout
-%%% NodeName = atom()
-%%% @doc Stops the running Erlang node with default options on a specified
-%%% host, or on the local host with specified options. That is,
-%%% the call is interpreted as <code>stop(Host, Node)</code> when the
-%%% second argument is atom-valued and <code>stop(Node, Opts)</code>
-%%% when it's list-valued.
-%%% @see stop/3
stop(_HostOrNode = Node, _NodeOrOpts = Opts) %% match to satiate edoc
when is_list(Opts) ->
stop(gethostname(), Node, Opts);
@@ -236,26 +71,6 @@ stop(_HostOrNode = Node, _NodeOrOpts = Opts) %% match to satiate edoc
stop(Host, Node) ->
stop(Host, Node, []).
-%%% @spec stop(Host, Node, Opts) -> Result
-%%% Host = atom()
-%%% Node = atom()
-%%% Opts = [OptTuples]
-%%% OptTuples = {stop_timeout, StopTimeout}
-%%% StopTimeout = integer()
-%%% Result = {ok, NodeName} |
-%%% {error, Reason, NodeName}
-%%% Reason = not_started |
-%%% not_connected |
-%%% stop_timeout
-%%% NodeName = atom()
-%%% @doc Stops the running Erlang node with name <code>Node</code> on
-%%% host <code>Host</code> as specified by options <code>Opts</code>.
-%%%
-%%% <p>Option <code>stop_timeout</code> specifies, in seconds,
-%%% the time to wait until the node is disconnected.
-%%% Defaults to 5 seconds. If this timeout occurs,
-%%% the result <code>{error, stop_timeout, NodeName}</code> is returned.
-%%%
stop(Host, Node, Opts) ->
ENode = enodename(Host, Node),
case is_started(ENode) of
@@ -300,19 +115,16 @@ fetch_options(Options) ->
stop_timeout=StopTimeout}.
% send a message when slave node is started
-% @hidden
slave_started(ENode, MasterPid) ->
MasterPid ! {node_started, ENode},
ok.
% send a message when slave node has finished startup
-% @hidden
slave_ready(ENode, MasterPid) ->
MasterPid ! {node_ready, ENode},
ok.
% start monitoring of the master node
-% @hidden
monitor_master(MasterNode) ->
spawn(fun() -> monitor_master_int(MasterNode) end).
diff --git a/lib/common_test/src/ct_snmp.erl b/lib/common_test/src/ct_snmp.erl
index 5844909d17..27b74dd04e 100644
--- a/lib/common_test/src/ct_snmp.erl
+++ b/lib/common_test/src/ct_snmp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,139 +18,8 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test user interface module for the OTP snmp application
-%%%
-%%% <p>The purpose of this module is to make snmp configuration easier for
-%%% the test case writer. Many test cases can use default values for common
-%%% operations and then no snmp configuration files need to be supplied. When
-%%% it is necessary to change particular configuration parameters, a subset
-%%% of the relevant snmp configuration files may be passed to <code>ct_snmp</code>
-%%% by means of Common Test configuration files.
-%%% For more specialized configuration parameters, it is possible to place a
-%%% "simple snmp configuration file" in the test suite data directory.
-%%% To simplify the test suite, Common Test keeps track
-%%% of some of the snmp manager information. This way the test suite doesn't
-%%% have to handle as many input parameters as it would if it had to interface the
-%%% OTP snmp manager directly.</p>
-%%%
-%%% <p> The following snmp manager and agent parameters are configurable: </p>
-%%%
-%%% <pre>
-%%% {snmp,
-%%% %%% Manager config
-%%% [{start_manager, boolean()} % Optional - default is true
-%%% {users, [{user_name(), [call_back_module(), user_data()]}]}, %% Optional
-%%% {usm_users, [{usm_user_name(), [usm_config()]}]},%% Optional - snmp v3 only
-%%% % managed_agents is optional
-%%% {managed_agents,[{agent_name(), [user_name(), agent_ip(), agent_port(), [agent_config()]]}]},
-%%% {max_msg_size, integer()}, % Optional - default is 484
-%%% {mgr_port, integer()}, % Optional - default is 5000
-%%% {engine _id, string()}, % Optional - default is "mgrEngine"
-%%%
-%%% %%% Agent config
-%%% {start_agent, boolean()}, % Optional - default is false
-%%% {agent_sysname, string()}, % Optional - default is "ct_test"
-%%% {agent_manager_ip, manager_ip()}, % Optional - default is localhost
-%%% {agent_vsns, list()}, % Optional - default is [v2]
-%%% {agent_trap_udp, integer()}, % Optional - default is 5000
-%%% {agent_udp, integer()}, % Optional - default is 4000
-%%% {agent_notify_type, atom()}, % Optional - default is trap
-%%% {agent_sec_type, sec_type()}, % Optional - default is none
-%%% {agent_passwd, string()}, % Optional - default is ""
-%%% {agent_engine_id, string()}, % Optional - default is "agentEngine"
-%%% {agent_max_msg_size, string()},% Optional - default is 484
-%%%
-%%% %% The following parameters represents the snmp configuration files
-%%% %% context.conf, standard.conf, community.conf, vacm.conf,
-%%% %% usm.conf, notify.conf, target_addr.conf and target_params.conf.
-%%% %% Note all values in agent.conf can be altered by the parametes
-%%% %% above. All these configuration files have default values set
-%%% %% up by the snmp application. These values can be overridden by
-%%% %% suppling a list of valid configuration values or a file located
-%%% %% in the test suites data dir that can produce a list
-%%% %% of valid configuration values if you apply file:consult/1 to the
-%%% %% file.
-%%% {agent_contexts, [term()] | {data_dir_file, rel_path()}}, % Optional
-%%% {agent_community, [term()] | {data_dir_file, rel_path()}},% Optional
-%%% {agent_sysinfo, [term()] | {data_dir_file, rel_path()}}, % Optional
-%%% {agent_vacm, [term()] | {data_dir_file, rel_path()}}, % Optional
-%%% {agent_usm, [term()] | {data_dir_file, rel_path()}}, % Optional
-%%% {agent_notify_def, [term()] | {data_dir_file, rel_path()}},% Optional
-%%% {agent_target_address_def, [term()] | {data_dir_file, rel_path()}},% Optional
-%%% {agent_target_param_def, [term()] | {data_dir_file, rel_path()}},% Optional
-%%% ]}.
-%%% </pre>
-%%%
-%%% <p>The <code>MgrAgentConfName</code> parameter in the functions
-%%% should be a name you allocate in your test suite using a
-%%% <code>require</code> statement.
-%%% Example (where <code>MgrAgentConfName = snmp_mgr_agent</code>):</p>
-%%% <pre> suite() -> [{require, snmp_mgr_agent, snmp}].</pre>
-%%% <p>or</p>
-%%% <pre> ct:require(snmp_mgr_agent, snmp).</pre>
-%%%
-%%% <p> Note that Usm users are needed for snmp v3 configuration and are
-%%% not to be confused with users.</p>
-%%%
-%%% <p> Snmp traps, inform and report messages are handled by the
-%%% user callback module. For more information about this see
-%%% the snmp application. </p>
-%%% <p> Note: It is recommended to use the .hrl-files created by the
-%%% Erlang/OTP mib-compiler to define the oids.
-%%% Example for the getting the erlang node name from the erlNodeTable
-%%% in the OTP-MIB:</p>
-%%% <pre>Oid = ?erlNodeEntry ++ [?erlNodeName, 1] </pre>
-%%%
-%%% <p>It is also possible to set values for snmp application configuration
-%%% parameters, such as <code>config</code>, <code>server</code>,
-%%% <code>net_if</code>, etc (see the "Configuring the application" chapter in
-%%% the OTP snmp User's Guide for a list of valid parameters and types). This is
-%%% done by defining a configuration data variable on the following form:</p>
-%%% <pre>
-%%% {snmp_app, [{manager, [snmp_app_manager_params()]},
-%%% {agent, [snmp_app_agent_params()]}]}.</pre>
-%%%
-%%% <p>A name for the data needs to be allocated in the suite using
-%%% <code>require</code> (see example above), and this name passed as
-%%% the <code>SnmpAppConfName</code> argument to <code>start/3</code>.
-%%% <code>ct_snmp</code> specifies default values for some snmp application
-%%% configuration parameters (such as <code>{verbosity,trace}</code> for the
-%%% <code>config</code> parameter). This set of defaults will be
-%%% merged with the parameters specified by the user, and user values
-%%% override <code>ct_snmp</code> defaults.</p>
-
-module(ct_snmp).
-%%% Common Types
-%%% @type agent_ip() = ip()
-%%% @type manager_ip() = ip()
-%%% @type agent_name() = atom()
-%%% @type ip() = string() | {integer(), integer(),
-%%% integer(), integer()}
-%%% @type agent_port() = integer()
-%%% @type agent_config() = {Item, Value}
-%%% @type user_name() = atom()
-%%% @type usm_user_name() = string()
-%%% @type usm_config() = {Item, Value}
-%%% @type call_back_module() = atom()
-%%% @type user_data() = term()
-%%% @type oids() = [oid()]
-%%% @type oid() = [byte()]
-%%% @type snmpreply() = {error_status(), error_index(), varbinds()}
-%%% @type error_status() = noError | atom()
-%%% @type error_index() = integer()
-%%% @type varbinds() = [varbind()]
-%%% @type varbind() = term()
-%%% @type value_type() = o ('OBJECT IDENTIFIER') | i ('INTEGER') |
-%%% u ('Unsigned32') | g ('Unsigned32') | s ('OCTET STRING')
-%%% @type varsandvals() = [var_and_val()]
-%%% @type var_and_val() = {oid(), value_type(), value()}
-%%% @type sec_type() = none | minimum | semi
-%%% @type rel_path() = string()
-%%% @type snmp_app_manager_params() = term()
-%%% @type snmp_app_agent_params() = term()
-
-
-include("snmp_types.hrl").
-include("inet.hrl").
-include("ct.hrl").
@@ -181,31 +50,9 @@
%%% API
%%%=========================================================================
-%%%-----------------------------------------------------------------
-%%% @spec start(Config, MgrAgentConfName) -> ok
-%%% @equiv start(Config, MgrAgentConfName, undefined)
start(Config, MgrAgentConfName) ->
start(Config, MgrAgentConfName, undefined).
-%%% @spec start(Config, MgrAgentConfName, SnmpAppConfName) -> ok
-%%% Config = [{Key, Value}]
-%%% Key = atom()
-%%% Value = term()
-%%% MgrAgentConfName = atom()
-%%% SnmpConfName = atom()
-%%%
-%%% @doc Starts an snmp manager and/or agent. In the manager case,
-%%% registrations of users and agents as specified by the configuration
-%%% <code>MgrAgentConfName</code> will be performed. When using snmp
-%%% v3 also so called usm users will be registered. Note that users,
-%%% usm_users and managed agents may also be registered at a later time
-%%% using ct_snmp:register_users/2, ct_snmp:register_agents/2, and
-%%% ct_snmp:register_usm_users/2. The agent started will be
-%%% called <code>snmp_master_agent</code>. Use ct_snmp:load_mibs/1 to load
-%%% mibs into the agent. With <code>SnmpAppConfName</code> it's possible
-%%% to configure the snmp application with parameters such as <code>config</code>,
-%%% <code>mibs</code>, <code>net_if</code>, etc. The values will be merged
-%%% with (and possibly override) default values set by <code>ct_snmp</code>.
start(Config, MgrAgentConfName, SnmpAppConfName) ->
StartManager= ct:get_config({MgrAgentConfName, start_manager}, true),
StartAgent = ct:get_config({MgrAgentConfName, start_agent}, false),
@@ -233,12 +80,6 @@ start_application(App) ->
Else
end.
-%%% @spec stop(Config) -> ok
-%%% Config = [{Key, Value}]
-%%% Key = atom()
-%%% Value = term()
-%%%
-%%% @doc Stops the snmp manager and/or agent removes all files created.
stop(Config) ->
PrivDir = ?config(priv_dir, Config),
ok = application:stop(snmp),
@@ -251,41 +92,16 @@ stop(Config) ->
catch del_dir(DbDir).
-%%% @spec get_values(Agent, Oids, MgrAgentConfName) -> SnmpReply
-%%%
-%%% Agent = agent_name()
-%%% Oids = oids()
-%%% MgrAgentConfName = atom()
-%%% SnmpReply = snmpreply()
-%%%
-%%% @doc Issues a synchronous snmp get request.
get_values(Agent, Oids, MgrAgentConfName) ->
[Uid | _] = agent_conf(Agent, MgrAgentConfName),
{ok, SnmpReply, _} = snmpm:sync_get2(Uid, target_name(Agent), Oids),
SnmpReply.
-%%% @spec get_next_values(Agent, Oids, MgrAgentConfName) -> SnmpReply
-%%%
-%%% Agent = agent_name()
-%%% Oids = oids()
-%%% MgrAgentConfName = atom()
-%%% SnmpReply = snmpreply()
-%%%
-%%% @doc Issues a synchronous snmp get next request.
get_next_values(Agent, Oids, MgrAgentConfName) ->
[Uid | _] = agent_conf(Agent, MgrAgentConfName),
{ok, SnmpReply, _} = snmpm:sync_get_next2(Uid, target_name(Agent), Oids),
SnmpReply.
-%%% @spec set_values(Agent, VarsAndVals, MgrAgentConfName, Config) -> SnmpReply
-%%%
-%%% Agent = agent_name()
-%%% Oids = oids()
-%%% MgrAgentConfName = atom()
-%%% Config = [{Key, Value}]
-%%% SnmpReply = snmpreply()
-%%%
-%%% @doc Issues a synchronous snmp set request.
set_values(Agent, VarsAndVals, MgrAgentConfName, Config) ->
PrivDir = ?config(priv_dir, Config),
[Uid | _] = agent_conf(Agent, MgrAgentConfName),
@@ -301,19 +117,6 @@ set_values(Agent, VarsAndVals, MgrAgentConfName, Config) ->
end,
SnmpSetReply.
-%%% @spec set_info(Config) -> [{Agent, OldVarsAndVals, NewVarsAndVals}]
-%%%
-%%% Config = [{Key, Value}]
-%%% Agent = agent_name()
-%%% OldVarsAndVals = varsandvals()
-%%% NewVarsAndVals = varsandvals()
-%%%
-%%% @doc Returns a list of all successful set requests performed in
-%%% the test case in reverse order. The list contains the involved
-%%% user and agent, the value prior to the set and the new value. This
-%%% is intended to facilitate the clean up in the end_per_testcase
-%%% function i.e. the undoing of the set requests and its possible
-%%% side-effects.
set_info(Config) ->
PrivDir = ?config(priv_dir, Config),
SetLogFile = filename:join(PrivDir, ?CT_SNMP_LOG_FILE),
@@ -325,18 +128,6 @@ set_info(Config) ->
[]
end.
-%%% @spec register_users(MgrAgentConfName, Users) -> ok | {error, Reason}
-%%%
-%%% MgrAgentConfName = atom()
-%%% Users = [user()]
-%%% Reason = term()
-%%%
-%%% @doc Register the manager entity (=user) responsible for specific agent(s).
-%%% Corresponds to making an entry in users.conf.
-%%%
-%%% <p>This function will try to register the given users, without
-%%% checking if any of them already exist. In order to change an
-%%% already registered user, the user must first be unregistered.</p>
register_users(MgrAgentConfName, Users) ->
case setup_users(Users) of
ok ->
@@ -350,19 +141,6 @@ register_users(MgrAgentConfName, Users) ->
Error
end.
-%%% @spec register_agents(MgrAgentConfName, ManagedAgents) -> ok | {error, Reason}
-%%%
-%%% MgrAgentConfName = atom()
-%%% ManagedAgents = [agent()]
-%%% Reason = term()
-%%%
-%%% @doc Explicitly instruct the manager to handle this agent.
-%%% Corresponds to making an entry in agents.conf
-%%%
-%%% <p>This function will try to register the given managed agents,
-%%% without checking if any of them already exist. In order to change
-%%% an already registered managed agent, the agent must first be
-%%% unregistered.</p>
register_agents(MgrAgentConfName, ManagedAgents) ->
case setup_managed_agents(MgrAgentConfName,ManagedAgents) of
ok ->
@@ -377,18 +155,6 @@ register_agents(MgrAgentConfName, ManagedAgents) ->
Error
end.
-%%% @spec register_usm_users(MgrAgentConfName, UsmUsers) -> ok | {error, Reason}
-%%%
-%%% MgrAgentConfName = atom()
-%%% UsmUsers = [usm_user()]
-%%% Reason = term()
-%%%
-%%% @doc Explicitly instruct the manager to handle this USM user.
-%%% Corresponds to making an entry in usm.conf
-%%%
-%%% <p>This function will try to register the given users, without
-%%% checking if any of them already exist. In order to change an
-%%% already registered user, the user must first be unregistered.</p>
register_usm_users(MgrAgentConfName, UsmUsers) ->
EngineID = ct:get_config({MgrAgentConfName, engine_id}, ?ENGINE_ID),
case setup_usm_users(UsmUsers, EngineID) of
@@ -403,23 +169,10 @@ register_usm_users(MgrAgentConfName, UsmUsers) ->
Error
end.
-%%% @spec unregister_users(MgrAgentConfName) -> ok
-%%%
-%%% MgrAgentConfName = atom()
-%%% Reason = term()
-%%%
-%%% @doc Unregister all users.
unregister_users(MgrAgentConfName) ->
Users = [Id || {Id,_} <- ct:get_config({MgrAgentConfName, users},[])],
unregister_users(MgrAgentConfName,Users).
-%%% @spec unregister_users(MgrAgentConfName,Users) -> ok
-%%%
-%%% MgrAgentConfName = atom()
-%%% Users = [user_name()]
-%%% Reason = term()
-%%%
-%%% @doc Unregister the given users.
unregister_users(MgrAgentConfName,Users) ->
takedown_users(Users),
SnmpVals = ct:get_config(MgrAgentConfName),
@@ -432,25 +185,12 @@ unregister_users(MgrAgentConfName,Users) ->
ct_config:update_config(MgrAgentConfName, NewSnmpVals),
ok.
-%%% @spec unregister_agents(MgrAgentConfName) -> ok
-%%%
-%%% MgrAgentConfName = atom()
-%%% Reason = term()
-%%%
-%%% @doc Unregister all managed agents.
unregister_agents(MgrAgentConfName) ->
ManagedAgents = [AgentName ||
{AgentName, _} <-
ct:get_config({MgrAgentConfName,managed_agents},[])],
unregister_agents(MgrAgentConfName,ManagedAgents).
-%%% @spec unregister_agents(MgrAgentConfName,ManagedAgents) -> ok
-%%%
-%%% MgrAgentConfName = atom()
-%%% ManagedAgents = [agent_name()]
-%%% Reason = term()
-%%%
-%%% @doc Unregister the given managed agents.
unregister_agents(MgrAgentConfName,ManagedAgents) ->
takedown_managed_agents(MgrAgentConfName, ManagedAgents),
SnmpVals = ct:get_config(MgrAgentConfName),
@@ -464,23 +204,10 @@ unregister_agents(MgrAgentConfName,ManagedAgents) ->
ct_config:update_config(MgrAgentConfName, NewSnmpVals),
ok.
-%%% @spec unregister_usm_users(MgrAgentConfName) -> ok
-%%%
-%%% MgrAgentConfName = atom()
-%%% Reason = term()
-%%%
-%%% @doc Unregister all usm users.
unregister_usm_users(MgrAgentConfName) ->
UsmUsers = [Id || {Id,_} <- ct:get_config({MgrAgentConfName, usm_users},[])],
unregister_usm_users(MgrAgentConfName,UsmUsers).
-%%% @spec unregister_usm_users(MgrAgentConfName,UsmUsers) -> ok
-%%%
-%%% MgrAgentConfName = atom()
-%%% UsmUsers = [usm_user_name()]
-%%% Reason = term()
-%%%
-%%% @doc Unregister the given usm users.
unregister_usm_users(MgrAgentConfName,UsmUsers) ->
EngineID = ct:get_config({MgrAgentConfName, engine_id}, ?ENGINE_ID),
takedown_usm_users(UsmUsers,EngineID),
@@ -495,23 +222,9 @@ unregister_usm_users(MgrAgentConfName,UsmUsers) ->
ct_config:update_config(MgrAgentConfName, NewSnmpVals),
ok.
-%%% @spec load_mibs(Mibs) -> ok | {error, Reason}
-%%%
-%%% Mibs = [MibName]
-%%% MibName = string()
-%%% Reason = term()
-%%%
-%%% @doc Load the mibs into the agent 'snmp_master_agent'.
load_mibs(Mibs) ->
snmpa:load_mibs(snmp_master_agent, Mibs).
-%%% @spec unload_mibs(Mibs) -> ok | {error, Reason}
-%%%
-%%% Mibs = [MibName]
-%%% MibName = string()
-%%% Reason = term()
-%%%
-%%% @doc Unload the mibs from the agent 'snmp_master_agent'.
unload_mibs(Mibs) ->
snmpa:unload_mibs(snmp_master_agent, Mibs).
diff --git a/lib/common_test/src/ct_ssh.erl b/lib/common_test/src/ct_ssh.erl
index 491d56dfc1..79ab122452 100644
--- a/lib/common_test/src/ct_ssh.erl
+++ b/lib/common_test/src/ct_ssh.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,44 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc SSH/SFTP client module.
-%%%
-%%% <p>ct_ssh uses the OTP ssh application and more detailed information
-%%% about e.g. functions, types and options can be found in the
-%%% documentation for this application.</p>
-%%%
-%%% <p>The <code>Server</code> argument in the SFTP functions should
-%%% only be used for SFTP sessions that have been started on existing
-%%% SSH connections (i.e. when the original connection type is
-%%% <code>ssh</code>). Whenever the connection type is
-%%% <code>sftp</code>, use the SSH connection reference only.</p>
-%%%
-%%% <p>The following options are valid for specifying an SSH/SFTP
-%%% connection (i.e. may be used as config elements):</p>
-%%%
-%%% <pre>
-%%%
-%%% [{ConnType, Addr},
-%%% {port, Port},
-%%% {user, UserName}
-%%% {password, Pwd}
-%%% {user_dir, String}
-%%% {public_key_alg, PubKeyAlg}
-%%% {connect_timeout, Timeout}
-%%% {key_cb, KeyCallbackMod}]
-%%% </pre>
-%%%
-%%% <p><code>ConnType = ssh | sftp</code>.</p>
-%%% <p>Please see ssh(3) for other types.</p>
-%%%
-%%% <p>All timeout parameters in ct_ssh functions are values in
-%%% milliseconds.</p>
-%%%
-%%% @type connection() = handle() | ct:target_name()
-%%% @type handle() = ct_gen_conn:handle(). Handle for a specific
-%%% SSH/SFTP connection.
-%%% @type ssh_sftp_return() = term(). A return value from an ssh_sftp function.
-
-module(ct_ssh).
%% SSH Functions
@@ -100,64 +62,15 @@
%%%-----------------------------------------------------------------
%%%------------------------ SSH COMMANDS ---------------------------
-%%%-----------------------------------------------------------------
-%%% @spec connect(KeyOrName) -> {ok,Handle} | {error,Reason}
-%%% @equiv connect(KeyOrName,host,[])
connect(KeyOrName) ->
connect(KeyOrName, host).
-%%%-----------------------------------------------------------------
-%%% @spec connect(KeyOrName,ConnType) -> {ok,Handle} | {error,Reason}
-%%% @equiv connect(KeyOrName,ConnType,[])
connect(KeyOrName, ConnType) when is_atom(ConnType) ->
connect(KeyOrName, ConnType, []);
-%%%-----------------------------------------------------------------
-%%% @spec connect(KeyOrName,ExtraOpts) -> {ok,Handle} | {error,Reason}
-%%% @equiv connect(KeyOrName,host,ExtraOpts)
connect(KeyOrName, ExtraOpts) when is_list(ExtraOpts) ->
connect(KeyOrName, host, ExtraOpts).
-%%%-----------------------------------------------------------------
-%%% @spec connect(KeyOrName,ConnType,ExtraOpts) ->
-%%% {ok,Handle} | {error,Reason}
-%%% KeyOrName = Key | Name
-%%% Key = atom()
-%%% Name = ct:target_name()
-%%% ConnType = ssh | sftp | host
-%%% ExtraOpts = ssh_connect_options()
-%%% Handle = handle()
-%%% Reason = term()
-%%%
-%%% @doc Open an SSH or SFTP connection using the information
-%%% associated with <code>KeyOrName</code>.
-%%%
-%%% <p>If <code>Name</code> (an alias name for <code>Key</code>),
-%%% is used to identify the connection, this name may
-%%% be used as connection reference for subsequent calls.
-%%% It's only possible to have one open connection at a time
-%%% associated with <code>Name</code>. If <code>Key</code> is
-%%% used, the returned handle must be used for subsequent calls
-%%% (multiple connections may be opened using the config
-%%% data specified by <code>Key</code>). See <c>ct:require/2</c>
-%%% for how to create a new <c>Name</c></p>
-%%%
-%%% <p><code>ConnType</code> will always override the type
-%%% specified in the address tuple in the configuration data (and
-%%% in <code>ExtraOpts</code>). So it is possible to for example
-%%% open an sftp connection directly using data originally
-%%% specifying an ssh connection. The value <code>host</code>
-%%% means the connection type specified by the host option
-%%% (either in the configuration data or in <code>ExtraOpts</code>)
-%%% will be used.</p>
-%%%
-%%% <p><code>ExtraOpts</code> (optional) are extra SSH options
-%%% to be added to the config data for <code>KeyOrName</code>.
-%%% The extra options will override any existing options with the
-%%% same key in the config data. For details on valid SSH
-%%% options, see the documentation for the OTP ssh application.</p>
-%%%
-%%% @see ct:require/2
connect(KeyOrName, ConnType, ExtraOpts) ->
case ct:get_config(KeyOrName) of
undefined ->
@@ -232,12 +145,6 @@ connect(KeyOrName, ConnType, ExtraOpts) ->
end
end.
-%%%-----------------------------------------------------------------
-%%% @spec disconnect(SSH) -> ok | {error,Reason}
-%%% SSH = connection()
-%%% Reason = term()
-%%%
-%%% @doc Close an SSH/SFTP connection.
disconnect(SSH) ->
case get_handle(SSH) of
{ok,Pid} ->
@@ -252,242 +159,78 @@ disconnect(SSH) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @spec session_open(SSH) -> {ok,ChannelId} | {error, Reason}
-%%% @equiv session_open(SSH,DefaultTimeout)
session_open(SSH) ->
call(SSH, {session_open,?DEFAULT_TIMEOUT}).
-%%%-----------------------------------------------------------------
-%%% @spec session_open(SSH,Timeout) -> {ok,ChannelId} | {error, Reason}
-%%% SSH = connection()
-%%% Timeout = integer()
-%%% ChannelId = integer()
-%%% Reason = term()
-%%%
-%%% @doc Opens a channel for an SSH session.
session_open(SSH, Timeout) ->
call(SSH, {session_open,Timeout}).
-%%%-----------------------------------------------------------------
-%%% @spec session_close(SSH,ChannelId) -> ok | {error, Reason}
-%%% SSH = connection()
-%%% ChannelId = integer()
-%%% Reason = term()
-%%%
-%%% @doc Closes an SSH session channel.
session_close(SSH, ChannelId) ->
call(SSH, {session_close,ChannelId}).
-%%%-----------------------------------------------------------------
-%%% @spec exec(SSH,Command) -> {ok,Data} | {error,Reason}
-%%% @equiv exec(SSH,Command,DefaultTimeout)
exec(SSH, Command) ->
exec(SSH, undefined, Command, ?DEFAULT_TIMEOUT).
-%%%-----------------------------------------------------------------
-%%% @spec exec(SSH,Command,Timeout) -> {ok,Data} | {error,Reason}
-%%% SSH = connection()
-%%% Command = string()
-%%% Timeout = integer()
-%%% Data = list()
-%%% Reason = term()
-%%%
-%%% @doc Requests server to perform <code>Command</code>. A session
-%%% channel is opened automatically for the request.
-%%% <code>Data</code> is received from the server as a result
-%%% of the command.
exec(SSH, Command, Timeout) when is_list(Command) ->
exec(SSH, undefined, Command, Timeout);
-%%%-----------------------------------------------------------------
-%%% @spec exec(SSH,ChannelId,Command) -> {ok,Data} | {error,Reason}
-%%% @equiv exec(SSH,ChannelId,Command,DefaultTimeout)
exec(SSH, ChannelId, Command) when is_integer(ChannelId) ->
exec(SSH, ChannelId, Command, ?DEFAULT_TIMEOUT).
-%%%-----------------------------------------------------------------
-%%% @spec exec(SSH,ChannelId,Command,Timeout) -> {ok,Data} | {error,Reason}
-%%% SSH = connection()
-%%% ChannelId = integer()
-%%% Command = string()
-%%% Timeout = integer()
-%%% Data = list()
-%%% Reason = term()
-%%%
-%%% @doc Requests server to perform <code>Command</code>. A previously
-%%% opened session channel is used for the request.
-%%% <code>Data</code> is received from the server as a result
-%%% of the command.
exec(SSH, ChannelId, Command, Timeout) ->
call(SSH, {exec,ChannelId,Command,Timeout}).
-%%%-----------------------------------------------------------------
-%%% @spec receive_response(SSH,ChannelId) -> {ok,Data} | {error,Reason}
-%%% @equiv receive_response(SSH,ChannelId,close)
receive_response(SSH, ChannelId) ->
receive_response(SSH, ChannelId, close, ?DEFAULT_TIMEOUT).
-%%%-----------------------------------------------------------------
-%%% @spec receive_response(SSH,ChannelId,End) -> {ok,Data} | {error,Reason}
-%%% @equiv receive_response(SSH,ChannelId,End,DefaultTimeout)
receive_response(SSH, ChannelId, End) when is_function(End) ->
receive_response(SSH, ChannelId, End, ?DEFAULT_TIMEOUT);
-%%%-----------------------------------------------------------------
-%%% @spec receive_response(SSH,ChannelId,Timeout) -> {ok,Data} | {error,Reason}
-%%% @equiv receive_response(SSH,ChannelId,close,Timeout)
receive_response(SSH, ChannelId, Timeout) when is_integer(Timeout) ->
receive_response(SSH, ChannelId, close, Timeout).
-%%%-----------------------------------------------------------------
-%%% @spec receive_response(SSH,ChannelId,End,Timeout) ->
-%%% {ok,Data} | {timeout,Data} | {error,Reason}
-%%% SSH = connection()
-%%% ChannelId = integer()
-%%% End = Fun | close | timeout
-%%% Timeout = integer()
-%%% Data = list()
-%%% Reason = term()
-%%%
-%%% @doc Receives expected data from server on the specified
-%%% session channel.
-%%%
-%%% <p>If <code>End == close</code>, data is returned
-%%% to the caller when the channel is closed by the
-%%% server. If a timeout occurs before this happens,
-%%% the function returns <code>{timeout,Data}</code>
-%%% (where <code>Data</code> is the data received so far).
-%%% If <code>End == timeout</code>, a timeout is expected
-%%% and <code>{ok,Data}</code> is returned both in the case
-%%% of a timeout and when the channel is closed. If
-%%% <code>End</code> is a fun, this fun will be
-%%% called with one argument - the data value in a received
-%%% <code>ssh_cm</code> message (see ssh_connection(3)). The
-%%% fun should return <code>true</code> to end the receiving
-%%% operation (and have the so far collected data returned), or
-%%% <code>false</code> to wait for more data from the server.
-%%% (Note that even if a fun is supplied, the function returns
-%%% immediately if the server closes the channel).</p>
receive_response(SSH, ChannelId, End, Timeout) ->
call(SSH, {receive_response,ChannelId,End,Timeout}).
-%%%-----------------------------------------------------------------
-%%% @spec send(SSH,ChannelId,Data) -> ok | {error,Reason}
-%%% @equiv send(SSH,ChannelId,0,Data,DefaultTimeout)
send(SSH, ChannelId, Data) ->
send(SSH, ChannelId, 0, Data, ?DEFAULT_TIMEOUT).
-%%%-----------------------------------------------------------------
-%%% @spec send(SSH,ChannelId,Data,Timeout) -> ok | {error,Reason}
-%%% @equiv send(SSH,ChannelId,0,Data,Timeout)
send(SSH, ChannelId, Data, Timeout) when is_integer(Timeout) ->
send(SSH, ChannelId, 0, Data, Timeout);
-%%%-----------------------------------------------------------------
-%%% @spec send(SSH,ChannelId,Type,Data) -> ok | {error,Reason}
-%%% @equiv send(SSH,ChannelId,Type,Data,DefaultTimeout)
send(SSH, ChannelId, Type, Data) when is_integer(Type) ->
send(SSH, ChannelId, Type, Data, ?DEFAULT_TIMEOUT).
-%%%-----------------------------------------------------------------
-%%% @spec send(SSH,ChannelId,Type,Data,Timeout) -> ok | {error,Reason}
-%%% SSH = connection()
-%%% ChannelId = integer()
-%%% Type = integer()
-%%% Data = list()
-%%% Timeout = integer()
-%%% Reason = term()
-%%%
-%%% @doc Send data to server on specified session channel.
send(SSH, ChannelId, Type, Data, Timeout) ->
call(SSH, {send,ChannelId,Type,Data,Timeout}).
-%%%-----------------------------------------------------------------
-%%% @spec send_and_receive(SSH,ChannelId,Data) ->
-%%% {ok,Data} | {error,Reason}
-%%% @equiv send_and_receive(SSH,ChannelId,Data,close)
send_and_receive(SSH, ChannelId, Data) ->
send_and_receive(SSH, ChannelId, 0, Data, close, ?DEFAULT_TIMEOUT).
-%%%-----------------------------------------------------------------
-%%% @spec send_and_receive(SSH,ChannelId,Data,End) ->
-%%% {ok,Data} | {error,Reason}
-%%% @equiv send_and_receive(SSH,ChannelId,0,Data,End,DefaultTimeout)
send_and_receive(SSH, ChannelId, Data, End) when is_function(End) ->
send_and_receive(SSH, ChannelId, 0, Data, End, ?DEFAULT_TIMEOUT);
-%%%-----------------------------------------------------------------
-%%% @spec send_and_receive(SSH,ChannelId,Data,Timeout) ->
-%%% {ok,Data} | {error,Reason}
-%%% @equiv send_and_receive(SSH,ChannelId,0,Data,close,Timeout)
send_and_receive(SSH, ChannelId, Data, Timeout) when is_integer(Timeout) ->
send_and_receive(SSH, ChannelId, 0, Data, close, Timeout);
-%%%-----------------------------------------------------------------
-%%% @spec send_and_receive(SSH,ChannelId,Type,Data) ->
-%%% {ok,Data} | {error,Reason}
-%%% @equiv send_and_receive(SSH,ChannelId,Type,Data,close,DefaultTimeout)
send_and_receive(SSH, ChannelId, Type, Data) when is_integer(Type) ->
send_and_receive(SSH, ChannelId, Type, Data, close, ?DEFAULT_TIMEOUT).
-%%%-----------------------------------------------------------------
-%%% @spec send_and_receive(SSH,ChannelId,Data,End,Timeout) ->
-%%% {ok,Data} | {error,Reason}
-%%% @equiv send_and_receive(SSH,ChannelId,0,Data,End,Timeout)
send_and_receive(SSH, ChannelId, Data, End, Timeout) when is_integer(Timeout) ->
send_and_receive(SSH, ChannelId, 0, Data, End, Timeout);
-%%%-----------------------------------------------------------------
-%%% @spec send_and_receive(SSH,ChannelId,Type,Data,Timeout) ->
-%%% {ok,Data} | {error,Reason}
-%%% @equiv send_and_receive(SSH,ChannelId,Type,Data,close,Timeout)
send_and_receive(SSH, ChannelId, Type, Data, Timeout) when is_integer(Type) ->
send_and_receive(SSH, ChannelId, Type, Data, close, Timeout);
-%%%-----------------------------------------------------------------
-%%% @spec send_and_receive(SSH,ChannelId,Type,Data,End) ->
-%%% {ok,Data} | {error,Reason}
-%%% @equiv send_and_receive(SSH,ChannelId,Type,Data,End,DefaultTimeout)
send_and_receive(SSH, ChannelId, Type, Data, End) when is_function(End) ->
send_and_receive(SSH, ChannelId, Type, Data, End, ?DEFAULT_TIMEOUT).
-%%%-----------------------------------------------------------------
-%%% @spec send_and_receive(SSH,ChannelId,Type,Data,End,Timeout) ->
-%%% {ok,Data} | {error,Reason}
-%%% SSH = connection()
-%%% ChannelId = integer()
-%%% Type = integer()
-%%% Data = list()
-%%% End = Fun | close | timeout
-%%% Timeout = integer()
-%%% Reason = term()
-%%%
-%%% @doc Send data to server on specified session channel and wait
-%%% to receive the server response.
-%%%
-%%% <p>See <code>receive_response/4</code> for details on the
-%%% <code>End</code> argument.</p>
send_and_receive(SSH, ChannelId, Type, Data, End, Timeout) ->
call(SSH, {send_and_receive,ChannelId,Type,Data,End,Timeout}).
-%%%-----------------------------------------------------------------
-%%% @spec subsystem(SSH,ChannelId,Subsystem) -> Status | {error,Reason}
-%%% @equiv subsystem(SSH,ChannelId,Subsystem,DefaultTimeout)
subsystem(SSH, ChannelId, Subsystem) ->
subsystem(SSH, ChannelId, Subsystem, ?DEFAULT_TIMEOUT).
-%%%-----------------------------------------------------------------
-%%% @spec subsystem(SSH,ChannelId,Subsystem,Timeout) ->
-%%% Status | {error,Reason}
-%%% SSH = connection()
-%%% ChannelId = integer()
-%%% Subsystem = string()
-%%% Timeout = integer()
-%%% Status = success | failure
-%%% Reason = term()
-%%%
-%%% @doc Sends a request to execute a predefined subsystem.
subsystem(SSH, ChannelId, Subsystem, Timeout) ->
call(SSH, {subsystem,ChannelId,Subsystem,Timeout}).
@@ -511,439 +254,157 @@ shell(SSH, ChannelId, Timeout) ->
%%%-----------------------------------------------------------------
%%%------------------------ SFTP COMMANDS --------------------------
-%%%-----------------------------------------------------------------
-%%% @spec sftp_connect(SSH) -> {ok,Server} | {error,Reason}
-%%% SSH = connection()
-%%% Server = pid()
-%%% Reason = term()
-%%% @doc Starts an SFTP session on an already existing SSH connection.
-%%% <code>Server</code> identifies the new session and must be
-%%% specified whenever SFTP requests are to be sent.
sftp_connect(SSH) ->
call(SSH, sftp_connect).
-%%%-----------------------------------------------------------------
-%%% @spec read_file(SSH, File) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
read_file(SSH, File) ->
call(SSH, {read_file,sftp,File}).
-%%%-----------------------------------------------------------------
-%%% @spec read_file(SSH, Server, File) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
read_file(SSH, Server, File) ->
call(SSH, {read_file,Server,File}).
-%%%-----------------------------------------------------------------
-%%% @spec write_file(SSH, File, Iolist) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
write_file(SSH, File, Iolist) ->
call(SSH, {write_file,sftp,File,Iolist}).
-%%%-----------------------------------------------------------------
-%%% @spec write_file(SSH, Server, File, Iolist) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
write_file(SSH, Server, File, Iolist) ->
call(SSH, {write_file,Server,File,Iolist}).
-%%%-----------------------------------------------------------------
-%%% @spec list_dir(SSH, Path) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
list_dir(SSH, Path) ->
call(SSH, {list_dir,sftp,Path}).
-%%%-----------------------------------------------------------------
-%%% @spec list_dir(SSH, Server, Path) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
list_dir(SSH, Server, Path) ->
call(SSH, {list_dir,Server,Path}).
-%%%-----------------------------------------------------------------
-%%% @spec open(SSH, File, Mode) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
open(SSH, File, Mode) ->
call(SSH, {open,sftp,File,Mode}).
-%%%-----------------------------------------------------------------
-%%% @spec open(SSH, Server, File, Mode) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
open(SSH, Server, File, Mode) ->
call(SSH, {open,Server,File,Mode}).
-%%%-----------------------------------------------------------------
-%%% @spec opendir(SSH, Path) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
opendir(SSH, Path) ->
call(SSH, {opendir,sftp,Path}).
-%%%-----------------------------------------------------------------
-%%% @spec opendir(SSH, Server, Path) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
opendir(SSH, Server, Path) ->
call(SSH, {opendir,Server,Path}).
-%%%-----------------------------------------------------------------
-%%% @spec close(SSH, Handle) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
close(SSH, Handle) ->
call(SSH, {close,sftp,Handle}).
-%%%-----------------------------------------------------------------
-%%% @spec close(SSH, Server, Handle) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
close(SSH, Server, Handle) ->
call(SSH, {close,Server,Handle}).
-%%%-----------------------------------------------------------------
-%%% @spec read(SSH, Handle, Len) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
read(SSH, Handle, Len) ->
call(SSH, {read,sftp,Handle,Len}).
-%%%-----------------------------------------------------------------
-%%% @spec read(SSH, Server, Handle, Len) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
read(SSH, Server, Handle, Len) ->
call(SSH, {read,Server,Handle,Len}).
-%%%-----------------------------------------------------------------
-%%% @spec pread(SSH, Handle, Position, Length) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
pread(SSH, Handle, Position, Length) ->
call(SSH, {pread,sftp,Handle,Position,Length}).
-%%%-----------------------------------------------------------------
-%%% @spec pread(SSH, Server, Handle, Position, Length) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
pread(SSH, Server, Handle, Position, Length) ->
call(SSH, {pread,Server,Handle,Position,Length}).
-%%%-----------------------------------------------------------------
-%%% @spec aread(SSH, Handle, Len) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
aread(SSH, Handle, Len) ->
call(SSH, {aread,sftp,Handle,Len}).
-%%%-----------------------------------------------------------------
-%%% @spec aread(SSH, Server, Handle, Len) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
aread(SSH, Server, Handle, Len) ->
call(SSH, {aread,Server,Handle,Len}).
-%%%-----------------------------------------------------------------
-%%% @spec apread(SSH, Handle, Position, Length) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
apread(SSH, Handle, Position, Length) ->
call(SSH, {apread,sftp,Handle,Position,Length}).
-%%%-----------------------------------------------------------------
-%%% @spec apread(SSH, Server, Handle, Position, Length) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
apread(SSH, Server, Handle, Position, Length) ->
call(SSH, {apread,Server,Handle,Position,Length}).
-%%%-----------------------------------------------------------------
-%%% @spec write(SSH, Handle, Data) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
write(SSH, Handle, Data) ->
call(SSH, {write,sftp,Handle,Data}).
-%%%-----------------------------------------------------------------
-%%% @spec write(SSH, Server, Handle, Data) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
write(SSH, Server, Handle, Data) ->
call(SSH, {write,Server,Handle,Data}).
-%%%-----------------------------------------------------------------
-%%% @spec pwrite(SSH, Handle, Position, Data) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
pwrite(SSH, Handle, Position, Data) ->
call(SSH, {pwrite,sftp,Handle,Position,Data}).
-%%%-----------------------------------------------------------------
-%%% @spec pwrite(SSH, Server, Handle, Position, Data) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
pwrite(SSH, Server, Handle, Position, Data) ->
call(SSH, {pwrite,Server,Handle,Position,Data}).
-%%%-----------------------------------------------------------------
-%%% @spec awrite(SSH, Handle, Data) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
awrite(SSH, Handle, Data) ->
call(SSH, {awrite,sftp,Handle, Data}).
-%%%-----------------------------------------------------------------
-%%% @spec awrite(SSH, Server, Handle, Data) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
awrite(SSH, Server, Handle, Data) ->
call(SSH, {awrite,Server,Handle, Data}).
-%%%-----------------------------------------------------------------
-%%% @spec apwrite(SSH, Handle, Position, Data) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
apwrite(SSH, Handle, Position, Data) ->
call(SSH, {apwrite,sftp,Handle,Position,Data}).
-%%%-----------------------------------------------------------------
-%%% @spec apwrite(SSH, Server, Handle, Position, Data) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
apwrite(SSH, Server, Handle, Position, Data) ->
call(SSH, {apwrite,Server,Handle,Position,Data}).
-%%%-----------------------------------------------------------------
-%%% @spec position(SSH, Handle, Location) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
position(SSH, Handle, Location) ->
call(SSH, {position,sftp,Handle,Location}).
-%%%-----------------------------------------------------------------
-%%% @spec position(SSH, Server, Handle, Location) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
position(SSH, Server, Handle, Location) ->
call(SSH, {position,Server,Handle,Location}).
-%%%-----------------------------------------------------------------
-%%% @spec read_file_info(SSH, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
read_file_info(SSH, Name) ->
call(SSH, {read_file_info,sftp,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec read_file_info(SSH, Server, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
read_file_info(SSH, Server, Name) ->
call(SSH, {read_file_info,Server,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec get_file_info(SSH, Handle) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
get_file_info(SSH, Handle) ->
call(SSH, {get_file_info,sftp,Handle}).
-%%%-----------------------------------------------------------------
-%%% @spec get_file_info(SSH, Server, Handle) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
get_file_info(SSH, Server, Handle) ->
call(SSH, {get_file_info,Server,Handle}).
-%%%-----------------------------------------------------------------
-%%% @spec read_link_info(SSH, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
read_link_info(SSH, Name) ->
call(SSH, {read_link_info,sftp,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec read_link_info(SSH, Server, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
read_link_info(SSH, Server, Name) ->
call(SSH, {read_link_info,Server,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec write_file_info(SSH, Name, Info) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
write_file_info(SSH, Name, Info) ->
call(SSH, {write_file_info,sftp,Name,Info}).
-%%%-----------------------------------------------------------------
-%%% @spec write_file_info(SSH, Server, Name, Info) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
write_file_info(SSH, Server, Name, Info) ->
call(SSH, {write_file_info,Server,Name,Info}).
-%%%-----------------------------------------------------------------
-%%% @spec read_link(SSH, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
read_link(SSH, Name) ->
call(SSH, {read_link,sftp,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec read_link(SSH, Server, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
read_link(SSH, Server, Name) ->
call(SSH, {read_link,Server,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec make_symlink(SSH, Name, Target) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
make_symlink(SSH, Name, Target) ->
call(SSH, {make_symlink,sftp,Name,Target}).
-%%%-----------------------------------------------------------------
-%%% @spec make_symlink(SSH, Server, Name, Target) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
make_symlink(SSH, Server, Name, Target) ->
call(SSH, {make_symlink,Server,Name,Target}).
-%%%-----------------------------------------------------------------
-%%% @spec rename(SSH, OldName, NewName) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
rename(SSH, OldName, NewName) ->
call(SSH, {rename,sftp,OldName,NewName}).
-%%%-----------------------------------------------------------------
-%%% @spec rename(SSH, Server, OldName, NewName) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
rename(SSH, Server, OldName, NewName) ->
call(SSH, {rename,Server,OldName,NewName}).
-%%%-----------------------------------------------------------------
-%%% @spec delete(SSH, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
delete(SSH, Name) ->
call(SSH, {delete,sftp,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec delete(SSH, Server, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
delete(SSH, Server, Name) ->
call(SSH, {delete,Server,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec make_dir(SSH, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
make_dir(SSH, Name) ->
call(SSH, {make_dir,sftp,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec make_dir(SSH, Server, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
make_dir(SSH, Server, Name) ->
call(SSH, {make_dir,Server,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec del_dir(SSH, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
del_dir(SSH, Name) ->
call(SSH, {del_dir,sftp,Name}).
-%%%-----------------------------------------------------------------
-%%% @spec del_dir(SSH, Server, Name) -> Result
-%%% SSH = connection()
-%%% Result = ssh_sftp_return() | {error,Reason}
-%%% Reason = term()
-%%% @doc For info and other types, see ssh_sftp(3).
+
del_dir(SSH, Server, Name) ->
call(SSH, {del_dir,Server,Name}).
@@ -952,7 +413,6 @@ del_dir(SSH, Server, Name) ->
%%% Callback functions
%%%=================================================================
-%% @hidden
init(KeyOrName, {ConnType,Addr,Port}, AllOpts) ->
User = proplists:get_value(user, AllOpts),
Password = case proplists:get_value(password, AllOpts) of
@@ -1002,7 +462,6 @@ init(KeyOrName, {ConnType,Addr,Port}, AllOpts) ->
target=KeyOrName}}
end.
-%% @hidden
handle_msg(sftp_connect, State) ->
#state{ssh_ref=SSHRef, target=Target} = State,
try_log(heading(sftp_connect,Target), "SSH Ref: ~p", [SSHRef]),
@@ -1246,15 +705,12 @@ handle_msg({del_dir,Srv,Name}=Cmd, S=#state{ssh_ref=SSHRef}) ->
[SSHRef,ref(Srv,SSHRef),mod(Cmd)]),
{ssh_sftp:del_dir(ref(Srv,SSHRef), Name),S}.
-%% @hidden
reconnect(_Addr,_State) ->
{error,no_reconnection_of_ssh}.
-%% @hidden
close(SSHRef) ->
disconnect(SSHRef).
-%% @hidden
terminate(SSHRef, State) ->
case State#state.conn_type of
ssh ->
@@ -1271,8 +727,6 @@ terminate(SSHRef, State) ->
%%%=================================================================
%%% Internal functions
-%%%-----------------------------------------------------------------
-%%%
do_recv_response(SSH, Chn, Data, End, Timeout) ->
receive
{ssh_cm, SSH, {open,Chn,RemoteChn,{session}}} ->
@@ -1351,8 +805,6 @@ do_recv_response(SSH, Chn, Data, End, Timeout) ->
end
end.
-%%%-----------------------------------------------------------------
-%%%
get_handle(SSH) when is_pid(SSH) ->
{ok,SSH};
get_handle(SSH) ->
@@ -1365,8 +817,6 @@ get_handle(SSH) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%%
call(SSH, Msg) ->
call(SSH, Msg, infinity).
@@ -1378,29 +828,19 @@ call(SSH, Msg, Timeout) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%%
ref(sftp, SSHRef) -> SSHRef;
ref(Server, _) -> Server.
-%%%-----------------------------------------------------------------
-%%%
mod(Cmd) ->
[Op,_Server|Args] = tuple_to_list(Cmd),
list_to_tuple([Op|Args]).
-%%%-----------------------------------------------------------------
-%%%
heading(Function, Ref) ->
io_lib:format("ct_ssh:~tw ~tp",[Function,Ref]).
-%%%-----------------------------------------------------------------
-%%%
log(Heading, Str, Args) ->
ct_gen_conn:log(Heading, Str, Args).
-%%%-----------------------------------------------------------------
-%%%
try_log(Heading, Str, Args) ->
try_log(Heading, Str, Args, infinity).
@@ -1414,8 +854,6 @@ try_log(Heading, Str, Args, Timeout) ->
ok
end.
-%%%-----------------------------------------------------------------
-%%%
debug(Str) ->
debug(Str, []).
diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl
index b50cddd492..58a29edace 100644
--- a/lib/common_test/src/ct_telnet.erl
+++ b/lib/common_test/src/ct_telnet.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,131 +18,6 @@
%% %CopyrightEnd%
%%
-%% @doc Common Test specific layer on top of telnet client `ct_telnet_client.erl'
-%%
-%% <p>Use this module to set up telnet connections, send commands and
-%% perform string matching on the result.
-%% See the `unix_telnet' manual page for information about how to use
-%% `ct_telnet', and configure connections, specifically for unix hosts.</p>
-%% <p>The following default values are defined in `ct_telnet':</p>
-%% <pre>
-%% Connection timeout = 10 sec (time to wait for connection)
-%% Command timeout = 10 sec (time to wait for a command to return)
-%% Max no of reconnection attempts = 3
-%% Reconnection interval = 5 sek (time to wait in between reconnection attempts)
-%% Keep alive = true (will send NOP to the server every 8 sec if connection is idle)
-%% Polling limit = 0 (max number of times to poll to get a remaining string terminated)
-%% Polling interval = 1 sec (sleep time between polls)</pre>
-%% <p>These parameters can be altered by the user with the following
-%% configuration term:</p>
-%% <pre>
-%% {telnet_settings, [{connect_timeout,Millisec},
-%% {command_timeout,Millisec},
-%% {reconnection_attempts,N},
-%% {reconnection_interval,Millisec},
-%% {keep_alive,Bool},
-%% {poll_limit,N},
-%% {poll_interval,Millisec},
-%% {tcp_nodelay,Bool}]}.</pre>
-%% <p><code>Millisec = integer(), N = integer()</code></p>
-%% <p>Enter the <code>telnet_settings</code> term in a configuration
-%% file included in the test and ct_telnet will retrieve the information
-%% automatically. Note that `keep_alive' may be specified per connection if
-%% required. See `unix_telnet' for details.</p>
-%%
-%% == Logging ==
-%%
-%% The default logging behaviour of `ct_telnet' is to print information
-%% to the test case HTML log about performed operations and commands
-%% and their corresponding results. What won't be printed to the HTML log
-%% are text strings sent from the telnet server that are not explicitly
-%% received by means of a `ct_telnet' function such as `expect/3'.
-%% `ct_telnet' may however be configured to use a special purpose event handler,
-%% implemented in `ct_conn_log_h', for logging <b>all</b> telnet traffic.
-%% To use this handler, you need to install a Common Test hook named
-%% `cth_conn_log'. Example (using the test suite info function):
-%%
-%% ```
-%% suite() ->
-%% [{ct_hooks, [{cth_conn_log, [{conn_mod(),hook_options()}]}]}].
-%% '''
-%%
-%% `conn_mod()' is the name of the common_test module implementing
-%% the connection protocol, i.e. `ct_telnet'.
-%%
-%% The `cth_conn_log' hook performs unformatted logging of telnet data to
-%% a separate text file. All telnet communication is captured and printed,
-%% including arbitrary data sent from the server. The link to this text file
-%% can be found on the top of the test case HTML log.
-%%
-%% By default, data for all telnet connections is logged in one common
-%% file (named `default'), which might get messy e.g. if multiple telnet
-%% sessions are running in parallel. It is therefore possible to create a
-%% separate log file for each connection. To configure this, use the hook
-%% option `hosts' and list the names of the servers/connections that will be
-%% used in the suite. Note that the connections must be named for this to work
-%% (see the `open' function below).
-%%
-%% The hook option named `log_type' may be used to change the `cth_conn_log'
-%% behaviour. The default value of this option is `raw', which results in the
-%% behaviour described above. If the value is set to `html', all telnet
-%% communication is printed to the test case HTML log instead.
-%%
-%% All `cth_conn_log' hook options described above can also be specified in
-%% a configuration file with the configuration variable `ct_conn_log'. Example:
-%%
-%% ```
-%% {ct_conn_log, [{ct_telnet,[{log_type,raw},
-%% {hosts,[key_or_name()]}]}]}
-%% '''
-%%
-%% <b>Note</b> that hook options specified in a configuration file
-%% will overwrite any hardcoded hook options in the test suite!
-%%
-%% === Logging example ===
-%%
-%% The following `ct_hooks' statement will cause printing of telnet traffic
-%% to separate logs for the connections named `server1' and `server2'.
-%% Traffic for any other connections will be logged in the default telnet log.
-%%
-%% ```
-%% suite() ->
-%% [{ct_hooks,
-%% [{cth_conn_log, [{ct_telnet,[{hosts,[server1,server2]}]}]}]}].
-%%'''
-%%
-%% As previously explained, the above specification could also be provided
-%% by means of an entry like this in a configuration file:
-%%
-%% ```
-%% {ct_conn_log, [{ct_telnet,[{hosts,[server1,server2]}]}]}.
-%% '''
-%%
-%% in which case the `ct_hooks' statement in the test suite may simply look
-%% like this:
-%%
-%% ```
-%% suite() ->
-%% [{ct_hooks, [{cth_conn_log, []}]}].
-%% '''
-%%
-%% @end
-
-%% @type connection_type() = telnet | ts1 | ts2
-
-%% @type connection() = handle() |
-%% {ct:target_name(),connection_type()} | ct:target_name()
-
-%% @type handle() = ct_gen_conn:handle(). Handle for a
-%% specific telnet connection.
-
-%% @type prompt_regexp() = string(). A regular expression which
-%% matches all possible prompts for a specific type of target. The
-%% regexp must not have any groups i.e. when matching, re:run/3 shall
-%% return a list with one single element.
-%%
-%% @see unix_telnet
-
-module(ct_telnet).
-export([open/1, open/2, open/3, open/4, close/1]).
@@ -186,20 +61,9 @@
reconn_int=?RECONN_TIMEOUT,
tcp_nodelay=false}).
-%%%-----------------------------------------------------------------
-%%% @spec open(Name) -> {ok,Handle} | {error,Reason}
-%%% @equiv open(Name,telnet)
open(Name) ->
open(Name,telnet).
-%%%-----------------------------------------------------------------
-%%% @spec open(Name,ConnType) -> {ok,Handle} | {error,Reason}
-%%% Name = target_name()
-%%% ConnType = ct_telnet:connection_type()
-%%% Handle = ct_telnet:handle()
-%%% Reason = term()
-%%%
-%%% @doc Open a telnet connection to the specified target host.
open(Name,ConnType) ->
case ct_util:get_key_from_name(Name) of
{ok, unix} -> % unix host
@@ -210,44 +74,9 @@ open(Name,ConnType) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @spec open(KeyOrName,ConnType,TargetMod) ->
-%%% {ok,Handle} | {error,Reason}
-%%% @equiv open(KeyOrName,ConnType,TargetMod,[])
open(KeyOrName,ConnType,TargetMod) ->
open(KeyOrName,ConnType,TargetMod,KeyOrName).
-%%%-----------------------------------------------------------------
-%%% @spec open(KeyOrName,ConnType,TargetMod,Extra) ->
-%%% {ok,Handle} | {error,Reason}
-%%% KeyOrName = Key | Name
-%%% Key = atom()
-%%% Name = ct:target_name()
-%%% ConnType = connection_type()
-%%% TargetMod = atom()
-%%% Extra = term()
-%%% Handle = handle()
-%%% Reason = term()
-%%%
-%%% @doc Open a telnet connection to the specified target host.
-%%%
-%%% <p>The target data must exist in a configuration file. The connection
-%%% may be associated with either <code>Name</code> and/or the returned
-%%% <code>Handle</code>. To allocate a name for the target,
-%%% use <code>ct:require/2</code> in a test case, or use a
-%%% <code>require</code> statement in the suite info function
-%%% (<code>suite/0</code>), or in a test case info function.
-%%% If you want the connection to be associated with <code>Handle</code> only
-%%% (in case you need to open multiple connections to a host for example),
-%%% simply use <code>Key</code>, the configuration variable name, to
-%%% specify the target. Note that a connection that has no associated target
-%%% name can only be closed with the handle value.</p>
-%%%
-%%% <p><code>TargetMod</code> is a module which exports the functions
-%%% <code>connect(Ip,Port,KeepAlive,Extra)</code> and <code>get_prompt_regexp()</code>
-%%% for the given <code>TargetType</code> (e.g. <code>unix_telnet</code>).</p>
-%%%
-%%% @see ct:require/2
open(KeyOrName,ConnType,TargetMod,Extra) ->
case ct:get_config({KeyOrName,ConnType}) of
undefined ->
@@ -287,17 +116,6 @@ open(KeyOrName,ConnType,TargetMod,Extra) ->
{old,true}])
end.
-%%%-----------------------------------------------------------------
-%%% @spec close(Connection) -> ok | {error,Reason}
-%%% Connection = ct_telnet:connection()
-%%% Reason = term()
-%%%
-%%% @doc Close the telnet connection and stop the process managing it.
-%%%
-%%% <p>A connection may be associated with a target name and/or a handle.
-%%% If <code>Connection</code> has no associated target name, it may only
-%%% be closed with the handle value (see the <code>open/4</code>
-%%% function).</p>
close(Connection) ->
case get_handle(Connection) of
{ok,Pid} ->
@@ -315,30 +133,10 @@ close(Connection) ->
%%%=================================================================
%%% Test suite interface
%%%-----------------------------------------------------------------
-%%% @spec cmd(Connection,Cmd) -> {ok,Data} | {error,Reason}
-%%% @equiv cmd(Connection,Cmd,[])
+
cmd(Connection,Cmd) ->
cmd(Connection,Cmd,[]).
-%%%-----------------------------------------------------------------
-%%% @spec cmd(Connection,Cmd,Opts) -> {ok,Data} | {error,Reason}
-%%% Connection = ct_telnet:connection()
-%%% Cmd = string()
-%%% Opts = [Opt]
-%%% Opt = {timeout,timeout()} | {newline,boolean()}
-%%% Data = [string()]
-%%% Reason = term()
-%%% @doc Send a command via telnet and wait for prompt.
-%%%
-%%% <p>This function will by default add a newline to the end of the
-%%% given command. If this is not desired, the option
-%%% `{newline,false}' can be used. This is necessary, for example,
-%%% when sending telnet command sequences (prefixed with the
-%%% Interprete As Command, IAC, character).</p>
-%%%
-%%% <p>The option `timeout' specifies how long the client shall wait for
-%%% prompt. If the time expires, the function returns
-%%% `{error,timeout}'. See the module description for information
-%%% about the default value for the command timeout.</p>
+
cmd(Connection,Cmd,Opts) when is_list(Opts) ->
case check_cmd_opts(Opts) of
ok ->
@@ -363,42 +161,13 @@ check_cmd_opts([]) ->
check_cmd_opts(Opts) ->
check_send_opts(Opts).
-%%%-----------------------------------------------------------------
-%%% @spec cmdf(Connection,CmdFormat,Args) -> {ok,Data} | {error,Reason}
-%%% @equiv cmdf(Connection,CmdFormat,Args,[])
cmdf(Connection,CmdFormat,Args) ->
cmdf(Connection,CmdFormat,Args,[]).
-%%%-----------------------------------------------------------------
-%%% @spec cmdf(Connection,CmdFormat,Args,Opts) -> {ok,Data} | {error,Reason}
-%%% Connection = ct_telnet:connection()
-%%% CmdFormat = string()
-%%% Args = list()
-%%% Opts = [Opt]
-%%% Opt = {timeout,timeout()} | {newline,boolean()}
-%%% Data = [string()]
-%%% Reason = term()
-%%% @doc Send a telnet command and wait for prompt
-%%% (uses a format string and list of arguments to build the command).
-%%%
-%%% <p>See {@link cmd/3} further description.</p>
+
cmdf(Connection,CmdFormat,Args,Opts) when is_list(Args) ->
Cmd = lists:flatten(io_lib:format(CmdFormat,Args)),
cmd(Connection,Cmd,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec get_data(Connection) -> {ok,Data} | {error,Reason}
-%%% Connection = ct_telnet:connection()
-%%% Data = [string()]
-%%% Reason = term()
-%%% @doc Get all data that has been received by the telnet client
-%%% since the last command was sent. Note that only newline terminated
-%%% strings are returned. If the last string received has not yet
-%%% been terminated, the connection may be polled automatically until
-%%% the string is complete. The polling feature is controlled
-%%% by the `poll_limit' and `poll_interval' config values and is
-%%% by default disabled (meaning the function will immediately
-%%% return all complete strings received and save a remaining
-%%% non-terminated string for a later `get_data' call).
get_data(Connection) ->
case get_handle(Connection) of
{ok,Pid} ->
@@ -407,29 +176,9 @@ get_data(Connection) ->
Error
end.
-%%%-----------------------------------------------------------------
-%%% @spec send(Connection,Cmd) -> ok | {error,Reason}
-%%% @equiv send(Connection,Cmd,[])
send(Connection,Cmd) ->
send(Connection,Cmd,[]).
-%%%-----------------------------------------------------------------
-%%% @spec send(Connection,Cmd,Opts) -> ok | {error,Reason}
-%%% Connection = ct_telnet:connection()
-%%% Cmd = string()
-%%% Opts = [Opt]
-%%% Opt = {newline,boolean()}
-%%% Reason = term()
-%%% @doc Send a telnet command and return immediately.
-%%%
-%%% This function will by default add a newline to the end of the
-%%% given command. If this is not desired, the option
-%%% `{newline,false}' can be used. This is necessary, for example,
-%%% when sending telnet command sequences (prefixed with the
-%%% Interprete As Command, IAC, character).
-%%%
-%%% <p>The resulting output from the command can be read with
-%%% <code>get_data/1</code> or <code>expect/2/3</code>.</p>
send(Connection,Cmd,Opts) ->
case check_send_opts(Opts) of
ok ->
@@ -450,142 +199,16 @@ check_send_opts([Invalid|_]) ->
check_send_opts([]) ->
ok.
-
-%%%-----------------------------------------------------------------
-%%% @spec sendf(Connection,CmdFormat,Args) -> ok | {error,Reason}
-%%% @equiv sendf(Connection,CmdFormat,Args,[])
sendf(Connection,CmdFormat,Args) when is_list(Args) ->
sendf(Connection,CmdFormat,Args,[]).
-%%%-----------------------------------------------------------------
-%%% @spec sendf(Connection,CmdFormat,Args,Opts) -> ok | {error,Reason}
-%%% Connection = ct_telnet:connection()
-%%% CmdFormat = string()
-%%% Args = list()
-%%% Opts = [Opt]
-%%% Opt = {newline,boolean()}
-%%% Reason = term()
-%%% @doc Send a telnet command and return immediately (uses a format
-%%% string and a list of arguments to build the command).
sendf(Connection,CmdFormat,Args,Opts) when is_list(Args) ->
Cmd = lists:flatten(io_lib:format(CmdFormat,Args)),
send(Connection,Cmd,Opts).
-%%%-----------------------------------------------------------------
-%%% @spec expect(Connection,Patterns) -> term()
-%%% @equiv expect(Connections,Patterns,[])
expect(Connection,Patterns) ->
expect(Connection,Patterns,[]).
-%%%-----------------------------------------------------------------
-%%% @spec expect(Connection,Patterns,Opts) -> {ok,Match} |
-%%% {ok,MatchList,HaltReason} |
-%%% {error,Reason}
-%%% Connection = ct_telnet:connection()
-%%% Patterns = Pattern | [Pattern]
-%%% Pattern = string() | {Tag,string()} | prompt | {prompt,Prompt}
-%%% Prompt = string()
-%%% Tag = term()
-%%% Opts = [Opt]
-%%% Opt = {idle_timeout,IdleTimeout} | {total_timeout,TotalTimeout} |
-%%% repeat | {repeat,N} | sequence | {halt,HaltPatterns} |
-%%% ignore_prompt | no_prompt_check | wait_for_prompt |
-%%% {wait_for_prompt,Prompt}
-%%% IdleTimeout = infinity | integer()
-%%% TotalTimeout = infinity | integer()
-%%% N = integer()
-%%% HaltPatterns = Patterns
-%%% MatchList = [Match]
-%%% Match = RxMatch | {Tag,RxMatch} | {prompt,Prompt}
-%%% RxMatch = [string()]
-%%% HaltReason = done | Match
-%%% Reason = timeout | {prompt,Prompt}
-%%%
-%%% @doc Get data from telnet and wait for the expected pattern.
-%%%
-%%% <p><code>Pattern</code> can be a POSIX regular expression. The function
-%%% returns as soon as a pattern has been successfully matched (at least one,
-%%% in the case of multiple patterns).</p>
-%%%
-%%% <p><code>RxMatch</code> is a list of matched strings. It looks
-%%% like this: <code>[FullMatch, SubMatch1, SubMatch2, ...]</code>
-%%% where <code>FullMatch</code> is the string matched by the whole
-%%% regular expression and <code>SubMatchN</code> is the string that
-%%% matched subexpression no <code>N</code>. Subexpressions are
-%%% denoted with '(' ')' in the regular expression</p>
-%%%
-%%% <p>If a <code>Tag</code> is given, the returned <code>Match</code>
-%%% will also include the matched <code>Tag</code>. Else, only
-%%% <code>RxMatch</code> is returned.</p>
-%%%
-%%% <p>The <code>idle_timeout</code> option indicates that the function
-%%% shall return if the telnet client is idle (i.e. if no data is
-%%% received) for more than <code>IdleTimeout</code> milliseconds. Default
-%%% timeout is 10 seconds.</p>
-%%%
-%%% <p>The <code>total_timeout</code> option sets a time limit for
-%%% the complete expect operation. After <code>TotalTimeout</code>
-%%% milliseconds, <code>{error,timeout}</code> is returned. The default
-%%% value is <code>infinity</code> (i.e. no time limit).</p>
-%%%
-%%% <p>The function will return when a prompt is received, even if no
-%%% pattern has yet been matched. In this event,
-%%% <code>{error,{prompt,Prompt}}</code> is returned.
-%%% However, this behaviour may be modified with the
-%%% <code>ignore_prompt</code> or <code>no_prompt_check</code> option, which
-%%% tells <code>expect</code> to return only when a match is found or after a
-%%% timeout.</p>
-%%%
-%%% <p>If the <code>ignore_prompt</code> option is used,
-%%% <code>ct_telnet</code> will ignore any prompt found. This option
-%%% is useful if data sent by the server could include a pattern that
-%%% would match the prompt regexp (as returned by
-%%% <code>TargedMod:get_prompt_regexp/0</code>), but which should not
-%%% cause the function to return.</p>
-%%%
-%%% <p>If the <code>no_prompt_check</code> option is used,
-%%% <code>ct_telnet</code> will not search for a prompt at all. This
-%%% is useful if, for instance, the <code>Pattern</code> itself
-%%% matches the prompt.</p>
-%%%
-%%% <p>The <code>wait_for_prompt</code> option forces <code>ct_telnet</code>
-%%% to wait until the prompt string has been received before returning
-%%% (even if a pattern has already been matched). This is equal to calling:
-%%% <code>expect(Conn, Patterns++[{prompt,Prompt}], [sequence|Opts])</code>.
-%%% Note that <code>idle_timeout</code> and <code>total_timeout</code>
-%%% may abort the operation of waiting for prompt.</p>
-%%%
-%%% <p>The <code>repeat</code> option indicates that the pattern(s)
-%%% shall be matched multiple times. If <code>N</code> is given, the
-%%% pattern(s) will be matched <code>N</code> times, and the function
-%%% will return with <code>HaltReason = done</code>.</p>
-%%%
-%%% <p>The <code>sequence</code> option indicates that all patterns
-%%% shall be matched in a sequence. A match will not be concluded
-%%% untill all patterns are matched.</p>
-%%%
-%%% <p>Both <code>repeat</code> and <code>sequence</code> can be
-%%% interrupted by one or more <code>HaltPatterns</code>. When
-%%% <code>sequence</code> or <code>repeat</code> is used, there will
-%%% always be a <code>MatchList</code> returned, i.e. a list of
-%%% <code>Match</code> instead of only one <code>Match</code>. There
-%%% will also be a <code>HaltReason</code> returned.</p>
-%%%
-%%% <p><underline>Examples:</underline><br/>
-%%% <code>expect(Connection,[{abc,"ABC"},{xyz,"XYZ"}],</code>
-%%% <code>[sequence,{halt,[{nnn,"NNN"}]}]).</code><br/> will try to match
-%%% "ABC" first and then "XYZ", but if "NNN" appears the function will
-%%% return <code>{error,{nnn,["NNN"]}}</code>. If both "ABC" and "XYZ"
-%%% are matched, the function will return
-%%% <code>{ok,[AbcMatch,XyzMatch]}</code>.</p>
-%%%
-%%% <p><code>expect(Connection,[{abc,"ABC"},{xyz,"XYZ"}],</code>
-%%% <code>[{repeat,2},{halt,[{nnn,"NNN"}]}]).</code><br/> will try to match
-%%% "ABC" or "XYZ" twice. If "NNN" appears the function will return
-%%% with <code>HaltReason = {nnn,["NNN"]}</code>.</p>
-%%%
-%%% <p>The <code>repeat</code> and <code>sequence</code> options can be
-%%% combined in order to match a sequence multiple times.</p>
expect(Connection,Patterns,Opts) ->
case get_handle(Connection) of
{ok,Pid} ->
@@ -596,7 +219,7 @@ expect(Connection,Patterns,Opts) ->
%%%=================================================================
%%% Callback functions
-%% @hidden
+
init(Name,{Ip,Port,Type},{TargetMod,KeepAlive,Extra}) ->
S0 = case ct:get_config(telnet_settings) of
undefined ->
@@ -677,7 +300,6 @@ set_telnet_defaults([Unknown|Ss],S) ->
set_telnet_defaults([],S) ->
S.
-%% @hidden
handle_msg({cmd,Cmd,Opts},State) ->
start_gen_log(heading(cmd,State#state.name)),
log(State,cmd,"Cmd: ~tp",[Cmd]),
@@ -803,7 +425,6 @@ handle_msg({expect,Pattern,Opts},State) ->
{Return1,State#state{buffer=NewBuffer,prompt=Prompt}}.
-%% @hidden
reconnect({Ip,Port,_Type},State) ->
reconnect(Ip,Port,State#state.reconns,State).
reconnect(Ip,Port,N,State=#state{name=Name,
@@ -834,7 +455,6 @@ reconnect(Ip,Port,N,State=#state{name=Name,
end.
-%% @hidden
terminate(TelnPid,State) ->
Result = ct_telnet_client:close(TelnPid),
log(State,close,"Telnet connection for ~w closed.",[TelnPid]),
@@ -902,7 +522,6 @@ force_log(State,Action,String,Args) ->
log(State,Action,String,Args,true).
%%%-----------------------------------------------------------------
-%%% @hidden
log(State,Action,String,Args) when is_record(State, state) ->
log(State,Action,String,Args,false);
log(Name,Action,String,Args) when is_atom(Name) ->
@@ -911,7 +530,6 @@ log(TelnPid,Action,String,Args) when is_pid(TelnPid) ->
log(#state{teln_pid=TelnPid},Action,String,Args,false).
%%%-----------------------------------------------------------------
-%%% @hidden
log(undefined,String,Args) ->
log(#state{},undefined,String,Args,false);
log(Name,String,Args) when is_atom(Name) ->
@@ -920,7 +538,6 @@ log(TelnPid,String,Args) when is_pid(TelnPid) ->
log(#state{teln_pid=TelnPid},undefined,String,Args).
%%%-----------------------------------------------------------------
-%%% @hidden
log(#state{name=Name,teln_pid=TelnPid,host=Host,port=Port},
Action,String,Args,ForcePrint) ->
Name1 = if Name == undefined -> get({ct_telnet_pid2name,TelnPid});
@@ -971,7 +588,6 @@ log(#state{name=Name,teln_pid=TelnPid,host=Host,port=Port},
end.
%%%-----------------------------------------------------------------
-%%% @hidden
start_gen_log(Heading) ->
%% check if output is suppressed
case ct_util:is_silenced(telnet) of
@@ -980,7 +596,6 @@ start_gen_log(Heading) ->
end.
%%%-----------------------------------------------------------------
-%%% @hidden
end_gen_log() ->
%% check if output is suppressed
case ct_util:is_silenced(telnet) of
@@ -988,7 +603,6 @@ end_gen_log() ->
false -> ct_gen_conn:end_log()
end.
-%%% @hidden
%% Debug printouts.
debug_cont_gen_log(Str,Args) ->
Old = put(silent,true),
@@ -1038,8 +652,7 @@ teln_get_all_data(State=#state{teln_pid=Pid,prx=Prx},Data,Acc,LastLine,Polls) ->
found_prompt=false,
prompt_check=true}).
-%% @hidden
-%% @doc Externally the silent_teln_expect function shall only be used
+%% Externally the silent_teln_expect function shall only be used
%% by the TargetModule, i.e. the target specific module which
%% implements connect/2 and get_prompt_regexp/0.
silent_teln_expect(Name,Pid,Data,Pattern,Prx,Opts) ->
@@ -1057,9 +670,9 @@ silent_teln_expect(Name,Pid,Data,Pattern,Prx,Opts) ->
%% 2) Sequence: Several patterns are given, and they are matched in
%% the order they appear in the pattern list.
%% 3a) Repeat (single): 1) is repeated either N times or until a halt
-%% condition is fullfilled.
+%% condition is fulfilled.
%% 3b) Repeat (sequence): 2) is repeated either N times or until a
-%% halt condition is fullfilled.
+%% halt condition is fulfilled.
teln_expect(Name,Pid,Data,Pattern0,Prx,Opts) ->
HaltPatterns =
case get_ignore_prompt(Opts) of
@@ -1203,7 +816,7 @@ wait_for_prompt2(Prompt, Pattern, Opts) ->
{true,Pattern1,Opts1}.
%% Repeat either single or sequence. All match results are accumulated
-%% and returned when a halt condition is fulllfilled.
+%% and returned when a halt condition is fulfilled.
repeat_expect(_Name,_Pid,Rest,_Pattern,Acc,#eo{repeat=0}) ->
{ok,lists:reverse(Acc),done,Rest};
repeat_expect(Name,Pid,Data,Pattern,Acc,EO) ->
@@ -1342,7 +955,7 @@ one_expect1(Name,Pid,Data,Pattern,Rest,EO) ->
%% 2) Sequence.
%% First the whole data chunk is searched for a prompt (to avoid doing
%% a regexp match for the prompt at each line).
-%% If we are searching for anyting else, the datachunk is split into
+%% If we are searching for anything else, the datachunk is split into
%% lines and each line is matched against the first pattern in the list.
%% When a match is found, the match result is accumulated, and we keep
%% searching for the next pattern in the list.
@@ -1472,7 +1085,7 @@ match_line(Name,Pid,Line,[Pattern|Patterns],FoundPrompt,Term,EO,RetTag) ->
end;
match_line(Name,Pid,Line,[],FoundPrompt,Term,EO,match) ->
match_line(Name,Pid,Line,EO#eo.haltpatterns,FoundPrompt,Term,EO,halt);
-%% print any terminated line that can not be matched
+%% print any terminated line that cannot be matched
match_line(Name,Pid,Line,[],_FoundPrompt,true,_EO,halt) ->
log(name_or_pid(Name,Pid)," ~ts",[Line]),
nomatch;
@@ -1530,8 +1143,6 @@ add_tabs([],[$\n|Acc],LastLine) ->
add_tabs([],[],LastLine) ->
{[],lists:reverse(LastLine)}.
-
-%%% @hidden
teln_receive_until_prompt(Pid,Prx,Timeout) ->
Fun = fun() -> teln_receive_until_prompt(Pid,Prx,[],[]) end,
ct_gen_conn:do_within_time(Fun, Timeout).
diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl
index bd3755722f..2c18caf18f 100644
--- a/lib/common_test/src/ct_testspec.erl
+++ b/lib/common_test/src/ct_testspec.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,10 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework functions handling test specifications.
-%%%
-%%% <p>This module exports functions that are used within CT to
-%%% scan and parse test specifikations.</p>
-module(ct_testspec).
-export([prepare_tests/1, prepare_tests/2,
diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl
index e904bb1e7c..9f489e9bfb 100644
--- a/lib/common_test/src/ct_util.erl
+++ b/lib/common_test/src/ct_util.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,11 +18,11 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework Utilities.
+%%% Common Test Framework Utilities.
%%%
-%%% <p>This is a support module for the Common Test Framework. It
+%%% This is a support module for the Common Test Framework. It
%%% implements the process ct_util_server which acts like a data
-%%% holder for suite, configuration and connection data.</p>
+%%% holder for suite, configuration and connection data.
%%%
-module(ct_util).
@@ -83,20 +83,20 @@
%%%-----------------------------------------------------------------
start() ->
start(normal, ".", ?default_verbosity).
-%%% @spec start(Mode) -> Pid | exit(Error)
+%%% -spec start(Mode) -> Pid | exit(Error)
%%% Mode = normal | interactive
%%% Pid = pid()
%%%
-%%% @doc Start start the ct_util_server process
+%%% Start start the ct_util_server process
%%% (tool-internal use only).
%%%
-%%% <p>This function is called from ct_run.erl. It starts and initiates
-%%% the <code>ct_util_server</code></p>
+%%% This function is called from ct_run.erl. It starts and initiates
+%%% the ct_util_server
%%%
-%%% <p>Returns the process identity of the
-%%% <code>ct_util_server</code>.</p>
+%%% Returns the process identity of the
+%%% ct_util_server.
%%%
-%%% @see ct
+%%% See ct.
start(LogDir) when is_list(LogDir) ->
start(normal, LogDir, ?default_verbosity);
start(Mode) ->
@@ -192,7 +192,10 @@ do_start(Parent, Mode, LogDir, Verbosity) ->
ok
end,
- ct_default_gl:start_link(group_leader()),
+ case ct_default_gl:start_link(group_leader()) of
+ {ok, _} -> ok;
+ ignore -> ok
+ end,
{StartTime,TestLogDir} = ct_logs:init(Mode, Verbosity),
@@ -520,19 +523,19 @@ get_key_from_name(Name)->
ct_config:get_key_from_name(Name).
%%%-----------------------------------------------------------------
-%%% @spec register_connection(TargetName,Address,Callback,Handle) ->
+%%% -spec register_connection(TargetName,Address,Callback,Handle) ->
%%% ok | {error,Reason}
%%% TargetName = ct:target_name()
%%% Address = term()
%%% Callback = atom()
%%% Handle = term
%%%
-%%% @doc Register a new connection (tool-internal use only).
+%%% Register a new connection (tool-internal use only).
%%%
-%%% <p>This function can be called when a new connection is
+%%% This function can be called when a new connection is
%%% established. The connection data is stored in the connection
%%% table, and ct_util will close all registered connections when the
-%%% test is finished by calling <code>Callback:close/1</code>.</p>
+%%% test is finished by calling Callback:close/1.
register_connection(TargetName,Address,Callback,Handle) ->
%% If TargetName is a registered alias for a config
%% variable, use it as reference for the connection,
@@ -553,28 +556,28 @@ register_connection(TargetName,Address,Callback,Handle) ->
ok.
%%%-----------------------------------------------------------------
-%%% @spec unregister_connection(Handle) -> ok
+%%% -spec unregister_connection(Handle) -> ok
%%% Handle = term
%%%
-%%% @doc Unregister a connection (tool-internal use only).
+%%% Unregister a connection (tool-internal use only).
%%%
-%%% <p>This function should be called when a registered connection is
+%%% This function should be called when a registered connection is
%%% closed. It removes the connection data from the connection
-%%% table.</p>
+%%% table.
unregister_connection(Handle) ->
ets:delete(?conn_table,Handle),
ok.
%%%-----------------------------------------------------------------
-%%% @spec does_connection_exist(TargetName,Address,Callback) ->
+%%% -spec does_connection_exist(TargetName,Address,Callback) ->
%%% {ok,Handle} | false
%%% TargetName = ct:target_name()
%%% Address = address
%%% Callback = atom()
%%% Handle = term()
%%%
-%%% @doc Check if a connection already exists.
+%%% Check if a connection already exists.
does_connection_exist(TargetName,Address,Callback) ->
case ct_config:get_key_from_name(TargetName) of
{ok,_Key} ->
@@ -594,7 +597,7 @@ does_connection_exist(TargetName,Address,Callback) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec get_connection(TargetName,Callback) ->
+%%% -spec get_connection(TargetName,Callback) ->
%%% {ok,Connection} | {error,Reason}
%%% TargetName = ct:target_name()
%%% Callback = atom()
@@ -602,8 +605,8 @@ does_connection_exist(TargetName,Address,Callback) ->
%%% Handle = term()
%%% Address = term()
%%%
-%%% @doc Return the connection for <code>Callback</code> on the
-%%% given target (<code>TargetName</code>).
+%%% Return the connection for Callback on the
+%%% given target (TargetName).
get_connection(TargetName,Callback) ->
%% check that TargetName is a registered alias
case ct_config:get_key_from_name(TargetName) of
@@ -624,7 +627,7 @@ get_connection(TargetName,Callback) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec get_connections(ConnPid) ->
+%%% -spec get_connections(ConnPid) ->
%%% {ok,Connections} | {error,Reason}
%%% Connections = [Connection]
%%% Connection = {TargetName,Handle,Callback,Address}
@@ -633,8 +636,8 @@ get_connection(TargetName,Callback) ->
%%% Callback = atom()
%%% Address = term()
%%%
-%%% @doc Get data for all connections associated with a particular
-%%% connection pid (see Callback:init/3).
+%%% Get data for all connections associated with a particular
+%%% connection pid (see Callback:init/3).
get_connections(ConnPid) ->
Conns = ets:tab2list(?conn_table),
lists:flatmap(fun(#conn{targetref=TargetName,
@@ -654,8 +657,7 @@ get_connections(ConnPid) ->
end, Conns).
%%%-----------------------------------------------------------------
-%%% @hidden
-%%% @equiv ct:get_target_name/1
+%%% Equivalent to ct:get_target_name/1
get_target_name(Handle) ->
case ets:select(?conn_table,[{#conn{handle=Handle,targetref='$1',_='_'},
[],
@@ -667,17 +669,14 @@ get_target_name(Handle) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec close_connections() -> ok
+%%% -spec close_connections() -> ok
%%%
-%%% @doc Close all open connections.
+%%% Close all open connections.
close_connections() ->
close_connections(ets:tab2list(?conn_table)),
ok.
%%%-----------------------------------------------------------------
-%%% @spec
-%%%
-%%% @doc
override_silence_all_connections() ->
Protocols = [telnet,ftp,rpc,snmp,ssh],
override_silence_connections(Protocols),
@@ -738,12 +737,12 @@ reset_silent_connections() ->
%%%-----------------------------------------------------------------
-%%% @spec stop(Info) -> ok
+%%% -spec stop(Info) -> ok
%%%
-%%% @doc Stop the ct_util_server and close all existing connections
+%%% Stop the ct_util_server and close all existing connections
%%% (tool-internal use only).
%%%
-%%% @see ct
+%%% See ct.
stop(Info) ->
case whereis(ct_util_server) of
undefined ->
@@ -757,26 +756,25 @@ stop(Info) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec update_last_run_index() -> ok
+%%% -spec update_last_run_index() -> ok
%%%
-%%% @doc Update <code>ct_run.&lt;timestamp&gt;/index.html</code>
+%%% Update ct_run.<timestamp>/index.html
%%% (tool-internal use only).
update_last_run_index() ->
call(update_last_run_index).
%%%-----------------------------------------------------------------
-%%% @spec get_mode() -> Mode
+%%% -spec get_mode() -> Mode
%%% Mode = normal | interactive
%%%
-%%% @doc Return the current mode of the ct_util_server
+%%% Return the current mode of the ct_util_server
%%% (tool-internal use only).
get_mode() ->
call(get_mode).
%%%-----------------------------------------------------------------
-%%% @hidden
-%%% @equiv ct:listenv/1
+%%% Equivalent to ct:listenv/1
listenv(Telnet) ->
case ct_telnet:send(Telnet,"listenv") of
ok ->
@@ -790,8 +788,7 @@ listenv(Telnet) ->
end.
%%%-----------------------------------------------------------------
-%%% @hidden
-%%% @equiv ct:parse_table/1
+%%% Equivalent to ct:parse_table/1
parse_table(Data) ->
{Heading, Rest} = get_headings(Data),
Lines = parse_row(Rest,[],size(Heading)),
@@ -831,16 +828,10 @@ remove_space([],Acc) ->
%%%-----------------------------------------------------------------
-%%% @spec
-%%%
-%%% @doc
is_test_dir(Dir) ->
lists:last(string:lexemes(filename:basename(Dir), "_")) == "test".
%%%-----------------------------------------------------------------
-%%% @spec
-%%%
-%%% @doc
get_testdir(Dir, all) ->
Abs = abs_name(Dir),
case is_test_dir(Abs) of
@@ -884,9 +875,6 @@ get_testdir(Dir, _) ->
get_testdir(Dir, all).
%%%-----------------------------------------------------------------
-%%% @spec
-%%%
-%%% @doc
get_attached(TCPid) ->
case dbg_iserver:safe_call({get_attpid,TCPid}) of
{ok,AttPid} when is_pid(AttPid) ->
@@ -896,9 +884,6 @@ get_attached(TCPid) ->
end.
%%%-----------------------------------------------------------------
-%%% @spec
-%%%
-%%% @doc
kill_attached(undefined,_AttPid) ->
ok;
kill_attached(_TCPid,undefined) ->
@@ -913,9 +898,6 @@ kill_attached(TCPid,AttPid) ->
%%%-----------------------------------------------------------------
-%%% @spec
-%%%
-%%% @doc
warn_duplicates(Suites) ->
Warn =
fun(Mod) ->
@@ -934,9 +916,6 @@ warn_duplicates(Suites) ->
ok.
%%%-----------------------------------------------------------------
-%%% @spec
-%%%
-%%% @doc
mark_process() ->
mark_process(system).
@@ -998,9 +977,6 @@ remaining_test_procs() ->
{TestProcs, SharedGL, OtherGLs}.
%%%-----------------------------------------------------------------
-%%% @spec
-%%%
-%%% @doc
get_profile_data() ->
get_profile_data(all).
diff --git a/lib/common_test/src/ct_webtool.erl b/lib/common_test/src/ct_webtool.erl
index c7174b13f5..32d4255217 100644
--- a/lib/common_test/src/ct_webtool.erl
+++ b/lib/common_test/src/ct_webtool.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/src/ct_webtool_sup.erl b/lib/common_test/src/ct_webtool_sup.erl
index 6c6dbde0a6..04fbbf8745 100644
--- a/lib/common_test/src/ct_webtool_sup.erl
+++ b/lib/common_test/src/ct_webtool_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/src/cth_log_redirect.erl b/lib/common_test/src/cth_log_redirect.erl
index 417ea615a3..86081369b9 100644
--- a/lib/common_test/src/cth_log_redirect.erl
+++ b/lib/common_test/src/cth_log_redirect.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,11 +19,9 @@
%%
-module(cth_log_redirect).
-%%% @doc Common Test Framework functions handling test specifications.
+%%% Common Test Framework functions handling test specifications.
%%%
-%%% <p>This module redirects sasl and error logger info to common test log.</p>
-%%% @end
-
+%%% This module redirects sasl and error logger info to common test log.
%% CTH Callbacks
-export([id/1, init/2,
@@ -126,7 +124,8 @@ start_log_handler() ->
shutdown=>2000,
type=>worker,
modules=>[?MODULE]},
- {ok,_} = supervisor:start_child(logger_sup,ChildSpec);
+ {ok,_} = supervisor:start_child(logger_sup,ChildSpec),
+ ok;
_Pid ->
ok
end,
@@ -138,7 +137,7 @@ start_log_handler() ->
init([]) ->
{ok, #eh_state{log_func = tc_log_async}}.
-log(#{msg:={report,Msg},meta:=#{domain:=[beam,erlang,otp,sasl]}}=Log,Config) ->
+log(#{msg:={report,Msg},meta:=#{domain:=[otp,sasl]}}=Log,Config) ->
case whereis(sasl_sup) of
undefined ->
ok; % sasl application is not started
@@ -164,7 +163,7 @@ log(#{msg:={report,Msg},meta:=#{domain:=[beam,erlang,otp,sasl]}}=Log,Config) ->
do_log(add_log_category(Log,sasl),Config)
end
end;
-log(#{meta:=#{domain:=[beam,erlang,otp]}}=Log,Config) ->
+log(#{meta:=#{domain:=[otp]}}=Log,Config) ->
do_log(add_log_category(Log,error_logger),Config);
log(#{meta:=#{domain:=_}},_) ->
ok;
@@ -186,21 +185,12 @@ handle_call({log,#{meta:=#{gl:=GL}},_}, _From,
{reply, ok, State};
handle_call({log,
- #{msg:=Msg0,
- meta:=#{?MODULE:=#{category:=Category}}=Meta}=Log,
+ #{meta:=#{?MODULE:=#{category:=Category}}}=Log,
#{formatter:={Formatter,FConfig}}},
_From,
#eh_state{log_func=LogFunc}=State) ->
Header = format_header(State),
- Msg =
- case Msg0 of
- {report,R} ->
- Fun=maps:get(report_cb,Meta,fun logger:format_report/1),
- Fun(R);
- _ ->
- Msg0
- end,
- String = Formatter:format(Log#{msg=>Msg},FConfig),
+ String = Formatter:format(Log,FConfig),
case LogFunc of
tc_log ->
ct_logs:tc_log(Category, ?STD_IMPORTANCE,
diff --git a/lib/common_test/src/cth_surefire.erl b/lib/common_test/src/cth_surefire.erl
index 4407ff56c1..b0742717ae 100644
--- a/lib/common_test/src/cth_surefire.erl
+++ b/lib/common_test/src/cth_surefire.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,10 +18,10 @@
%% %CopyrightEnd%
%%--------------------------------------------------------------------
-%%% @doc Common Test Framework functions handling test specifications.
+%%% Common Test Framework functions handling test specifications.
%%%
-%%% <p>This module creates a junit report of the test run if plugged in
-%%% as a suite_callback.</p>
+%%% This module creates a junit report of the test run if plugged in
+%%% as a suite_callback.
-module(cth_surefire).
diff --git a/lib/common_test/src/test_server.erl b/lib/common_test/src/test_server.erl
index 9469619aa9..a896a0551b 100644
--- a/lib/common_test/src/test_server.erl
+++ b/lib/common_test/src/test_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/src/test_server_ctrl.erl b/lib/common_test/src/test_server_ctrl.erl
index 1ae6c8c7c7..34f2feb33c 100644
--- a/lib/common_test/src/test_server_ctrl.erl
+++ b/lib/common_test/src/test_server_ctrl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1393,7 +1393,7 @@ temp_nodename([Chr|Base], Acc) ->
%%
%% Counts the test cases that are about to run and returns that number.
%% If there's a conf group in TestSpec with a repeat property, the total number
-%% of cases can not be calculated and NoOfCases = unknown.
+%% of cases cannot be calculated and NoOfCases = unknown.
count_test_cases(TopCases, SkipCases) when is_list(TopCases) ->
case collect_all_cases(TopCases, SkipCases) of
{error,_Why} = Error ->
@@ -4382,7 +4382,7 @@ do_format_exception(Reason={Error,Stack}) ->
PF = fun(Term, I) ->
io_lib:format("~." ++ integer_to_list(I) ++ "tp", [Term])
end,
- case catch lib:format_exception(1, error, Error, Stack, StackFun, PF, utf8) of
+ case catch erl_error:format_exception(1, error, Error, Stack, StackFun, PF, utf8) of
{'EXIT',_R} ->
{"~tp",Reason};
Formatted ->
@@ -4906,7 +4906,7 @@ collect_files(Dir, Pattern, St, Mode) ->
fullname_to_mod(Path) when is_list(Path) ->
%% If this is called with a binary, then we are probably in +fnu
%% mode and have found a beam file with name encoded as latin1. We
- %% will let this crash since it can not work to load such a module
+ %% will let this crash since it cannot work to load such a module
%% anyway. It should be removed or renamed!
list_to_atom(filename:rootname(filename:basename(Path))).
diff --git a/lib/common_test/src/test_server_node.erl b/lib/common_test/src/test_server_node.erl
index b2d4f199c3..ea7ad8538e 100644
--- a/lib/common_test/src/test_server_node.erl
+++ b/lib/common_test/src/test_server_node.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -591,7 +591,7 @@ cast_to_list(X) -> lists:flatten(io_lib:format("~tw", [X])).
%%% this
%%%
pick_erl_program(default) ->
- cast_to_list(lib:progname());
+ ct:get_progname();
pick_erl_program(L) ->
P = random_element(L),
case P of
@@ -600,7 +600,7 @@ pick_erl_program(L) ->
{release, S} ->
find_release(S);
this ->
- cast_to_list(lib:progname())
+ ct:get_progname()
end.
%% This is an attempt to distinguish between spaces in the program
@@ -611,8 +611,8 @@ pick_erl_program(L) ->
%% ({prog,String}) or if the -program switch to beam is used and
%% includes arguments (typically done by cerl in OTP test environment
%% in order to ensure that slave/peer nodes are started with the same
-%% emulator and flags as the test node. The return from lib:progname()
-%% could then typically be '/<full_path_to>/cerl -gcov').
+%% emulator and flags as the test node. The return from ct:get_progname()
+%% could then typically be "/<full_path_to>/cerl -gcov").
quote_progname(Progname) ->
do_quote_progname(string:lexemes(Progname," ")).
diff --git a/lib/common_test/src/test_server_sup.erl b/lib/common_test/src/test_server_sup.erl
index 139621141d..26e7534c6c 100644
--- a/lib/common_test/src/test_server_sup.erl
+++ b/lib/common_test/src/test_server_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/src/unix_telnet.erl b/lib/common_test/src/unix_telnet.erl
index 5992f26e6d..7a210237a8 100644
--- a/lib/common_test/src/unix_telnet.erl
+++ b/lib/common_test/src/unix_telnet.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,39 +18,6 @@
%% %CopyrightEnd%
%%
-%%% @doc Callback module for ct_telnet, for connecting to a telnet
-%%% server on a unix host.
-%%%
-%%% <p>It requires the following entry in the config file:</p>
-%%% <pre>
-%%% {unix,[{telnet,HostNameOrIpAddress},
-%%% {port,PortNum}, % optional
-%%% {username,UserName},
-%%% {password,Password},
-%%% {keep_alive,Bool}, % optional
-%%% {tcp_nodely,Bool}]} % optional</pre>
-%%%
-%%% <p>To communicate via telnet to the host specified by
-%%% <code>HostNameOrIpAddress</code>, use the interface functions in
-%%% <code>ct_telnet</code>, e.g. <code>open(Name), cmd(Name,Cmd), ...</code>.</p>
-%%%
-%%% <p><code>Name</code> is the name you allocated to the unix host in
-%%% your <code>require</code> statement. E.g.</p>
-%%% <pre> suite() -> [{require,Name,{unix,[telnet]}}].</pre>
-%%% <p>or</p>
-%%% <pre> ct:require(Name,{unix,[telnet]}).</pre>
-%%%
-%%% <p>The "keep alive" activity (i.e. that Common Test sends NOP to the server
-%%% every 10 seconds if the connection is idle) may be enabled or disabled for one
-%%% particular connection as described here. It may be disabled for all connections
-%%% using <c>telnet_settings</c> (see <c>ct_telnet</c>).</p>
-%%%
-%%% <p>Note that the <code>{port,PortNum}</code> tuple is optional and if
-%%% omitted, default telnet port 23 will be used. Also the <c>keep_alive</c> tuple
-%%% is optional, and the value defauls to true (enabled).</p>
-%%%
-%%% @see ct
-%%% @see ct_telnet
-module(unix_telnet).
%% Callbacks for ct_telnet.erl
@@ -61,36 +28,9 @@
-define(password,"Password: ").
-define(prx,"login: |Password: |\\\$ |> ").
-%%%-----------------------------------------------------------------
-%%% @spec get_prompt_regexp() -> PromptRegexp
-%%% PromptRegexp = ct_telnet:prompt_regexp()
-%%%
-%%% @doc Callback for ct_telnet.erl.
-%%%
-%%% <p>Return a suitable regexp string that will match common
-%%% prompts for users on unix hosts.</p>
get_prompt_regexp() ->
?prx.
-
-%%%-----------------------------------------------------------------
-%%% @spec connect(ConnName,Ip,Port,Timeout,KeepAlive,Extra) ->
-%%% {ok,Handle} | {error,Reason}
-%%% ConnName = ct:target_name()
-%%% Ip = string() | {integer(),integer(),integer(),integer()}
-%%% Port = integer()
-%%% Timeout = integer()
-%%% KeepAlive = bool()
-%%% TCPNoDelay = bool()
-%%% Extra = ct:target_name() | {Username,Password}
-%%% Username = string()
-%%% Password = string()
-%%% Handle = ct_telnet:handle()
-%%% Reason = term()
-%%%
-%%% @doc Callback for ct_telnet.erl.
-%%%
-%%% <p>Setup telnet connection to a unix host.</p>
connect(ConnName,Ip,Port,Timeout,KeepAlive,TCPNoDelay,Extra) ->
case Extra of
{Username,Password} ->
diff --git a/lib/common_test/src/vts.erl b/lib/common_test/src/vts.erl
index 2bf3e82ade..38e549d2d6 100644
--- a/lib/common_test/src/vts.erl
+++ b/lib/common_test/src/vts.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/test/ct_auto_clean_SUITE.erl b/lib/common_test/test/ct_auto_clean_SUITE.erl
index fd81430d0d..a89c90eb79 100644
--- a/lib/common_test/test/ct_auto_clean_SUITE.erl
+++ b/lib/common_test/test/ct_auto_clean_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/test/ct_auto_clean_SUITE_data/ac_SUITE.erl b/lib/common_test/test/ct_auto_clean_SUITE_data/ac_SUITE.erl
index dae7c1e22c..e779f70693 100644
--- a/lib/common_test/test/ct_auto_clean_SUITE_data/ac_SUITE.erl
+++ b/lib/common_test/test/ct_auto_clean_SUITE_data/ac_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/test/ct_auto_clean_SUITE_data/cth_auto_clean.erl b/lib/common_test/test/ct_auto_clean_SUITE_data/cth_auto_clean.erl
index 137c81969d..3f8d3957cc 100644
--- a/lib/common_test/test/ct_auto_clean_SUITE_data/cth_auto_clean.erl
+++ b/lib/common_test/test/ct_auto_clean_SUITE_data/cth_auto_clean.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/test/ct_auto_compile_SUITE.erl b/lib/common_test/test/ct_auto_compile_SUITE.erl
index dface99b8f..f88f13c889 100644
--- a/lib/common_test/test/ct_auto_compile_SUITE.erl
+++ b/lib/common_test/test/ct_auto_compile_SUITE.erl
@@ -169,7 +169,7 @@ test_events(ac_flag) ->
{?eh,start_info,{1,1,3}},
{?eh,tc_start,{ct_framework,error_in_suite}},
{?eh,tc_done,{ct_framework,error_in_suite,
- {failed,{error,'bad_SUITE can not be compiled or loaded'}}}},
+ {failed,{error,'bad_SUITE cannot be compiled or loaded'}}}},
{?eh,tc_start,{dummy_SUITE,init_per_suite}},
{?eh,tc_done,{dummy_SUITE,init_per_suite,ok}},
{?eh,test_stats,{1,1,{1,0}}},
@@ -186,7 +186,7 @@ test_events(ac_spec) ->
{?eh,start_info,{1,1,3}},
{?eh,tc_start,{ct_framework,error_in_suite}},
{?eh,tc_done,{ct_framework,error_in_suite,
- {failed,{error,'bad_SUITE can not be compiled or loaded'}}}},
+ {failed,{error,'bad_SUITE cannot be compiled or loaded'}}}},
{?eh,tc_start,{dummy_SUITE,init_per_suite}},
{?eh,tc_done,{dummy_SUITE,init_per_suite,ok}},
{?eh,test_stats,{1,1,{1,0}}},
diff --git a/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl b/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl
index 4e013b8056..e9e8b2a54d 100644
--- a/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl
+++ b/lib/common_test/test/ct_cover_SUITE_data/cover_SUITE.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,9 +23,7 @@
%% Description:
%% This file contains the test cases for the code coverage support
%%
-%% @author Support
-%% @doc Test of code coverage support in common_test
-%% @end
+%% Test of code coverage support in common_test
%%----------------------------------------------------------------------
%%----------------------------------------------------------------------
-module(cover_SUITE).
diff --git a/lib/common_test/test/ct_error_SUITE_data/error/test/verify_config.erl b/lib/common_test/test/ct_error_SUITE_data/error/test/verify_config.erl
index 530ee09654..ef8c05cb2e 100644
--- a/lib/common_test/test/ct_error_SUITE_data/error/test/verify_config.erl
+++ b/lib/common_test/test/ct_error_SUITE_data/error/test/verify_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,9 +18,9 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Example Suite Callback module.
+%%% Common Test Example Suite Callback module.
%%%
-%%% <p>This module gives an example of a common test CTH (Common Test Hook).
+%%% This module gives an example of a common test CTH (Common Test Hook).
%%% There are many ways to add a CTH to a test run, you can do it either in
%%% the command line using -ct_hook, in a test spec using
%%% {ct_hook,M} or in the suite it self by returning ct_hook
@@ -31,7 +31,7 @@
%%% it will be stopped after end_per_suite and so on. See terminate
%%% documentation for a table describing the scoping machanics.
%%%
-%%% All of callbacks except init/1 in a CTH are optional.</p>
+%%% All of callbacks except init/1 in a CTH are optional.
-module(verify_config).
@@ -69,14 +69,14 @@
-record(state, { id = ?MODULE :: term()}).
-%% @doc Always called before any other callback function. Use this to initiate
+%% Always called before any other callback function. Use this to initiate
%% any common state. It should return an state for this CTH.
-spec init(Id :: term(), Opts :: proplists:proplist()) ->
{ok, State :: #state{}}.
init(Id, Opts) ->
{ok,Opts}.
-%% @doc The ID is used to uniquly identify an CTH instance, if two CTH's
+%% The ID is used to uniquly identify an CTH instance, if two CTH's
%% return the same ID the seconds CTH is ignored. This function should NOT
%% have any side effects as it might be called multiple times by common test.
-spec id(Opts :: proplists:proplist()) ->
@@ -84,7 +84,7 @@ init(Id, Opts) ->
id(Opts) ->
os:timestamp().
-%% @doc Called before init_per_suite is called. Note that this callback is
+%% Called before init_per_suite is called. Note that this callback is
%% only called if the CTH is added before init_per_suite is run (eg. in a test
%% specification, suite/0 function etc).
%% You can change the config in the this function.
@@ -95,7 +95,7 @@ id(Opts) ->
pre_init_per_suite(Suite,Config,State) ->
{Config, State}.
-%% @doc Called after init_per_suite.
+%% Called after init_per_suite.
%% you can change the return value in this function.
-spec post_init_per_suite(Suite :: atom(),
Config :: config(),
@@ -105,7 +105,7 @@ pre_init_per_suite(Suite,Config,State) ->
post_init_per_suite(Suite,Config,Return,State) ->
{Return, State}.
-%% @doc Called before end_per_suite. The config/state can be changed here,
+%% Called before end_per_suite. The config/state can be changed here,
%% though it will only affect the *end_per_suite function.
-spec pre_end_per_suite(Suite :: atom(),
Config :: config() | skip_or_fail(),
@@ -114,7 +114,7 @@ post_init_per_suite(Suite,Config,Return,State) ->
pre_end_per_suite(Suite,Config,State) ->
{Config, State}.
-%% @doc Called after end_per_suite. Note that the config cannot be
+%% Called after end_per_suite. Note that the config cannot be
%% changed here, only the status of the suite.
-spec post_end_per_suite(Suite :: atom(),
Config :: config(),
@@ -124,7 +124,7 @@ pre_end_per_suite(Suite,Config,State) ->
post_end_per_suite(Suite,Config,Return,State) ->
{Return, State}.
-%% @doc Called before each init_per_group.
+%% Called before each init_per_group.
%% You can change the config in this function.
-spec pre_init_per_group(Group :: atom(),
Config :: config(),
@@ -133,7 +133,7 @@ post_end_per_suite(Suite,Config,Return,State) ->
pre_init_per_group(Group,Config,State) ->
{Config, State}.
-%% @doc Called after each init_per_group.
+%% Called after each init_per_group.
%% You can change the return value in this function.
-spec post_init_per_group(Group :: atom(),
Config :: config(),
@@ -143,7 +143,7 @@ pre_init_per_group(Group,Config,State) ->
post_init_per_group(Group,Config,Return,State) ->
{Return, State}.
-%% @doc Called after each end_per_group. The config/state can be changed here,
+%% Called after each end_per_group. The config/state can be changed here,
%% though it will only affect the *end_per_group functions.
-spec pre_end_per_group(Group :: atom(),
Config :: config() | skip_or_fail(),
@@ -152,7 +152,7 @@ post_init_per_group(Group,Config,Return,State) ->
pre_end_per_group(Group,Config,State) ->
{Config, State}.
-%% @doc Called after each end_per_group. Note that the config cannot be
+%% Called after each end_per_group. Note that the config cannot be
%% changed here, only the status of the group.
-spec post_end_per_group(Group :: atom(),
Config :: config(),
@@ -162,7 +162,7 @@ pre_end_per_group(Group,Config,State) ->
post_end_per_group(Group,Config,Return,State) ->
{Return, State}.
-%% @doc Called before each test case.
+%% Called before each test case.
%% You can change the config in this function.
-spec pre_init_per_testcase(TC :: atom(),
Config :: config(),
@@ -171,7 +171,7 @@ post_end_per_group(Group,Config,Return,State) ->
pre_init_per_testcase(TC,Config,State) ->
{Config, State}.
-%% @doc Called after each test case. Note that the config cannot be
+%% Called after each test case. Note that the config cannot be
%% changed here, only the status of the test case.
-spec post_end_per_testcase(TC :: atom(),
Config :: config(),
@@ -198,7 +198,7 @@ post_end_per_testcase(TC,Config,Return,State) ->
end,
{Return, State}.
-%% @doc Called after post_init_per_suite, post_end_per_suite, post_init_per_group,
+%% Called after post_init_per_suite, post_end_per_suite, post_init_per_group,
%% post_end_per_group and post_end_per_tc if the suite, group or test case failed.
%% This function should be used for extra cleanup which might be needed.
%% It is not possible to modify the config or the status of the test run.
@@ -209,7 +209,7 @@ post_end_per_testcase(TC,Config,Return,State) ->
on_tc_fail(TC, Reason, State) ->
State.
-%% @doc Called when a test case is skipped by either user action
+%% Called when a test case is skipped by either user action
%% or due to an init function failing. Test case can be
%% end_per_suite, init_per_group, end_per_group and the actual test cases.
-spec on_tc_skip(TC :: end_per_suite |
@@ -221,7 +221,7 @@ on_tc_fail(TC, Reason, State) ->
on_tc_skip(TC, Reason, State) ->
State.
-%% @doc Called when the scope of the CTH is done, this depends on
+%% Called when the scope of the CTH is done, this depends on
%% when the CTH was specified. This translation table describes when this
%% function is called.
%%
diff --git a/lib/common_test/test/ct_event_handler_SUITE_data/eh_A.erl b/lib/common_test/test/ct_event_handler_SUITE_data/eh_A.erl
index 07b21b4178..e4c7be3cac 100644
--- a/lib/common_test/test/ct_event_handler_SUITE_data/eh_A.erl
+++ b/lib/common_test/test/ct_event_handler_SUITE_data/eh_A.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,10 +18,10 @@
%% %CopyrightEnd%
%%
-%%% @doc Event handler module
+%%% Event handler module
%%%
-%%% <p>This is an event handler module used for testing that
-%%% Common Test generates events as expected.</p>
+%%% This is an event handler module used for testing that
+%%% Common Test generates events as expected.
%%%
-module(eh_A).
diff --git a/lib/common_test/test/ct_hooks_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE.erl
index 6228524a88..0f5636a789 100644
--- a/lib/common_test/test/ct_hooks_SUITE.erl
+++ b/lib/common_test/test/ct_hooks_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_per_tc_cth_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_per_tc_cth_SUITE.erl
index d400348354..404fb33476 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_per_tc_cth_SUITE.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/ct_scope_per_tc_cth_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,7 +29,6 @@
%% Test server callback functions
%%--------------------------------------------------------------------
-%% @doc
%% Config - [tuple()]
%% A list of key/value pairs, holding the test case configuration.
%%
@@ -38,27 +37,23 @@
%% Note: This function is free to add any key/value pairs to the Config
%% variable, but should NOT alter/remove any existing entries.
%%
-%% @spec init_per_suite(Config) -> Config
-%% @end
+%% -spec init_per_suite(Config) -> Config
%%--------------------------------------------------------------------
init_per_suite(Config) ->
Config.
%%--------------------------------------------------------------------
-%% @doc
%% Config - [tuple()]
%% A list of key/value pairs, holding the test case configuration.
%%
%% Cleanup after the whole suite
%%
-%% @spec end_per_suite(Config) -> _
-%% @end
+%% -spec end_per_suite(Config) -> _
%%--------------------------------------------------------------------
end_per_suite(_Config) ->
ok.
%%--------------------------------------------------------------------
-%% @doc
%% Case - atom()
%% Name of the test case that is about to be run.
%% Config - [tuple()]
@@ -70,14 +65,12 @@ end_per_suite(_Config) ->
%% variable, but should NOT alter/remove any existing entries.
%% Initiation before each test case
%%
-%% @spec init_per_testcase(TestCase, Config) -> Config
-%% @end
+%% -spec init_per_testcase(TestCase, Config) -> Config
%%--------------------------------------------------------------------
init_per_testcase(_TestCase, Config) ->
[{ct_hooks,[empty_cth]}|Config].
%%--------------------------------------------------------------------
-%% @doc
%% Case - atom()
%% Name of the test case that is about to be run.
%% Config - [tuple()]
@@ -85,22 +78,19 @@ init_per_testcase(_TestCase, Config) ->
%%
%% Cleanup after each test case
%%
-%% @spec end_per_testcase(TestCase, Config) -> _
-%% @end
+%% -spec end_per_testcase(TestCase, Config) -> _
%%--------------------------------------------------------------------
end_per_testcase(_TestCase, _Config) ->
ok.
%%--------------------------------------------------------------------
-%% @doc
%% TestCases - [Case]
%% Case - atom()
%% Name of a test case.
%%
%% Returns a list of all test cases in this test suite
%%
-%% @spec all() -> TestCases
-%% @end
+%% -spec all() -> TestCases
%%--------------------------------------------------------------------
all() ->
[test_case].
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/cth_log_SUITE.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/cth_log_SUITE.erl
index a0cd77b88b..eda190b682 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/cth_log_SUITE.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/cth_log_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl
index 961ea68d2d..c648367838 100644
--- a/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl
+++ b/lib/common_test/test/ct_hooks_SUITE_data/cth/tests/empty_cth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,9 +18,9 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Example Suite Callback module.
+%%% Common Test Example Suite Callback module.
%%%
-%%% <p>This module gives an example of a common test CTH (Common Test Hook).
+%%% This module gives an example of a common test CTH (Common Test Hook).
%%% There are many ways to add a CTH to a test run, you can do it either in
%%% the command line using -ct_hook, in a test spec using
%%% {ct_hook,M} or in the suite it self by returning ct_hook
@@ -31,7 +31,7 @@
%%% it will be stopped after end_per_suite and so on. See terminate
%%% documentation for a table describing the scoping machanics.
%%%
-%%% All of callbacks except init/1 in a CTH are optional.</p>
+%%% All of callbacks except init/1 in a CTH are optional.
-module(empty_cth).
@@ -71,7 +71,7 @@
-record(state, { id = ?MODULE :: term()}).
-%% @doc Always called before any other callback function. Use this to initiate
+%% Always called before any other callback function. Use this to initiate
%% any common state. It should return an state for this CTH.
-spec init(Id :: term(), Opts :: proplists:proplist()) ->
{ok, State :: #state{}}.
@@ -81,7 +81,7 @@ init(Id, Opts) ->
ct:log("~w:init called", [?MODULE]),
{ok,Opts}.
-%% @doc The ID is used to uniquly identify an CTH instance, if two CTH's
+%% The ID is used to uniquly identify an CTH instance, if two CTH's
%% return the same ID the seconds CTH is ignored. This function should NOT
%% have any side effects as it might be called multiple times by common test.
-spec id(Opts :: proplists:proplist()) ->
@@ -92,7 +92,7 @@ id(Opts) ->
ct:log("~w:id called", [?MODULE]),
ct_test_support:unique_timestamp().
-%% @doc Called before init_per_suite is called. Note that this callback is
+%% Called before init_per_suite is called. Note that this callback is
%% only called if the CTH is added before init_per_suite is run (eg. in a test
%% specification, suite/0 function etc).
%% You can change the config in the this function.
@@ -108,7 +108,7 @@ pre_init_per_suite(Suite,Config,State) ->
ct:log("~w:pre_init_per_suite(~w) called", [?MODULE,Suite]),
{Config, State}.
-%% @doc Called after init_per_suite.
+%% Called after init_per_suite.
%% you can change the return value in this function.
-spec post_init_per_suite(Suite :: atom(),
Config :: config(),
@@ -123,7 +123,7 @@ post_init_per_suite(Suite,Config,Return,State) ->
ct:log("~w:post_init_per_suite(~w) called", [?MODULE,Suite]),
{Return, State}.
-%% @doc Called before end_per_suite. The config/state can be changed here,
+%% Called before end_per_suite. The config/state can be changed here,
%% though it will only affect the *end_per_suite function.
-spec pre_end_per_suite(Suite :: atom(),
Config :: config() | skip_or_fail(),
@@ -137,7 +137,7 @@ pre_end_per_suite(Suite,Config,State) ->
ct:log("~w:pre_end_per_suite(~w) called", [?MODULE,Suite]),
{Config, State}.
-%% @doc Called after end_per_suite. Note that the config cannot be
+%% Called after end_per_suite. Note that the config cannot be
%% changed here, only the status of the suite.
-spec post_end_per_suite(Suite :: atom(),
Config :: config(),
@@ -152,7 +152,7 @@ post_end_per_suite(Suite,Config,Return,State) ->
ct:log("~w:post_end_per_suite(~w) called", [?MODULE,Suite]),
{Return, State}.
-%% @doc Called before each init_per_group.
+%% Called before each init_per_group.
%% You can change the config in this function.
-spec pre_init_per_group(Suite :: atom(),
Group :: atom(),
@@ -167,7 +167,7 @@ pre_init_per_group(Suite,Group,Config,State) ->
ct:log("~w:pre_init_per_group(~w,~w) called", [?MODULE,Suite,Group]),
{Config, State}.
-%% @doc Called after each init_per_group.
+%% Called after each init_per_group.
%% You can change the return value in this function.
-spec post_init_per_group(Suite :: atom(),
Group :: atom(),
@@ -183,7 +183,7 @@ post_init_per_group(Suite,Group,Config,Return,State) ->
ct:log("~w:post_init_per_group(~w,~w) called", [?MODULE,Suite,Group]),
{Return, State}.
-%% @doc Called after each end_per_group. The config/state can be changed here,
+%% Called after each end_per_group. The config/state can be changed here,
%% though it will only affect the *end_per_group functions.
-spec pre_end_per_group(Suite :: atom(),
Group :: atom(),
@@ -198,7 +198,7 @@ pre_end_per_group(Suite,Group,Config,State) ->
ct:log("~w:pre_end_per_group(~w~w) called", [?MODULE,Suite,Group]),
{Config, State}.
-%% @doc Called after each end_per_group. Note that the config cannot be
+%% Called after each end_per_group. Note that the config cannot be
%% changed here, only the status of the group.
-spec post_end_per_group(Suite :: atom(),
Group :: atom(),
@@ -214,7 +214,7 @@ post_end_per_group(Suite,Group,Config,Return,State) ->
ct:log("~w:post_end_per_group(~w,~w) called", [?MODULE,Suite,Group]),
{Return, State}.
-%% @doc Called before init_per_testcase/2 for each test case.
+%% Called before init_per_testcase/2 for each test case.
%% You can change the config in this function.
-spec pre_init_per_testcase(Suite :: atom(),
TC :: atom(),
@@ -229,7 +229,7 @@ pre_init_per_testcase(Suite,TC,Config,State) ->
ct:log("~w:pre_init_per_testcase(~w,~w) called", [?MODULE,Suite,TC]),
{Config, State}.
-%% @doc Called after init_per_testcase/2, and before the test case.
+%% Called after init_per_testcase/2, and before the test case.
-spec post_init_per_testcase(Suite :: atom(),
TC :: atom(),
Config :: config(),
@@ -244,7 +244,7 @@ post_init_per_testcase(Suite,TC,Config,Return,State) ->
ct:log("~w:post_init_per_testcase(~w,~w) called", [?MODULE,Suite,TC]),
{Return, State}.
-%% @doc Called before end_per_testacse/2. No skip or fail allowed here,
+%% Called before end_per_testacse/2. No skip or fail allowed here,
%% only config additions.
-spec pre_end_per_testcase(Suite :: atom(),
TC :: atom(),
@@ -259,7 +259,7 @@ pre_end_per_testcase(Suite,TC,Config,State) ->
ct:log("~w:pre_end_per_testcase(~w,~w) called", [?MODULE,Suite,TC]),
{Config, State}.
-%% @doc Called after end_per_testcase/2 for each test case. Note that
+%% Called after end_per_testcase/2 for each test case. Note that
%% the config cannot be changed here, only the status of the test case.
-spec post_end_per_testcase(Suite :: atom(),
TC :: atom(),
@@ -275,7 +275,7 @@ post_end_per_testcase(Suite,TC,Config,Return,State) ->
ct:log("~w:post_end_per_testcase(~w,~w) called", [?MODULE,Suite,TC]),
{Return, State}.
-%% @doc Called after post_init_per_suite, post_end_per_suite, post_init_per_group,
+%% Called after post_init_per_suite, post_end_per_suite, post_init_per_group,
%% post_end_per_group and post_end_per_tc if the suite, group or test case failed.
%% This function should be used for extra cleanup which might be needed.
%% It is not possible to modify the config or the status of the test run.
@@ -292,7 +292,7 @@ on_tc_fail(Suite, TC, Reason, State) ->
ct:log("~w:on_tc_fail(~w,~w) called", [?MODULE,Suite,TC]),
State.
-%% @doc Called when a test case is skipped by either user action
+%% Called when a test case is skipped by either user action
%% or due to an init function failing. Test case can be
%% end_per_suite, init_per_group, end_per_group and the actual test cases.
-spec on_tc_skip(Suite :: atom(),
@@ -310,7 +310,7 @@ on_tc_skip(Suite, TC, Reason, State) ->
ct:log("~w:on_tc_skip(~w,~w) called", [?MODULE,Suite,TC]),
State.
-%% @doc Called when the scope of the CTH is done, this depends on
+%% Called when the scope of the CTH is done, this depends on
%% when the CTH was specified. This translation table describes when this
%% function is called.
%%
diff --git a/lib/common_test/test/ct_log_SUITE.erl b/lib/common_test/test/ct_log_SUITE.erl
index 9655b6f09a..214eb17e1a 100644
--- a/lib/common_test/test/ct_log_SUITE.erl
+++ b/lib/common_test/test/ct_log_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
index 586589ad40..0a374d7404 100644
--- a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
+++ b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,9 +23,7 @@
%% Description:
%% This file contains the test cases for the ct_netconfc API.
%%
-%% @author Support
-%% @doc Netconf Client Interface.
-%% @end
+%% Netconf Client Interface.
%%----------------------------------------------------------------------
%%----------------------------------------------------------------------
-module(netconfc1_SUITE).
@@ -207,7 +205,7 @@ hello_required_exists(Config) ->
SshDir = ?config(ssh_dir,Config),
{ok,_Client1} = open_configured_success(my_named_connection,SshDir),
- %% Check that same name can not be used twice
+ %% Check that same name cannot be used twice
{error,{connection_exists,_Client1}} =
ct_netconfc:open(my_named_connection,[{user_dir,SshDir}]),
@@ -387,7 +385,7 @@ timeout_get(Config) ->
%% received, the timeout message might already be sent when the timer
%% is cancelled. This test checks that the timeout message is flushed
%% from the message queue. If it isn't, the client crashes and the
-%% session can not be closed afterwards.
+%% session cannot be closed afterwards.
%% Note that we can only hope that the test case triggers the problem
%% every now and then, as it is very timing dependent...
flush_timeout_get(Config) ->
diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl
index 975f6cafcb..656fdb4a40 100644
--- a/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl
+++ b/lib/common_test/test/ct_netconfc_SUITE_data/ns.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/test/ct_pre_post_test_io_SUITE.erl b/lib/common_test/test/ct_pre_post_test_io_SUITE.erl
index 538fd822c1..bca2d5f3de 100644
--- a/lib/common_test/test/ct_pre_post_test_io_SUITE.erl
+++ b/lib/common_test/test/ct_pre_post_test_io_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/test/ct_priv_dir_SUITE_data/priv_dir_SUITE.erl b/lib/common_test/test/ct_priv_dir_SUITE_data/priv_dir_SUITE.erl
index b1d191873d..0e10ec187d 100644
--- a/lib/common_test/test/ct_priv_dir_SUITE_data/priv_dir_SUITE.erl
+++ b/lib/common_test/test/ct_priv_dir_SUITE_data/priv_dir_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/test/ct_repeat_testrun_SUITE_data/a_test/r1_SUITE.erl b/lib/common_test/test/ct_repeat_testrun_SUITE_data/a_test/r1_SUITE.erl
index 4ce375b4ee..1a305b1516 100644
--- a/lib/common_test/test/ct_repeat_testrun_SUITE_data/a_test/r1_SUITE.erl
+++ b/lib/common_test/test/ct_repeat_testrun_SUITE_data/a_test/r1_SUITE.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,14 +19,6 @@
%%
%%----------------------------------------------------------------------
%% File: r1_SUITE.erl
-%%
-%% Description:
-%%
-%%
-%% @author Support
-%% @doc
-%% @end
-%%----------------------------------------------------------------------
%%----------------------------------------------------------------------
-module(r1_SUITE).
-include_lib("common_test/include/ct.hrl").
diff --git a/lib/common_test/test/ct_repeat_testrun_SUITE_data/b_test/r2_SUITE.erl b/lib/common_test/test/ct_repeat_testrun_SUITE_data/b_test/r2_SUITE.erl
index 77bb544080..393cbcc780 100644
--- a/lib/common_test/test/ct_repeat_testrun_SUITE_data/b_test/r2_SUITE.erl
+++ b/lib/common_test/test/ct_repeat_testrun_SUITE_data/b_test/r2_SUITE.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,14 +19,6 @@
%%
%%----------------------------------------------------------------------
%% File: r2_SUITE.erl
-%%
-%% Description:
-%%
-%%
-%% @author Support
-%% @doc
-%% @end
-%%----------------------------------------------------------------------
%%----------------------------------------------------------------------
-module(r2_SUITE).
-include_lib("common_test/include/ct.hrl").
diff --git a/lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE.erl b/lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE.erl
index a6533641d8..1c81bbe95d 100644
--- a/lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE.erl
+++ b/lib/common_test/test/ct_snmp_SUITE_data/snmp_SUITE.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,9 +23,7 @@
%% Description:
%% This file contains the test cases for the ct_snmp API.
%%
-%% @author Support
-%% @doc Test of SNMP support in common_test
-%% @end
+%% Test of SNMP support in common_test
%%----------------------------------------------------------------------
%%----------------------------------------------------------------------
-module(snmp_SUITE).
diff --git a/lib/common_test/test/ct_surefire_SUITE_data/surefire_SUITE.erl b/lib/common_test/test/ct_surefire_SUITE_data/surefire_SUITE.erl
index ed10356cdd..7a73e45b43 100644
--- a/lib/common_test/test/ct_surefire_SUITE_data/surefire_SUITE.erl
+++ b/lib/common_test/test/ct_surefire_SUITE_data/surefire_SUITE.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,9 +23,7 @@
%% Description:
%% This file contains the test cases for cth_surefire.
%%
-%% @author Support
-%% @doc Test of surefire support in common_test
-%% @end
+%% Test of surefire support in common_test
%%----------------------------------------------------------------------
%%----------------------------------------------------------------------
-module(surefire_SUITE).
diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl
index 2ba7c7c13f..388d5d46c6 100644
--- a/lib/common_test/test/ct_test_support.erl
+++ b/lib/common_test/test/ct_test_support.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,9 +18,9 @@
%% %CopyrightEnd%
%%
-%%% @doc Test support functions
+%%% Test support functions
%%%
-%%% <p>This is a support module for testing the Common Test Framework.</p>
+%%% This is a support module for testing the Common Test Framework.
%%%
-module(ct_test_support).
diff --git a/lib/common_test/test/ct_test_support_eh.erl b/lib/common_test/test/ct_test_support_eh.erl
index e8db52dcd3..120692dc7c 100644
--- a/lib/common_test/test/ct_test_support_eh.erl
+++ b/lib/common_test/test/ct_test_support_eh.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,10 +18,10 @@
%% %CopyrightEnd%
%%
-%%% @doc Event handler module
+%%% Event handler module
%%%
-%%% <p>This is an event handler module used for testing that
-%%% Common Test generates events as expected.</p>
+%%% This is an event handler module used for testing that
+%%% Common Test generates events as expected.
%%%
-module(ct_test_support_eh).
diff --git a/lib/common_test/test/ct_unicode_SUITE_data/unicode_atoms_SUITE.erl b/lib/common_test/test/ct_unicode_SUITE_data/unicode_atoms_SUITE.erl
index 041c13cdbd..4f9dd20e3e 100644
--- a/lib/common_test/test/ct_unicode_SUITE_data/unicode_atoms_SUITE.erl
+++ b/lib/common_test/test/ct_unicode_SUITE_data/unicode_atoms_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/test/ct_userconfig_callback.erl b/lib/common_test/test/ct_userconfig_callback.erl
index 14e3d9a688..e48d338dd5 100644
--- a/lib/common_test/test/ct_userconfig_callback.erl
+++ b/lib/common_test/test/ct_userconfig_callback.erl
@@ -1,7 +1,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/test/ct_verbosity_SUITE_data/simple_evh.erl b/lib/common_test/test/ct_verbosity_SUITE_data/simple_evh.erl
index 03a0832e53..d1c293b4af 100644
--- a/lib/common_test/test/ct_verbosity_SUITE_data/simple_evh.erl
+++ b/lib/common_test/test/ct_verbosity_SUITE_data/simple_evh.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,14 +18,14 @@
%% %CopyrightEnd%
%%
-%%% @doc Common Test Framework Event Handler
+%%% Common Test Framework Event Handler
%%%
-%%% <p>This module implements an event handler that CT uses to
+%%% This module implements an event handler that CT uses to
%%% handle status and progress notifications during test runs.
%%% The notifications are handled locally (per node) and passed
%%% on to ct_master when CT runs in distributed mode. This
%%% module may be used as a template for other event handlers
-%%% that can be plugged in to handle local logging and reporting.</p>
+%%% that can be plugged in to handle local logging and reporting.
-module(simple_evh).
-behaviour(gen_event).
diff --git a/lib/common_test/test/test_server_SUITE.erl b/lib/common_test/test/test_server_SUITE.erl
index edfaea1d08..6e52f24025 100644
--- a/lib/common_test/test/test_server_SUITE.erl
+++ b/lib/common_test/test/test_server_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,12 +18,7 @@
%% %CopyrightEnd%
%%
%%%-------------------------------------------------------------------
-%%% @author Lukas Larsson <[email protected]>
-%%% @copyright (C) 2011, Erlang Solutions Ltd.
-%%% @doc
-%%%
-%%% @end
-%%% Created : 15 Feb 2011 by Lukas Larsson <[email protected]>
+%%% Author: Lukas Larsson <[email protected]>
%%%-------------------------------------------------------------------
-module(test_server_SUITE).
@@ -265,7 +260,7 @@ translate_filename(Filename,EncodingOnTestNode) ->
end.
get_latest_run_dir(Dir) ->
- %% For the time being, filelib:wildcard can not take a binary
+ %% For the time being, filelib:wildcard cannot take a binary
%% argument, so we avoid using this here.
case file:list_dir(Dir) of
{ok,Files} ->
@@ -320,7 +315,7 @@ generate_and_run_unicode_test(Config0,Encoding) ->
DataDir = ?config(data_dir,Config0),
Suite = create_unicode_test_suite(DataDir,Encoding),
- %% We can not run this test on default node since it must be
+ %% We cannot run this test on default node since it must be
%% started with correct file name mode (+fnu/+fnl).
%% OBS: the node are stopped by end_per_testcase/2
Config1 = lists:keydelete(node,1,Config0),
diff --git a/lib/common_test/test/test_server_test_lib.erl b/lib/common_test/test/test_server_test_lib.erl
index 9ee946af0b..58b3aaee9b 100644
--- a/lib/common_test/test/test_server_test_lib.erl
+++ b/lib/common_test/test/test_server_test_lib.erl
@@ -22,7 +22,7 @@
-export([parse_suite/1]).
-export([init/2, pre_init_per_testcase/3, post_end_per_testcase/4]).
-%% for test_server_SUITE when node can not be started as slave
+%% for test_server_SUITE when node cannot be started as slave
-export([prepare_tester_node/2]).
-include("test_server_test_lib.hrl").
diff --git a/lib/common_test/test_server/ts.erl b/lib/common_test/test_server/ts.erl
index 330652e73f..179380a562 100644
--- a/lib/common_test/test_server/ts.erl
+++ b/lib/common_test/test_server/ts.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/test_server/ts_autoconf_win32.erl b/lib/common_test/test_server/ts_autoconf_win32.erl
index 6f6caaeb70..1179dfe0e5 100644
--- a/lib/common_test/test_server/ts_autoconf_win32.erl
+++ b/lib/common_test/test_server/ts_autoconf_win32.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/test_server/ts_erl_config.erl b/lib/common_test/test_server/ts_erl_config.erl
index c7fe4ccf83..537628e39a 100644
--- a/lib/common_test/test_server/ts_erl_config.erl
+++ b/lib/common_test/test_server/ts_erl_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -358,7 +358,15 @@ link_library(_LibName,_Other) ->
%% Returns emulator specific variables.
emu_vars(Vars) ->
[{is_source_build, is_source_build()},
- {erl_name, atom_to_list(lib:progname())}|Vars].
+ {erl_name, get_progname()}|Vars].
+
+get_progname() ->
+ case init:get_argument(progname) of
+ {ok, [[Prog]]} ->
+ Prog;
+ _Other ->
+ "no_prog_name"
+ end.
is_source_build() ->
string:find(erlang:system_info(system_version), "source") =/= nomatch.
diff --git a/lib/common_test/test_server/ts_install_cth.erl b/lib/common_test/test_server/ts_install_cth.erl
index 35a5ec916c..b6503fb864 100644
--- a/lib/common_test/test_server/ts_install_cth.erl
+++ b/lib/common_test/test_server/ts_install_cth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@
%% %CopyrightEnd%
%%
-%%% @doc TS Installed SCB
+%%% TS Installed SCB
%%%
%%% This module does what the make parts of the ts:run/x command did,
%%% but not the Makefile.first parts! So they have to be done by ts or
@@ -60,13 +60,13 @@
-record(state, { ts_conf_dir, target_system, install_opts, nodenames, nodes }).
-%% @doc The id of this SCB
+%% The id of this SCB
-spec id(Opts :: term()) ->
Id :: term().
id(_Opts) ->
?MODULE.
-%% @doc Always called before any other callback function.
+%% Always called before any other callback function.
-spec init(Id :: term(), Opts :: proplists:proplist()) ->
{ok, State :: #state{}}.
init(_Id, Opts) ->
@@ -81,7 +81,7 @@ init(_Id, Opts) ->
target_system = TargetSystem,
install_opts = InstallOpts } }.
-%% @doc Called before init_per_suite is called.
+%% Called before init_per_suite is called.
-spec pre_init_per_suite(Suite :: atom(),
Config :: config(),
State :: #state{}) ->
@@ -113,7 +113,7 @@ pre_init_per_suite(_Suite,Config,State) ->
{{fail,{?MODULE,{Error,Reason, Stack}}},State}
end.
-%% @doc Called after init_per_suite.
+%% Called after init_per_suite.
-spec post_init_per_suite(Suite :: atom(),
Config :: config(),
Return :: config() | skip_or_fail(),
@@ -123,7 +123,7 @@ post_init_per_suite(_Suite,_Config,Return,State) ->
test_server_ctrl:kill_slavenodes(),
{Return, State}.
-%% @doc Called before end_per_suite.
+%% Called before end_per_suite.
-spec pre_end_per_suite(Suite :: atom(),
Config :: config() | skip_or_fail(),
State :: #state{}) ->
@@ -131,7 +131,7 @@ post_init_per_suite(_Suite,_Config,Return,State) ->
pre_end_per_suite(_Suite,Config,State) ->
{Config, State}.
-%% @doc Called after end_per_suite.
+%% Called after end_per_suite.
-spec post_end_per_suite(Suite :: atom(),
Config :: config(),
Return :: term(),
@@ -140,7 +140,7 @@ pre_end_per_suite(_Suite,Config,State) ->
post_end_per_suite(_Suite,_Config,Return,State) ->
{Return, State}.
-%% @doc Called before each init_per_group.
+%% Called before each init_per_group.
-spec pre_init_per_group(Group :: atom(),
Config :: config(),
State :: #state{}) ->
@@ -148,7 +148,7 @@ post_end_per_suite(_Suite,_Config,Return,State) ->
pre_init_per_group(_Group,Config,State) ->
{add_node_name(Config, State), State}.
-%% @doc Called after each init_per_group.
+%% Called after each init_per_group.
-spec post_init_per_group(Group :: atom(),
Config :: config(),
Return :: config() | skip_or_fail(),
@@ -157,7 +157,7 @@ pre_init_per_group(_Group,Config,State) ->
post_init_per_group(_Group,_Config,Return,State) ->
{Return, State}.
-%% @doc Called after each end_per_group.
+%% Called after each end_per_group.
-spec pre_end_per_group(Group :: atom(),
Config :: config() | skip_or_fail(),
State :: #state{}) ->
@@ -165,7 +165,7 @@ post_init_per_group(_Group,_Config,Return,State) ->
pre_end_per_group(_Group,Config,State) ->
{Config, State}.
-%% @doc Called after each end_per_group.
+%% Called after each end_per_group.
-spec post_end_per_group(Group :: atom(),
Config :: config(),
Return :: term(),
@@ -174,7 +174,7 @@ pre_end_per_group(_Group,Config,State) ->
post_end_per_group(_Group,_Config,Return,State) ->
{Return, State}.
-%% @doc Called before each test case.
+%% Called before each test case.
-spec pre_init_per_testcase(TC :: atom(),
Config :: config(),
State :: #state{}) ->
@@ -190,7 +190,7 @@ pre_init_per_testcase(_TC,Config,State) ->
post_init_per_testcase(_TC,_Config,Return,State) ->
{Return, State}.
-%% @doc Called after each test case.
+%% Called after each test case.
-spec pre_end_per_testcase(TC :: atom(),
Config :: config(),
State :: #state{}) ->
@@ -206,7 +206,7 @@ pre_end_per_testcase(_TC,Config,State) ->
post_end_per_testcase(_TC,_Config,Return,State) ->
{Return, State}.
-%% @doc Called after a test case failed.
+%% Called after a test case failed.
-spec on_tc_fail(TC :: init_per_suite | end_per_suite |
init_per_group | end_per_group | atom(),
Reason :: term(), State :: #state{}) ->
@@ -214,7 +214,7 @@ post_end_per_testcase(_TC,_Config,Return,State) ->
on_tc_fail(_TC, _Reason, State) ->
State.
-%% @doc Called when a test case is skipped.
+%% Called when a test case is skipped.
-spec on_tc_skip(TC :: end_per_suite | init_per_group | end_per_group | atom(),
{tc_auto_skip, {failed, {Mod :: atom(), Function :: atom(),
Reason :: term()}}} |
@@ -224,7 +224,7 @@ on_tc_fail(_TC, _Reason, State) ->
on_tc_skip(_TC, _Reason, State) ->
State.
-%% @doc Called when the scope of the SCB is done.
+%% Called when the scope of the SCB is done.
-spec terminate(State :: #state{}) ->
term().
terminate(_State) ->
diff --git a/lib/common_test/test_server/ts_lib.erl b/lib/common_test/test_server/ts_lib.erl
index da8d676b18..7c1c14f467 100644
--- a/lib/common_test/test_server/ts_lib.erl
+++ b/lib/common_test/test_server/ts_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/common_test/test_server/ts_run.erl b/lib/common_test/test_server/ts_run.erl
index 3f594236bc..7e12b9652c 100644
--- a/lib/common_test/test_server/ts_run.erl
+++ b/lib/common_test/test_server/ts_run.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -199,7 +199,7 @@ make_command(Vars, Spec, State) ->
TestPath = filename:nativename(TestDir),
Erl = case os:getenv("TS_RUN_VALGRIND") of
false ->
- atom_to_list(lib:progname());
+ ct:get_progname();
_ ->
case State#state.file of
Dir when is_list(Dir) ->
@@ -411,9 +411,9 @@ make_common_test_args(Args0, Options0, _Vars) ->
end,
ConfigFiles = [{config,[filename:join(ConfigPath,File)
|| File <- get_config_files()]}],
- io_lib:format("~100000p",[[{abort_if_missing_suites,true} |
- Args0++Trace++Cover++Logdir++
- ConfigFiles++Options++TimeTrap]]).
+ io_lib:format("~0p",[[{abort_if_missing_suites,true} |
+ Args0++Trace++Cover++Logdir++
+ ConfigFiles++Options++TimeTrap]]).
to_list(X) when is_atom(X) ->
atom_to_list(X);
diff --git a/lib/common_test/vsn.mk b/lib/common_test/vsn.mk
index ea3e9871cb..2dc1965878 100644
--- a/lib/common_test/vsn.mk
+++ b/lib/common_test/vsn.mk
@@ -1 +1 @@
-COMMON_TEST_VSN = 1.15.4
+COMMON_TEST_VSN = 1.16
diff --git a/lib/compiler/doc/src/Makefile b/lib/compiler/doc/src/Makefile
index 13210de040..661415899f 100644
--- a/lib/compiler/doc/src/Makefile
+++ b/lib/compiler/doc/src/Makefile
@@ -89,6 +89,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml
index e4491288a6..1a71c83521 100644
--- a/lib/compiler/doc/src/compile.xml
+++ b/lib/compiler/doc/src/compile.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml
index bc1f68337b..671126b73b 100644
--- a/lib/compiler/doc/src/notes.xml
+++ b/lib/compiler/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,305 @@
<p>This document describes the changes made to the Compiler
application.</p>
+<section><title>Compiler 7.2.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed an issue where files compiled with the
+ <c>+deterministic</c> option differed if they were
+ compiled in a different directory but were otherwise
+ identical.</p>
+ <p>
+ Own Id: OTP-15204 Aux Id: ERL-679 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.2.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>In rare cases involving matching of binary literal
+ strings, the compiler could optimize away code that
+ should be executed.</p>
+ <p>
+ Own Id: OTP-15156 Aux Id: ERL-655 </p>
+ </item>
+ <item>
+ <p>There could be an internal consistency check failure
+ when compiling code that called <c>map_get(Key, Map)</c>
+ and then updated the same map.</p>
+ <p>
+ Own Id: OTP-15157</p>
+ </item>
+ <item>
+ <p>In rare circumstances, the compiler could crash in
+ <c>beam_jump</c> when compiling a floating point
+ operation.</p>
+ <p>
+ Own Id: OTP-15166 Aux Id: ERL-660 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>The could could crash when compiling a complicated
+ function that used the binary syntax.</p>
+ <p>
+ Own Id: OTP-15150 Aux Id: ERL-650 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed an error in an optimization pass that caused
+ impossible tuple matching.</p>
+ <p>
+ Own Id: OTP-14855 Aux Id: ERL-549 </p>
+ </item>
+ <item>
+ <p>The exception thrown when a list comprehension was
+ given a non-list term was not always correct.</p>
+ <p>
+ Own Id: OTP-14992 Aux Id: ERL-572 </p>
+ </item>
+ <item>
+ <p>The compiler could produce incorrect code in rare
+ circumstances when the <c>[{inline,F/A}]</c> option was
+ used.</p>
+ <p>
+ Own Id: OTP-15115 Aux Id: PR-1831 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>Changed the default behaviour of <c>.erlang</c>
+ loading: <c>.erlang</c> is no longer loaded from the
+ current directory. <c>c:erlangrc(PathList)</c> can be
+ used to search and load an <c>.erlang</c> file from user
+ specified directories.</p> <p><c>escript</c>,
+ <c>erlc</c>, <c>dialyzer</c> and <c>typer</c> no longer
+ load an <c>.erlang</c> at all.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14439</p>
+ </item>
+ <item>
+ <p>Support for "tuple calls" have been removed from the
+ run-time system. Tuple calls was an undocumented and
+ unsupported feature which allowed the module argument for
+ an apply operation to be a tuple: <c>Var = dict:new(),
+ Var:size()</c>. This "feature" frequently caused
+ confusion, especially when such call failed. The
+ stacktrace would point out functions that don't exist in
+ the source code.</p>
+ <p>For legacy code that need to use parameterized modules
+ or tuple calls for some other reason, there is a new
+ compiler option called <c>tuple_calls</c>. When this
+ option is given, the compiler will generate extra code
+ that emulates the old behavior for calls where the module
+ is a variable.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14497</p>
+ </item>
+ <item>
+ <p>In code such as <c>example({ok, Val}) -&gt; {ok,
+ Val}.</c> a tuple would be built. The compiler will now
+ automatically rewrite the code to
+ <c>example({ok,Val}=Tuple) -&gt; Tuple.</c> which will
+ reduce code size, execution time, and remove GC
+ pressure.</p>
+ <p>
+ Own Id: OTP-14505</p>
+ </item>
+ <item>
+ <p>The optimization of <c>case</c> expression where only
+ one of the case arms can execute successfully has been
+ improved.</p>
+ <p>
+ Own Id: OTP-14525</p>
+ </item>
+ <item>
+ <p>Some uses of binary matching has been slightly
+ improved, eliminating unnecessary register shuffling.</p>
+ <p>
+ Own Id: OTP-14594 Aux Id: ERL-444 </p>
+ </item>
+ <item>
+ <p>There is a new <c>{compile_info,Info}</c> option for
+ the compiler that allows BEAM-based languages such as
+ Elixir and LFE to add their own compiler versions.</p>
+ <p>
+ Own Id: OTP-14615 Aux Id: PR-1558 </p>
+ </item>
+ <item>
+ <p>Loaded BEAM code in a 64-bit system requires less
+ memory because of better packing of operands for
+ instructions.</p>
+ <p>These memory savings were achieved by major
+ improvements to the <c>beam_makeops</c> scripts used when
+ building the run time system and BEAM compiler. There is
+ also new for documentation for <c>beam_makeops</c> that
+ describes how new BEAM instructions and loader
+ transformations can be implemented. The documentation is
+ found in here in a source directory or git repository:
+ erts/emulator/internal_doc/beam_makeops.md. An online
+ version can be found here:
+ https://github.com/erlang/otp/blob/master/erts/emulator/internal_doc/beam_makeops.md</p>
+ <p>
+ Own Id: OTP-14626</p>
+ </item>
+ <item>
+ <p>Size calculations for binary constructions has been
+ somewhat optimized, producing smaller code.</p>
+ <p>
+ Own Id: OTP-14654</p>
+ </item>
+ <item>
+ <p>When the value returned from a '<c>catch</c>'
+ expression is ignored, no stacktrace will be built if an
+ exception is caught. That will save time and produce less
+ garbage. There are also some minor optimizations of
+ '<c>try</c>/<c>catch</c>' both in the compiler and
+ run-time system.</p>
+ <p>
+ Own Id: OTP-14683</p>
+ </item>
+ <item>
+ <p>There is a new syntax in '<c>try/catch</c>' for
+ retrieving the stacktrace without calling
+ '<c>erlang:get_stacktrace/0</c>'. See the reference
+ manual for a description of the new syntax. The
+ '<c>erlang:get_stacktrace/0</c>' BIF is now
+ deprecated.</p>
+ <p>
+ Own Id: OTP-14692</p>
+ </item>
+ <item>
+ <p>The following is an internal change in the compiler,
+ that is not noticeable for normal use of the compiler:
+ The module <c>v3_life</c> has been removed. Its
+ functionality has been simplified and integrated into
+ <c>v3_codegen</c>.</p>
+ <p>
+ Own Id: OTP-14712</p>
+ </item>
+ <item>
+ <p>The optimization of binary matching that delays
+ creation of sub binaries (see the Efficiency Guide) could
+ be thwarted by the argument order and could be necessary
+ to change the argument order. The compiler has now become
+ smarter and can handle any argument order.</p>
+ <p>
+ Own Id: OTP-14774</p>
+ </item>
+ <item>
+ <p>When the compiler was faced with complex case
+ expressions it would unnecessarily allocate stack
+ elements and shuffle data between x and y registers.
+ Improved code generation to only allocate a stack frame
+ when strictly necessary.</p>
+ <p>
+ Own Id: OTP-14808 Aux Id: ERL-514 </p>
+ </item>
+ <item>
+ <p>There is a new option '<c>makedep_side_effect</c>' for
+ the compiler and <c>-MMD</c> for '<c>erlc</c>' that
+ generates dependencies and continues to compile as
+ normal.</p>
+ <p>
+ Own Id: OTP-14830</p>
+ </item>
+ <item>
+ <p>When compiling modules with huge functions, the
+ compiler would generate a lot of atoms for its internal,
+ sometimes so many that the atom table would overflow. The
+ compiler has been rewritten to generate far less internal
+ atoms to avoid filling the atom table.</p>
+ <p>
+ Own Id: OTP-14968 Aux Id: ERL-563 </p>
+ </item>
+ <item>
+ <p>External funs with literal values for module, name,
+ and arity (e.g. <c>erlang:abs/1</c>) are now treated as
+ literals. That means more efficient code that produces
+ less garbage on the heap.</p>
+ <p>
+ Own Id: OTP-15003</p>
+ </item>
+ <item>
+ <p>Two new guards BIFs operating on maps have been added:
+ <c>map_get/2</c> and <c>is_map_key/2</c>. They do the
+ same as <c>maps:get/2</c> and <c>maps:is_key/2</c>,
+ respectively, except that they are allowed to be used in
+ guards.</p>
+ <p>
+ Own Id: OTP-15037 Aux Id: PR-1784, PR-1802 </p>
+ </item>
+ <item>
+ <p>A call or apply of a literal external fun will be
+ replaced with a direct call.</p>
+ <p>
+ Own Id: OTP-15044 Aux Id: ERL-614 </p>
+ </item>
+ <item>
+ <p>Part of EEP-44 has been implemented.</p>
+ <p>There is a new predefined macro called
+ <c>OTP_RELEASE</c> which is an integer indicating the OTP
+ release number (its value is <c>21</c> in this
+ release).</p>
+ <p>There are new preprocessor directives
+ <c>-if(Condition).</c> and <c>-elif(Condition).</c>. The
+ <c>if/elif</c> supports the builtin function
+ <c>defined(Symbol)</c>.</p>
+ <p>
+ Own Id: OTP-15087 Aux Id: PR-1810 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.1.5.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed an issue where files compiled with the
+ <c>+deterministic</c> option differed if they were
+ compiled in a different directory but were otherwise
+ identical.</p>
+ <p>
+ Own Id: OTP-15204 Aux Id: ERL-679 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Compiler 7.1.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/compiler/src/Makefile b/lib/compiler/src/Makefile
index c81b81e82b..2408c76b48 100644
--- a/lib/compiler/src/Makefile
+++ b/lib/compiler/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2017. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/beam_a.erl b/lib/compiler/src/beam_a.erl
index 91acb19971..6fd4ace540 100644
--- a/lib/compiler/src/beam_a.erl
+++ b/lib/compiler/src/beam_a.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/beam_asm.erl b/lib/compiler/src/beam_asm.erl
index 5ef340c831..df0321e85a 100644
--- a/lib/compiler/src/beam_asm.erl
+++ b/lib/compiler/src/beam_asm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -475,7 +475,7 @@ encode_alloc_list_1([{floats,Floats}|T], Dict, Acc0) ->
encode_alloc_list_1([], Dict, Acc) ->
{iolist_to_binary(Acc),Dict}.
--spec encode(non_neg_integer(), integer()) -> iodata().
+-spec encode(non_neg_integer(), integer()) -> iolist() | integer().
encode(Tag, N) when N < 0 ->
encode1(Tag, negative_to_bytes(N));
diff --git a/lib/compiler/src/beam_block.erl b/lib/compiler/src/beam_block.erl
index 8cd271e1dc..fe43163455 100644
--- a/lib/compiler/src/beam_block.erl
+++ b/lib/compiler/src/beam_block.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/beam_bs.erl b/lib/compiler/src/beam_bs.erl
index 14cedbb582..5f1b9ed488 100644
--- a/lib/compiler/src/beam_bs.erl
+++ b/lib/compiler/src/beam_bs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/beam_bsm.erl b/lib/compiler/src/beam_bsm.erl
index 9f3b9d788f..abc6e96c85 100644
--- a/lib/compiler/src/beam_bsm.erl
+++ b/lib/compiler/src/beam_bsm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -310,7 +310,18 @@ btb_reaches_match_2([{test,bs_start_match2,{f,F},Live,[Bin,_],Ctx}|Is],
end;
btb_reaches_match_2([{test,_,{f,F},Ss}=I|Is], Regs, D0) ->
btb_ensure_not_used(Ss, I, Regs),
- D = btb_follow_branch(F, Regs, D0),
+ D1 = btb_follow_branch(F, Regs, D0),
+ D = case Is of
+ [{bs_context_to_binary,_}|_] ->
+ %% bs_context_to_binary following a test instruction
+ %% probably needs the current position to be saved as
+ %% the new start position, but we can't be sure.
+ %% Therefore, conservatively disable the optimization
+ %% (instead of forcing a saving of the position).
+ D1#btb{must_save=true,must_not_save=true};
+ _ ->
+ D1
+ end,
btb_reaches_match_1(Is, Regs, D);
btb_reaches_match_2([{test,_,{f,F},_,Ss,_}=I|Is], Regs, D0) ->
btb_ensure_not_used(Ss, I, Regs),
diff --git a/lib/compiler/src/beam_clean.erl b/lib/compiler/src/beam_clean.erl
index 955c128699..207f1c4deb 100644
--- a/lib/compiler/src/beam_clean.erl
+++ b/lib/compiler/src/beam_clean.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/beam_dead.erl b/lib/compiler/src/beam_dead.erl
index 762c7bdf9e..efad082152 100644
--- a/lib/compiler/src/beam_dead.erl
+++ b/lib/compiler/src/beam_dead.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/beam_disasm.erl b/lib/compiler/src/beam_disasm.erl
index a68c4b5367..6cee9acae4 100644
--- a/lib/compiler/src/beam_disasm.erl
+++ b/lib/compiler/src/beam_disasm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/beam_disasm.hrl b/lib/compiler/src/beam_disasm.hrl
index c3326c15a0..e8ebfc4cfc 100644
--- a/lib/compiler/src/beam_disasm.hrl
+++ b/lib/compiler/src/beam_disasm.hrl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/beam_except.erl b/lib/compiler/src/beam_except.erl
index abd39c661d..05c0f4fbc7 100644
--- a/lib/compiler/src/beam_except.erl
+++ b/lib/compiler/src/beam_except.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/beam_flatten.erl b/lib/compiler/src/beam_flatten.erl
index c60211f516..20bd23a912 100644
--- a/lib/compiler/src/beam_flatten.erl
+++ b/lib/compiler/src/beam_flatten.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/beam_jump.erl b/lib/compiler/src/beam_jump.erl
index c33de217bd..43084ad588 100644
--- a/lib/compiler/src/beam_jump.erl
+++ b/lib/compiler/src/beam_jump.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -164,17 +164,19 @@ share(Is0) ->
share_1([{label,L}=Lbl|Is], Dict0, Lbls0, [_|_]=Seq, Acc) ->
case maps:find(Seq, Dict0) of
- error ->
- Dict = maps:put(Seq, L, Dict0),
- share_1(Is, Dict, Lbls0, [], [Lbl|Seq ++ Acc]);
- {ok,Label} ->
+ error ->
+ Dict = maps:put(Seq, L, Dict0),
+ share_1(Is, Dict, Lbls0, [], [[Lbl|Seq]|Acc]);
+ {ok,Label} ->
Lbls = maps:put(L, Label, Lbls0),
- share_1(Is, Dict0, Lbls, [], [Lbl,{jump,{f,Label}}|Acc])
+ share_1(Is, Dict0, Lbls, [], [[Lbl,{jump,{f,Label}}]|Acc])
end;
-share_1([{func_info,_,_,_}|_]=Is, _, Lbls, [], Acc) when Lbls =/= #{} ->
- beam_utils:replace_labels(Acc, Is, Lbls, fun(Old) -> Old end);
+share_1([{func_info,_,_,_}|_]=Is0, _, Lbls, [], Acc0) when Lbls =/= #{} ->
+ lists:foldl(fun(Is, Acc) ->
+ beam_utils:replace_labels(Is, Acc, Lbls, fun(Old) -> Old end)
+ end, Is0, Acc0);
share_1([{func_info,_,_,_}|_]=Is, _, Lbls, [], Acc) when Lbls =:= #{} ->
- reverse(Acc, Is);
+ lists:foldl(fun lists:reverse/2, Is, Acc);
share_1([{'catch',_,_}=I|Is], Dict0, Lbls0, Seq, Acc) ->
{Dict,Lbls} = clean_non_sharable(Dict0, Lbls0),
share_1(Is, Dict, Lbls, [I|Seq], Acc);
@@ -187,6 +189,9 @@ share_1([{try_case,_}=I|Is], Dict0, Lbls0, Seq, Acc) ->
share_1([{catch_end,_}=I|Is], Dict0, Lbls0, Seq, Acc) ->
{Dict,Lbls} = clean_non_sharable(Dict0, Lbls0),
share_1(Is, Dict, Lbls, [I|Seq], Acc);
+share_1([{jump,{f,To}}=I,{label,L}=Lbl|Is], Dict0, Lbls0, _Seq, Acc) ->
+ Lbls = maps:put(L, To, Lbls0),
+ share_1(Is, Dict0, Lbls, [], [[Lbl,I]|Acc]);
share_1([I|Is], Dict, Lbls, Seq, Acc) ->
case is_unreachable_after(I) of
false ->
diff --git a/lib/compiler/src/beam_listing.erl b/lib/compiler/src/beam_listing.erl
index 73c6501fe5..518b958794 100644
--- a/lib/compiler/src/beam_listing.erl
+++ b/lib/compiler/src/beam_listing.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/beam_peep.erl b/lib/compiler/src/beam_peep.erl
index 920fb00397..2b8dd40e29 100644
--- a/lib/compiler/src/beam_peep.erl
+++ b/lib/compiler/src/beam_peep.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/beam_receive.erl b/lib/compiler/src/beam_receive.erl
index 3c8efa577c..ddbe67605a 100644
--- a/lib/compiler/src/beam_receive.erl
+++ b/lib/compiler/src/beam_receive.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/beam_reorder.erl b/lib/compiler/src/beam_reorder.erl
index 63bb57a1ac..8d2ef5a431 100644
--- a/lib/compiler/src/beam_reorder.erl
+++ b/lib/compiler/src/beam_reorder.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/beam_split.erl b/lib/compiler/src/beam_split.erl
index 52dd89b5bb..809e49b3d0 100644
--- a/lib/compiler/src/beam_split.erl
+++ b/lib/compiler/src/beam_split.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/beam_type.erl b/lib/compiler/src/beam_type.erl
index 12da8c9446..b5c979e529 100644
--- a/lib/compiler/src/beam_type.erl
+++ b/lib/compiler/src/beam_type.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -559,7 +559,7 @@ update({bs_save2,_,_}, Ts) ->
update({bs_restore2,_,_}, Ts) ->
Ts;
update({bs_context_to_binary,Dst}, Ts) ->
- tdb_store(Dst, {binary,1}, Ts);
+ tdb_store(Dst, any, Ts);
update({test,bs_start_match2,_,_,[Src,_],Dst}, Ts0) ->
Ts = tdb_meet(Src, {binary,1}, Ts0),
tdb_copy(Src, Dst, Ts);
diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl
index f57a7af1ab..5580d2f123 100644
--- a/lib/compiler/src/beam_utils.erl
+++ b/lib/compiler/src/beam_utils.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -355,6 +355,9 @@ split_even(Rs) -> split_even(Rs, [], []).
%% exit BIF will raise an exception
%% used - Reg is used
+check_liveness({fr,_}, _, St) ->
+ %% Conservatively always consider the floating point register used.
+ {used,St};
check_liveness(R, [{block,Blk}|Is], St0) ->
case check_liveness_block(R, Blk, St0) of
{transparent,St1} ->
@@ -1105,8 +1108,12 @@ defs([{bif,_,{f,Fail},_Src,Dst}=I|Is], Regs0, D) ->
defs([{block,Block0}|Is], Regs0, D0) ->
{Block,Regs,D} = defs_list(Block0, Regs0, D0),
[{block,[make_anno({def,Regs0})|Block]}|defs(Is, Regs, D)];
-defs([{bs_init,{f,L},_,_,_,Dst}=I|Is], Regs0, D) ->
- Regs = def_regs([Dst], Regs0),
+defs([{bs_init,{f,L},_,Live,_,Dst}=I|Is], Regs0, D) ->
+ Regs1 = case Live of
+ none -> Regs0;
+ _ -> init_def_regs(Live)
+ end,
+ Regs = def_regs([Dst], Regs1),
[I|defs(Is, Regs, update_regs(L, Regs, D))];
defs([{bs_put,{f,L},_,_}=I|Is], Regs, D) ->
[I|defs(Is, Regs, update_regs(L, Regs, D))];
@@ -1157,7 +1164,7 @@ defs([{loop_rec,{f,L},{x,0}}=I|Is], _Regs, D0) ->
D = update_regs(L, RegsAtLabel, D0),
[I|defs(Is, init_def_regs(1), D)];
defs([{loop_rec_end,_}=I|Is], _Regs, D) ->
- [I|defs(Is, 0, D)];
+ [I|defs_unreachable(Is, D)];
defs([{make_fun2,_,_,_,_}=I|Is], _Regs, D) ->
[I|defs(Is, 1, D)];
defs([{move,_,Dst}=I|Is], Regs0, D) ->
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index 86aa12e19b..c09dbadd7f 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -280,7 +280,7 @@ valfun_1({try_case_end,Src}, Vst) ->
verify_y_init(Vst),
assert_term(Src, Vst),
kill_state(Vst);
-%% Instructions that can not cause exceptions
+%% Instructions that cannot cause exceptions
valfun_1({bs_context_to_binary,Ctx}, #vst{current=#st{x=Xs}}=Vst) ->
case Ctx of
{Tag,X} when Tag =:= x; Tag =:= y ->
@@ -451,6 +451,19 @@ valfun_1({try_case,Reg}, #vst{current=#st{ct=[Fail|Fails]}}=Vst0) ->
Type ->
error({bad_type,Type})
end;
+valfun_1({get_list,Src,D1,D2}, Vst0) ->
+ assert_type(cons, Src, Vst0),
+ Vst = set_type_reg(term, Src, D1, Vst0),
+ set_type_reg(term, Src, D2, Vst);
+valfun_1({get_hd,Src,Dst}, Vst) ->
+ assert_type(cons, Src, Vst),
+ set_type_reg(term, Src, Dst, Vst);
+valfun_1({get_tl,Src,Dst}, Vst) ->
+ assert_type(cons, Src, Vst),
+ set_type_reg(term, Src, Dst, Vst);
+valfun_1({get_tuple_element,Src,I,Dst}, Vst) ->
+ assert_type({tuple_element,I+1}, Src, Vst),
+ set_type_reg(term, Src, Dst, Vst);
valfun_1(I, Vst) ->
valfun_2(I, Vst).
@@ -546,6 +559,12 @@ valfun_4({bif,raise,{f,0},Src,_Dst}, Vst) ->
kill_state(Vst);
valfun_4(raw_raise=I, Vst) ->
call(I, 3, Vst);
+valfun_4({bif,map_get,{f,Fail},[_Key,Map]=Src,Dst}, Vst0) ->
+ validate_src(Src, Vst0),
+ Vst1 = branch_state(Fail, Vst0),
+ Vst = set_type(map, Map, Vst1),
+ Type = propagate_fragility(term, Src, Vst),
+ set_type_reg(Type, Dst, Vst);
valfun_4({bif,Op,{f,Fail},Src,Dst}, Vst0) ->
validate_src(Src, Vst0),
Vst = branch_state(Fail, Vst0),
@@ -603,19 +622,6 @@ valfun_4({select_val,Src,{f,Fail},{list,Choices}}, Vst) ->
valfun_4({select_tuple_arity,Tuple,{f,Fail},{list,Choices}}, Vst) ->
assert_type(tuple, Tuple, Vst),
kill_state(branch_arities(Choices, Tuple, branch_state(Fail, Vst)));
-valfun_4({get_list,Src,D1,D2}, Vst0) ->
- assert_type(cons, Src, Vst0),
- Vst = set_type_reg(term, Src, D1, Vst0),
- set_type_reg(term, Src, D2, Vst);
-valfun_4({get_hd,Src,Dst}, Vst) ->
- assert_type(cons, Src, Vst),
- set_type_reg(term, Src, Dst, Vst);
-valfun_4({get_tl,Src,Dst}, Vst) ->
- assert_type(cons, Src, Vst),
- set_type_reg(term, Src, Dst, Vst);
-valfun_4({get_tuple_element,Src,I,Dst}, Vst) ->
- assert_type({tuple_element,I+1}, Src, Vst),
- set_type_reg(term, Src, Dst, Vst);
%% New bit syntax matching instructions.
valfun_4({test,bs_start_match2,{f,Fail},Live,[Ctx,NeedSlots],Ctx}, Vst0) ->
diff --git a/lib/compiler/src/beam_z.erl b/lib/compiler/src/beam_z.erl
index 6c3a6995d7..1c9d762eb1 100644
--- a/lib/compiler/src/beam_z.erl
+++ b/lib/compiler/src/beam_z.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index c6a0056a70..e1c1f7338e 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -295,7 +295,7 @@ format_error_reason({Reason, Stack}) when is_list(Stack) ->
end,
FormatFun = fun (Term, _) -> io_lib:format("~tp", [Term]) end,
[io_lib:format("~tp", [Reason]),"\n\n",
- lib:format_stacktrace(1, Stack, StackFun, FormatFun)];
+ erl_error:format_stacktrace(1, Stack, StackFun, FormatFun)];
format_error_reason(Reason) ->
io_lib:format("~tp", [Reason]).
@@ -1432,16 +1432,30 @@ encrypt_debug_info(DebugInfo, Key, Opts) ->
end.
cleanup_compile_options(Opts) ->
- lists:filter(fun keep_compile_option/1, Opts).
-
+ IsDeterministic = lists:member(deterministic, Opts),
+ lists:filter(fun(Opt) ->
+ keep_compile_option(Opt, IsDeterministic)
+ end, Opts).
+
+%% Include paths and current directory don't affect compilation, but they might
+%% be helpful so we include them unless we're doing a deterministic build.
+keep_compile_option({i, _}, Deterministic) ->
+ not Deterministic;
+keep_compile_option({cwd, _}, Deterministic) ->
+ not Deterministic;
%% We are storing abstract, not asm or core.
-keep_compile_option(from_asm) -> false;
-keep_compile_option(from_core) -> false;
+keep_compile_option(from_asm, _Deterministic) ->
+ false;
+keep_compile_option(from_core, _Deterministic) ->
+ false;
%% Parse transform and macros have already been applied.
-keep_compile_option({parse_transform, _}) -> false;
-keep_compile_option({d, _, _}) -> false;
+keep_compile_option({parse_transform, _}, _Deterministic) ->
+ false;
+keep_compile_option({d, _, _}, _Deterministic) ->
+ false;
%% Do not affect compilation result on future calls.
-keep_compile_option(Option) -> effects_code_generation(Option).
+keep_compile_option(Option, _Deterministic) ->
+ effects_code_generation(Option).
start_crypto() ->
try crypto:start() of
@@ -1589,6 +1603,7 @@ effects_code_generation(Option) ->
binary -> false;
verbose -> false;
{cwd,_} -> false;
+ {i,_} -> false;
{outdir, _} -> false;
_ -> true
end.
diff --git a/lib/compiler/src/core_lint.erl b/lib/compiler/src/core_lint.erl
index 6ded8fe78f..3f69cb03a9 100644
--- a/lib/compiler/src/core_lint.erl
+++ b/lib/compiler/src/core_lint.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/core_parse.yrl b/lib/compiler/src/core_parse.yrl
index 11c4cd8b50..10d8c44dd3 100644
--- a/lib/compiler/src/core_parse.yrl
+++ b/lib/compiler/src/core_parse.yrl
@@ -1,7 +1,7 @@
%% -*-Erlang-*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/core_pp.erl b/lib/compiler/src/core_pp.erl
index f247722b4c..cb3f24fd08 100644
--- a/lib/compiler/src/core_pp.erl
+++ b/lib/compiler/src/core_pp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/erl_bifs.erl b/lib/compiler/src/erl_bifs.erl
index a7452aebc8..71ab0e872a 100644
--- a/lib/compiler/src/erl_bifs.erl
+++ b/lib/compiler/src/erl_bifs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -91,6 +91,7 @@ is_pure(erlang, is_bitstring, 1) -> true;
%% erlang:is_builtin/3 depends on the state (i.e. the version of the emulator).
is_pure(erlang, is_float, 1) -> true;
is_pure(erlang, is_function, 1) -> true;
+is_pure(erlang, is_function, 2) -> true;
is_pure(erlang, is_integer, 1) -> true;
is_pure(erlang, is_list, 1) -> true;
is_pure(erlang, is_map, 1) -> true;
diff --git a/lib/compiler/src/genop.tab b/lib/compiler/src/genop.tab
index a47d4e8cf7..f35ae09fe7 100755
--- a/lib/compiler/src/genop.tab
+++ b/lib/compiler/src/genop.tab
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1998-2017. All Rights Reserved.
+# Copyright Ericsson AB 1998-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -142,8 +142,7 @@ BEAM_FORMAT_NUMBER=0
20: send/0
## @spec remove_message
-## @doc Unlink the current message from the message queue and store a
-## pointer to the message in x(0). Remove any timeout.
+## @doc Unlink the current message from the message queue. Remove any timeout.
21: remove_message/0
## @spec timeout
diff --git a/lib/compiler/src/sys_core_alias.erl b/lib/compiler/src/sys_core_alias.erl
index 1bce1577d1..3326c6a2a8 100644
--- a/lib/compiler/src/sys_core_alias.erl
+++ b/lib/compiler/src/sys_core_alias.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/sys_core_bsm.erl b/lib/compiler/src/sys_core_bsm.erl
index 65580f79e3..d7b26c3a56 100644
--- a/lib/compiler/src/sys_core_bsm.erl
+++ b/lib/compiler/src/sys_core_bsm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/sys_core_dsetel.erl b/lib/compiler/src/sys_core_dsetel.erl
index 9e2df69b33..9ab83c210f 100644
--- a/lib/compiler/src/sys_core_dsetel.erl
+++ b/lib/compiler/src/sys_core_dsetel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index a13bdedaf9..d848cd8f19 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -99,7 +99,7 @@
t=#{} :: map(), %Types
in_guard=false}). %In guard or not.
--type type_info() :: cerl:cerl() | 'bool' | 'integer'.
+-type type_info() :: cerl:cerl() | 'bool' | 'integer' | {'fun', pos_integer()}.
-type yes_no_maybe() :: 'yes' | 'no' | 'maybe'.
-type sub() :: #sub{}.
@@ -115,13 +115,6 @@ module(#c_module{defs=Ds0}=Mod, Opts) ->
{ok,Mod#c_module{defs=Ds1},get_warnings()}.
function_1({#c_var{name={F,Arity}}=Name,B0}) ->
- %% Find a suitable starting value for the variable counter. Note
- %% that this pass assumes that new_var_name/1 returns a variable
- %% name distinct from any variable used in the entire body of
- %% the function. We use integers as variable names to avoid
- %% filling up the atom table when compiling huge functions.
- Count = cerl_trees:next_free_variable_name(B0),
- put(new_var_num, Count),
try
%% Find a suitable starting value for the variable
%% counter. Note that this pass assumes that new_var_name/1
@@ -352,7 +345,12 @@ expr(#c_letrec{body=#c_var{}}=Letrec, effect, _Sub) ->
void();
expr(#c_letrec{defs=Fs0,body=B0}=Letrec, Ctxt, Sub) ->
Fs1 = map(fun ({Name,Fb}) ->
- {Name,expr(Fb, {letrec,Ctxt}, Sub)}
+ case Ctxt =:= effect andalso is_fun_effect_safe(Name, B0) of
+ true ->
+ {Name,expr(Fb, {letrec, effect}, Sub)};
+ false ->
+ {Name,expr(Fb, {letrec, value}, Sub)}
+ end
end, Fs0),
B1 = body(B0, Ctxt, Sub),
Letrec#c_letrec{defs=Fs1,body=B1};
@@ -480,9 +478,101 @@ expr(#c_try{anno=A,arg=E0,vars=Vs0,body=B0,evars=Evs0,handler=H0}=Try, _, Sub0)
false ->
{Evs1,Sub2} = var_list(Evs0, Sub0),
H1 = body(H0, value, Sub2),
- Try#c_try{arg=E1,vars=Vs1,body=B1,evars=Evs1,handler=H1}
+ H2 = opt_try_handler(H1, lists:last(Evs1)),
+ Try#c_try{arg=E1,vars=Vs1,body=B1,evars=Evs1,handler=H2}
end.
+%% Attempts to convert old erlang:get_stacktrace/0 calls into the new
+%% three-argument catch, with possibility of further optimisations.
+opt_try_handler(#c_call{anno=A,module=#c_literal{val=erlang},name=#c_literal{val=get_stacktrace},args=[]}, Var) ->
+ #c_primop{anno=A,name=#c_literal{val=build_stacktrace},args=[Var]};
+opt_try_handler(#c_case{clauses=Cs0} = Case, Var) ->
+ Cs = [C#c_clause{body=opt_try_handler(B, Var)} || #c_clause{body=B} = C <- Cs0],
+ Case#c_case{clauses=Cs};
+opt_try_handler(#c_let{arg=Arg} = Let, Var) ->
+ Let#c_let{arg=opt_try_handler(Arg, Var)};
+opt_try_handler(X, _) -> X.
+
+%% If a fun or its application is used as an argument, then it's unsafe to
+%% handle it in effect context as the side-effects may rely on its return
+%% value. The following is a minimal example of where it can go wrong:
+%%
+%% do letrec 'f'/0 = fun () -> ... whatever ...
+%% in call 'side':'effect'(apply 'f'/0())
+%% 'ok'
+%%
+%% This function returns 'true' if Body definitely does not rely on a
+%% value produced by FVar, or 'false' if Body depends on or might depend on
+%% a value produced by FVar.
+
+is_fun_effect_safe(#c_var{}=FVar, Body) ->
+ ifes_1(FVar, Body, true).
+
+ifes_1(FVar, #c_alias{pat=Pat}, _Safe) ->
+ ifes_1(FVar, Pat, false);
+ifes_1(FVar, #c_apply{op=Op,args=Args}, Safe) ->
+ %% FVar(...) is safe as long its return value is ignored, but it's never
+ %% okay to pass FVar as an argument.
+ ifes_list(FVar, Args, false) andalso ifes_1(FVar, Op, Safe);
+ifes_1(FVar, #c_binary{segments=Segments}, _Safe) ->
+ ifes_list(FVar, Segments, false);
+ifes_1(FVar, #c_bitstr{val=Val,size=Size,unit=Unit}, _Safe) ->
+ ifes_list(FVar, [Val, Size, Unit], false);
+ifes_1(FVar, #c_call{args=Args}, _Safe) ->
+ ifes_list(FVar, Args, false);
+ifes_1(FVar, #c_case{arg=Arg,clauses=Clauses}, Safe) ->
+ ifes_1(FVar, Arg, false) andalso ifes_list(FVar, Clauses, Safe);
+ifes_1(FVar, #c_catch{body=Body}, _Safe) ->
+ ifes_1(FVar, Body, false);
+ifes_1(FVar, #c_clause{pats=Pats,guard=Guard,body=Body}, Safe) ->
+ ifes_list(FVar, Pats, false) andalso
+ ifes_1(FVar, Guard, false) andalso
+ ifes_1(FVar, Body, Safe);
+ifes_1(FVar, #c_cons{hd=Hd,tl=Tl}, _Safe) ->
+ ifes_1(FVar, Hd, false) andalso ifes_1(FVar, Tl, false);
+ifes_1(FVar, #c_fun{body=Body}, _Safe) ->
+ ifes_1(FVar, Body, false);
+ifes_1(FVar, #c_let{arg=Arg,body=Body}, Safe) ->
+ ifes_1(FVar, Arg, false) andalso ifes_1(FVar, Body, Safe);
+ifes_1(FVar, #c_letrec{defs=Defs,body=Body}, Safe) ->
+ Funs = [Fun || {_,Fun} <- Defs],
+ ifes_list(FVar, Funs, false) andalso ifes_1(FVar, Body, Safe);
+ifes_1(_FVar, #c_literal{}, _Safe) ->
+ true;
+ifes_1(FVar, #c_map{arg=Arg,es=Elements}, _Safe) ->
+ ifes_1(FVar, Arg, false) andalso ifes_list(FVar, Elements, false);
+ifes_1(FVar, #c_map_pair{key=Key,val=Val}, _Safe) ->
+ ifes_1(FVar, Key, false) andalso ifes_1(FVar, Val, false);
+ifes_1(FVar, #c_primop{args=Args}, _Safe) ->
+ ifes_list(FVar, Args, false);
+ifes_1(FVar, #c_receive{timeout=Timeout,action=Action,clauses=Clauses}, Safe) ->
+ ifes_1(FVar, Timeout, false) andalso
+ ifes_1(FVar, Action, Safe) andalso
+ ifes_list(FVar, Clauses, Safe);
+ifes_1(FVar, #c_seq{arg=Arg,body=Body}, Safe) ->
+ %% Arg of a #c_seq{} has no effect so it's okay to use FVar there even if
+ %% Safe=false.
+ ifes_1(FVar, Arg, true) andalso ifes_1(FVar, Body, Safe);
+ifes_1(FVar, #c_try{arg=Arg,handler=Handler,body=Body}, Safe) ->
+ ifes_1(FVar, Arg, false) andalso
+ ifes_1(FVar, Handler, Safe) andalso
+ ifes_1(FVar, Body, Safe);
+ifes_1(FVar, #c_tuple{es=Elements}, _Safe) ->
+ ifes_list(FVar, Elements, false);
+ifes_1(FVar, #c_values{es=Elements}, _Safe) ->
+ ifes_list(FVar, Elements, false);
+ifes_1(#c_var{name=Name}, #c_var{name=Name}, Safe) ->
+ %% It's safe to return FVar if it's unused.
+ Safe;
+ifes_1(_FVar, #c_var{}, _Safe) ->
+ true.
+
+ifes_list(FVar, [E|Es], Safe) ->
+ ifes_1(FVar, E, Safe) andalso ifes_list(FVar, Es, Safe);
+ifes_list(_FVar, [], _Safe) ->
+ true.
+
+
expr_list(Es, Ctxt, Sub) ->
[expr(E, Ctxt, Sub) || E <- Es].
@@ -883,6 +973,10 @@ fold_non_lit_args(Call, erlang, setelement, [Arg1,Arg2,Arg3], _) ->
eval_setelement(Call, Arg1, Arg2, Arg3);
fold_non_lit_args(Call, erlang, is_record, [Arg1,Arg2,Arg3], Sub) ->
eval_is_record(Call, Arg1, Arg2, Arg3, Sub);
+fold_non_lit_args(Call, erlang, is_function, [Arg1], Sub) ->
+ eval_is_function_1(Call, Arg1, Sub);
+fold_non_lit_args(Call, erlang, is_function, [Arg1,Arg2], Sub) ->
+ eval_is_function_2(Call, Arg1, Arg2, Sub);
fold_non_lit_args(Call, erlang, N, Args, Sub) ->
NumArgs = length(Args),
case erl_internal:comp_op(N, NumArgs) of
@@ -898,6 +992,22 @@ fold_non_lit_args(Call, erlang, N, Args, Sub) ->
end;
fold_non_lit_args(Call, _, _, _, _) -> Call.
+eval_is_function_1(Call, Arg1, Sub) ->
+ case get_type(Arg1, Sub) of
+ none -> Call;
+ {'fun',_} -> #c_literal{anno=cerl:get_ann(Call),val=true};
+ _ -> #c_literal{anno=cerl:get_ann(Call),val=false}
+ end.
+
+eval_is_function_2(Call, Arg1, #c_literal{val=Arity}, Sub)
+ when is_integer(Arity), Arity > 0 ->
+ case get_type(Arg1, Sub) of
+ none -> Call;
+ {'fun',Arity} -> #c_literal{anno=cerl:get_ann(Call),val=true};
+ _ -> #c_literal{anno=cerl:get_ann(Call),val=false}
+ end;
+eval_is_function_2(Call, _Arg1, _Arg2, _Sub) -> Call.
+
%% Evaluate a relational operation using type information.
eval_rel_op(Call, Op, [#c_var{name=V},#c_var{name=V}], _) ->
Bool = erlang:Op(same, same),
@@ -1275,13 +1385,18 @@ let_subst_list([], [], _) -> {[],[],[]}.
%%pattern(Pat, Sub) -> pattern(Pat, Sub, Sub).
pattern(#c_var{}=Pat, Isub, Osub) ->
- case sub_is_val(Pat, Isub) of
+ case sub_is_in_scope(Pat, Isub) of
true ->
+ %% This variable either has a substitution or is used in
+ %% the variable list of an enclosing `let`. In either
+ %% case, it must be renamed to an unused name to avoid
+ %% name capture problems.
V1 = make_var_name(),
Pat1 = #c_var{name=V1},
{Pat1,sub_set_var(Pat, Pat1, sub_add_scope([V1], Osub))};
false ->
- {Pat,sub_del_var(Pat, Osub)}
+ %% This variable has never been used. Add it to the scope.
+ {Pat,sub_add_scope([Pat#c_var.name], Osub)}
end;
pattern(#c_literal{}=Pat, _, Osub) -> {Pat,Osub};
pattern(#c_cons{anno=Anno,hd=H0,tl=T0}, Isub, Osub0) ->
@@ -1460,8 +1575,8 @@ is_subst(_) -> false.
%% sub_set_name(Name, Value, #sub{}) -> #sub{}.
%% sub_del_var(Var, #sub{}) -> #sub{}.
%% sub_subst_var(Var, Value, #sub{}) -> [{Name,Value}].
-%% sub_is_val(Var, #sub{}) -> boolean().
-%% sub_add_scope(#sub{}) -> #sub{}
+%% sub_is_in_scope(Var, #sub{}) -> boolean().
+%% sub_add_scope([Var], #sub{}) -> #sub{}
%% sub_subst_scope(#sub{}) -> #sub{}
%%
%% We use the variable name as key so as not have problems with
@@ -1496,18 +1611,6 @@ sub_set_name(V, Val, #sub{v=S,s=Scope,t=Tdb0}=Sub) ->
Tdb = copy_type(V, Val, Tdb1),
Sub#sub{v=orddict:store(V, Val, S),s=cerl_sets:add_element(V, Scope),t=Tdb}.
-sub_del_var(#c_var{name=V}, #sub{v=S,s=Scope,t=Tdb}=Sub) ->
- %% Profiling shows that for programs with many record operations,
- %% sub_del_var/2 is a bottleneck. Since the scope contains all
- %% variables that are live, we know that V cannot be present in S
- %% if it is not in the scope.
- case cerl_sets:is_element(V, Scope) of
- false ->
- Sub#sub{s=cerl_sets:add_element(V, Scope)};
- true ->
- Sub#sub{v=orddict:erase(V, S),t=kill_types(V, Tdb)}
- end.
-
sub_subst_var(#c_var{name=V}, Val, #sub{v=S0}) ->
%% Fold chained substitutions.
[{V,Val}] ++ [ {K,Val} || {K,#c_var{name=V1}} <- S0, V1 =:= V].
@@ -1533,16 +1636,8 @@ sub_subst_scope_1([H|T], Key, Acc) ->
sub_subst_scope_1(T, Key-1, [{Key,#c_var{name=H}}|Acc]);
sub_subst_scope_1([], _, Acc) -> Acc.
-sub_is_val(#c_var{name=V}, #sub{v=S,s=Scope}) ->
- %% When the bottleneck in sub_del_var/2 was eliminated, this
- %% became the new bottleneck. Since the scope contains all
- %% live variables, a variable V can only be the target for
- %% a substitution if it is in the scope.
- cerl_sets:is_element(V, Scope) andalso v_is_value(V, S).
-
-v_is_value(Var, [{_,#c_var{name=Var}}|_]) -> true;
-v_is_value(Var, [_|T]) -> v_is_value(Var, T);
-v_is_value(_, []) -> false.
+sub_is_in_scope(#c_var{name=V}, #sub{s=Scope}) ->
+ cerl_sets:is_element(V, Scope).
%% warn_no_clause_match(CaseOrig, CaseOpt) -> ok
%% Generate a warning if none of the user-specified clauses
@@ -3120,6 +3215,10 @@ update_types_2(V, [#c_tuple{}=P], Types) ->
Types#{V=>P};
update_types_2(V, [#c_literal{val=Bool}], Types) when is_boolean(Bool) ->
Types#{V=>bool};
+update_types_2(V, [#c_fun{vars=Vars}], Types) ->
+ Types#{V=>{'fun',length(Vars)}};
+update_types_2(V, [#c_var{name={_,Arity}}], Types) ->
+ Types#{V=>{'fun',Arity}};
update_types_2(V, [Type], Types) when is_atom(Type) ->
Types#{V=>Type};
update_types_2(_, _, Types) -> Types.
@@ -3138,6 +3237,8 @@ kill_types2(V, [{_,#c_tuple{}=Tuple}=Entry|Tdb]) ->
false -> [Entry|kill_types2(V, Tdb)];
true -> kill_types2(V, Tdb)
end;
+kill_types2(V, [{_, {'fun',_}}=Entry|Tdb]) ->
+ [Entry|kill_types2(V, Tdb)];
kill_types2(V, [{_,Atom}=Entry|Tdb]) when is_atom(Atom) ->
[Entry|kill_types2(V, Tdb)];
kill_types2(_, []) -> [].
diff --git a/lib/compiler/src/sys_core_inline.erl b/lib/compiler/src/sys_core_inline.erl
index 8c1f69d5de..5a6cc45e4a 100644
--- a/lib/compiler/src/sys_core_inline.erl
+++ b/lib/compiler/src/sys_core_inline.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -143,7 +143,7 @@ inline_inline(#ifun{body=B,weight=Iw}=If, Is) ->
case find_inl(F, A, Is) of
#ifun{vars=Vs,body=B2,weight=W} when W < Iw ->
#c_let{vars=Vs,
- arg=core_lib:make_values(As),
+ arg=kill_id_anns(core_lib:make_values(As)),
body=kill_id_anns(B2)};
_Other -> Call
end;
@@ -160,7 +160,7 @@ inline_func(#fstat{def={Name,F0}}=Fstat, Is) ->
case find_inl(F, A, Is) of
#ifun{vars=Vs,body=B} ->
{#c_let{vars=Vs,
- arg=core_lib:make_values(As),
+ arg=kill_id_anns(core_lib:make_values(As)),
body=kill_id_anns(B)},
true}; %Have modified
_Other -> {Call,Mod}
diff --git a/lib/compiler/src/v3_codegen.erl b/lib/compiler/src/v3_codegen.erl
index 9652a8476d..e9152ba88f 100644
--- a/lib/compiler/src/v3_codegen.erl
+++ b/lib/compiler/src/v3_codegen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1621,11 +1621,6 @@ test_cg(is_boolean, [#k_atom{val=Val}], Fail, I, Vdb, Bef, St) ->
false -> [{jump,{f,Fail}}]
end,
{Is,Aft,St};
-test_cg(is_map_key, As, Fail, I, Vdb, Bef, St) ->
- [Key,Map] = cg_reg_args(As, Bef),
- Aft = clear_dead(Bef, I, Vdb),
- F = {f,Fail},
- {[{test,is_map,F,[Map]},{test,has_map_fields,F,Map,{list,[Key]}}],Aft,St};
test_cg(Test, As, Fail, I, Vdb, Bef, St) ->
Args = cg_reg_args(As, Bef),
Aft = clear_dead(Bef, I, Vdb),
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 4799105d05..3b746ab5bf 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1501,7 +1501,7 @@ bc_initial_size(E0, Q, St0) ->
end.
bc_elem_size({bin,_,El}, St0) ->
- case bc_elem_size_1(El, 0, []) of
+ case bc_elem_size_1(El, ordsets:new(), 0, []) of
{Bits,[]} ->
{#c_literal{val=Bits},[],[],St0};
{Bits,Vars0} ->
@@ -1515,19 +1515,33 @@ bc_elem_size(_, _) ->
throw(impossible).
bc_elem_size_1([{bin_element,_,{string,_,String},{integer,_,N},_}=El|Es],
- Bits, Vars) ->
+ DefVars, Bits, SizeVars) ->
U = get_unit(El),
- bc_elem_size_1(Es, Bits+U*N*length(String), Vars);
-bc_elem_size_1([{bin_element,_,_,{integer,_,N},_}=El|Es], Bits, Vars) ->
+ bc_elem_size_1(Es, DefVars, Bits+U*N*length(String), SizeVars);
+bc_elem_size_1([{bin_element,_,Expr,{integer,_,N},_}=El|Es],
+ DefVars0, Bits, SizeVars) ->
U = get_unit(El),
- bc_elem_size_1(Es, Bits+U*N, Vars);
-bc_elem_size_1([{bin_element,_,_,{var,_,Var},_}=El|Es], Bits, Vars) ->
- U = get_unit(El),
- bc_elem_size_1(Es, Bits, [{U,#c_var{name=Var}}|Vars]);
-bc_elem_size_1([_|_], _, _) ->
+ DefVars = bc_elem_size_def_var(Expr, DefVars0),
+ bc_elem_size_1(Es, DefVars, Bits+U*N, SizeVars);
+bc_elem_size_1([{bin_element,_,Expr,{var,_,Src},_}=El|Es],
+ DefVars0, Bits, SizeVars) ->
+ case ordsets:is_element(Src, DefVars0) of
+ false ->
+ U = get_unit(El),
+ DefVars = bc_elem_size_def_var(Expr, DefVars0),
+ bc_elem_size_1(Es, DefVars, Bits, [{U,#c_var{name=Src}}|SizeVars]);
+ true ->
+ throw(impossible)
+ end;
+bc_elem_size_1([_|_], _, _, _) ->
throw(impossible);
-bc_elem_size_1([], Bits, Vars) ->
- {Bits,Vars}.
+bc_elem_size_1([], _DefVars, Bits, SizeVars) ->
+ {Bits,SizeVars}.
+
+bc_elem_size_def_var({var,_,Var}, DefVars) ->
+ ordsets:add_element(Var, DefVars);
+bc_elem_size_def_var(_Expr, DefVars) ->
+ DefVars.
bc_elem_size_combine([{U,V}|T], U, UVars, Acc) ->
bc_elem_size_combine(T, U, [V|UVars], Acc);
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index 4e3ceedbc0..aef0b6cc9f 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/v3_kernel.hrl b/lib/compiler/src/v3_kernel.hrl
index 7cd30b25a8..e6f0d3c1f7 100644
--- a/lib/compiler/src/v3_kernel.hrl
+++ b/lib/compiler/src/v3_kernel.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/src/v3_kernel_pp.erl b/lib/compiler/src/v3_kernel_pp.erl
index e9cbe81088..c12c301ee2 100644
--- a/lib/compiler/src/v3_kernel_pp.erl
+++ b/lib/compiler/src/v3_kernel_pp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/andor_SUITE.erl b/lib/compiler/test/andor_SUITE.erl
index 05c087104d..721f77f0f6 100644
--- a/lib/compiler/test/andor_SUITE.erl
+++ b/lib/compiler/test/andor_SUITE.erl
@@ -29,7 +29,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -38,6 +37,7 @@ groups() ->
combined,in_case,slow_compilation]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/apply_SUITE.erl b/lib/compiler/test/apply_SUITE.erl
index cca92e4713..be49cff9b9 100644
--- a/lib/compiler/test/apply_SUITE.erl
+++ b/lib/compiler/test/apply_SUITE.erl
@@ -29,13 +29,13 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[mfa, fun_apply].
groups() ->
[].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/beam_block_SUITE.erl b/lib/compiler/test/beam_block_SUITE.erl
index 38ead96cc8..40a30b65d7 100644
--- a/lib/compiler/test/beam_block_SUITE.erl
+++ b/lib/compiler/test/beam_block_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,7 +31,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -46,6 +45,7 @@ groups() ->
]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/beam_except_SUITE.erl b/lib/compiler/test/beam_except_SUITE.erl
index 47367d6eab..1eb07c8c85 100644
--- a/lib/compiler/test/beam_except_SUITE.erl
+++ b/lib/compiler/test/beam_except_SUITE.erl
@@ -26,7 +26,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -35,6 +34,7 @@ groups() ->
coverage]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/beam_jump_SUITE.erl b/lib/compiler/test/beam_jump_SUITE.erl
index 088f63606c..488c30919b 100644
--- a/lib/compiler/test/beam_jump_SUITE.erl
+++ b/lib/compiler/test/beam_jump_SUITE.erl
@@ -27,7 +27,6 @@ suite() ->
[{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -37,6 +36,7 @@ groups() ->
]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/beam_reorder_SUITE.erl b/lib/compiler/test/beam_reorder_SUITE.erl
index 27ce51eec3..33b27b9f9f 100644
--- a/lib/compiler/test/beam_reorder_SUITE.erl
+++ b/lib/compiler/test/beam_reorder_SUITE.erl
@@ -26,7 +26,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -36,6 +35,7 @@ groups() ->
]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl
index 541075af2a..061076b3ff 100644
--- a/lib/compiler/test/beam_type_SUITE.erl
+++ b/lib/compiler/test/beam_type_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,12 +23,11 @@
init_per_group/2,end_per_group/2,
integers/1,coverage/1,booleans/1,setelement/1,cons/1,
tuple/1,record_float/1,binary_float/1,float_compare/1,
- arity_checks/1,elixir_binaries/1]).
+ arity_checks/1,elixir_binaries/1,find_best/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -43,10 +42,12 @@ groups() ->
binary_float,
float_compare,
arity_checks,
- elixir_binaries
+ elixir_binaries,
+ find_best
]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -292,6 +293,33 @@ elixir_bitstring_3(Bar) when is_bitstring(Bar) ->
list_to_bitstring(Rewrite)
end/bitstring>>.
+find_best(_Config) ->
+ ok = find_best([a], nil),
+ ok = find_best([<<"a">>], nil),
+ {error,_} = find_best([], nil),
+ ok.
+
+%% Failed because beam_type assumed that the operand
+%% for bs_context_binary must be a binary. Not true!
+find_best([a|Tail], Best) ->
+ find_best(Tail,
+ case Best of
+ X when X =:= nil orelse X =:= false -> a;
+ X -> X
+ end);
+find_best([<<"a">>|Tail], Best) ->
+ find_best(Tail,
+ case Best of
+ X when X =:= nil orelse X =:= false -> <<"a">>;
+ X -> X
+ end);
+find_best([], a) ->
+ ok;
+find_best([], <<"a">>) ->
+ ok;
+find_best([], nil) ->
+ {error,<<"should not get here">>}.
+
id(I) ->
I.
diff --git a/lib/compiler/test/beam_utils_SUITE.erl b/lib/compiler/test/beam_utils_SUITE.erl
index b2a5cada3d..ac19305d69 100644
--- a/lib/compiler/test/beam_utils_SUITE.erl
+++ b/lib/compiler/test/beam_utils_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,13 +25,13 @@
is_not_killed/1,is_not_used_at/1,
select/1,y_catch/1,otp_8949_b/1,liveopt/1,coverage/1,
y_registers/1,user_predef/1,scan_f/1,cafu/1,
- receive_label/1,read_size_file_version/1,not_used/1]).
+ receive_label/1,read_size_file_version/1,not_used/1,
+ is_used_fr/1]).
-export([id/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -52,10 +52,12 @@ groups() ->
scan_f,
cafu,
read_size_file_version,
- not_used
+ not_used,
+ is_used_fr
]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -132,6 +134,15 @@ bs_init(_Config) ->
<<"foo/foo">> = do_bs_init_4(<<"foo">>, true),
error = do_bs_init_4([], not_boolean),
+ Id = 17575,
+ Domain = -8798798,
+ [<<10,1:16,Id:16/signed>>,<<8,2:16,Domain:32/signed>>] =
+ do_bs_init_5(#{tag=>value,id=>Id,domain=>Domain}),
+ {'EXIT',{{required,id},[_|_]}} =
+ (catch do_bs_init_5(#{tag=>value,id=>nil,domain=>Domain})),
+ {'EXIT',{{required,domain},[_|_]}} =
+ (catch do_bs_init_5(#{tag=>value,id=>Id,domain=>nil})),
+
ok.
do_bs_init_1([?MODULE], Sz) ->
@@ -189,6 +200,20 @@ do_bs_init_4(Arg1, Arg2) ->
error
end.
+do_bs_init_5(#{tag := value, id := Id, domain := Domain}) ->
+ [case Id of
+ nil ->
+ error(id({required, id}));
+ _ ->
+ <<10, 1:16/signed, Id:16/signed>>
+ end,
+ case Domain of
+ nil ->
+ error(id({required, domain}));
+ _ ->
+ <<8, 2:16/signed, Domain:32/signed>>
+ end].
+
bs_save(_Config) ->
{a,30,<<>>} = do_bs_save(<<1:1,30:5>>),
{b,127,<<>>} = do_bs_save(<<1:1,31:5,0:1,127:7>>),
@@ -527,5 +552,24 @@ not_used_p(_C, S, K, L) when is_record(K, k) ->
id(K)
end.
+is_used_fr(Config) ->
+ 1 = is_used_fr(self(), self()),
+ 1 = is_used_fr(self(), other),
+ receive 1 -> ok end,
+ receive 1 -> ok end,
+ receive 1 -> ok end,
+ receive 1 -> ok end,
+ ok.
+
+is_used_fr(X, Y) ->
+ %% beam_utils:is_used({fr,R}, Code) would crash.
+ _ = 0 / (X ! 1),
+ _ = case Y of
+ X -> ok;
+ _ -> error
+ end,
+ X ! 1.
+
+
%% The identity function.
id(I) -> I.
diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl
index 41f2957dc1..d3e544a9cc 100644
--- a/lib/compiler/test/beam_validator_SUITE.erl
+++ b/lib/compiler/test/beam_validator_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -49,7 +49,6 @@ suite() ->
{timetrap,{minutes,10}}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -67,6 +66,7 @@ groups() ->
receive_stacked]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/bif_SUITE.erl b/lib/compiler/test/bif_SUITE.erl
index bba2058f2f..c4c709eb3a 100644
--- a/lib/compiler/test/bif_SUITE.erl
+++ b/lib/compiler/test/bif_SUITE.erl
@@ -29,7 +29,6 @@ suite() ->
[{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -40,6 +39,7 @@ groups() ->
]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/bs_bincomp_SUITE.erl b/lib/compiler/test/bs_bincomp_SUITE.erl
index dd1d245f88..a5d49020a9 100644
--- a/lib/compiler/test/bs_bincomp_SUITE.erl
+++ b/lib/compiler/test/bs_bincomp_SUITE.erl
@@ -26,22 +26,22 @@
init_per_group/2,end_per_group/2,
byte_aligned/1,bit_aligned/1,extended_byte_aligned/1,
extended_bit_aligned/1,mixed/1,filters/1,trim_coverage/1,
- nomatch/1,sizes/1,general_expressions/1]).
+ nomatch/1,sizes/1,general_expressions/1,matched_out_size/1]).
-include_lib("common_test/include/ct.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[byte_aligned, bit_aligned, extended_byte_aligned,
extended_bit_aligned, mixed, filters, trim_coverage,
- nomatch, sizes, general_expressions].
+ nomatch, sizes, general_expressions, matched_out_size].
groups() ->
[].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -338,6 +338,13 @@ general_expressions(_) ->
-undef(BAD).
+matched_out_size(Config) when is_list(Config) ->
+ <<1, 2>> = matched_out_size_1(<<4, 1:4, 4, 2:4>>),
+ ok.
+
+matched_out_size_1(Binary) ->
+ << <<X>> || <<S, X:S>> <= Binary>>.
+
cs_init() ->
erts_debug:set_internal_state(available_internal_state, true),
ok.
diff --git a/lib/compiler/test/bs_bit_binaries_SUITE.erl b/lib/compiler/test/bs_bit_binaries_SUITE.erl
index 208d8c5487..17faa012bc 100644
--- a/lib/compiler/test/bs_bit_binaries_SUITE.erl
+++ b/lib/compiler/test/bs_bit_binaries_SUITE.erl
@@ -34,7 +34,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -43,9 +42,10 @@ groups() ->
asymmetric_tests,big_asymmetric_tests,
binary_to_and_from_list,big_binary_to_and_from_list,
send_and_receive,send_and_receive_alot]}].
-
+
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/bs_construct_SUITE.erl b/lib/compiler/test/bs_construct_SUITE.erl
index 7c5ad97f7e..ccc49df005 100644
--- a/lib/compiler/test/bs_construct_SUITE.erl
+++ b/lib/compiler/test/bs_construct_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -38,11 +38,10 @@ suite() ->
[{ct_hooks,[ts_install_cth]},
{timetrap,{minutes,1}}].
-all() ->
- test_lib:recompile(?MODULE),
+all() ->
[{group,p}].
-groups() ->
+groups() ->
[{p,[parallel],
[two,test1,fail,float_bin,in_guard,in_catch,
nasty_literals,side_effect,opt,otp_7556,float_arith,
@@ -50,6 +49,7 @@ groups() ->
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index 235956a714..7814738449 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -40,7 +40,7 @@
map_and_binary/1,unsafe_branch_caching/1,
bad_literals/1,good_literals/1,constant_propagation/1,
parse_xml/1,get_payload/1,escape/1,num_slots_different/1,
- beam_bsm/1,guard/1,is_ascii/1,non_opt_eq/1]).
+ beam_bsm/1,guard/1,is_ascii/1,non_opt_eq/1,erl_689/1]).
-export([coverage_id/1,coverage_external_ignore/2]).
@@ -53,7 +53,6 @@ suite() ->
{timetrap,{minutes,1}}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -73,10 +72,11 @@ groups() ->
map_and_binary,unsafe_branch_caching,
bad_literals,good_literals,constant_propagation,parse_xml,
get_payload,escape,num_slots_different,
- beam_bsm,guard,is_ascii,non_opt_eq]}].
+ beam_bsm,guard,is_ascii,non_opt_eq,erl_689]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -330,6 +330,11 @@ save_restore(Config) when is_list(Config) ->
{"-",<<"x">>} = nnn(C),
{"-",<<"x">>} = ooo(C),
+ a = multiple_matches(<<777:16>>, <<777:16>>),
+ b = multiple_matches(<<777:16>>, <<999:16>>),
+ c = multiple_matches(<<777:16>>, <<57:8>>),
+ d = multiple_matches(<<17:8>>, <<1111:16>>),
+
Bin = <<-1:64>>,
case bad_float_unpack_match(Bin) of
-1 -> ok;
@@ -357,6 +362,11 @@ nnn(<<Char, Tail/binary>>) -> {[Char],Tail}. %% Buggy Tail!
ooo(<<" - ", Tail/binary>>) -> Tail;
ooo(<<Char, Tail/binary>>) -> {[Char],Tail}.
+multiple_matches(<<Y:16>>, <<Y:16>>) -> a;
+multiple_matches(<<_:16>>, <<_:16>>) -> b;
+multiple_matches(<<_:16>>, <<_:8>>) -> c;
+multiple_matches(<<_:8>>, <<_:16>>) -> d.
+
bad_float_unpack_match(<<F:64/float>>) -> F;
bad_float_unpack_match(<<I:64/integer-signed>>) -> I.
@@ -1678,6 +1688,35 @@ non_opt_eq([_|_], <<_,_/binary>>) ->
non_opt_eq([], <<>>) ->
true.
+%% ERL-689
+
+erl_689(Config) ->
+ {{0, 0, 0}, <<>>} = do_erl_689_1(<<0>>, ?MODULE),
+ {{2018, 8, 7}, <<>>} = do_erl_689_1(<<4,2018:16/little,8,7>>, ?MODULE),
+ {{0, 0, 0}, <<>>} = do_erl_689_2(?MODULE, <<0>>),
+ {{2018, 8, 7}, <<>>} = do_erl_689_2(?MODULE, <<4,2018:16/little,8,7>>),
+ ok.
+
+do_erl_689_1(<<Length, Data/binary>>, _) ->
+ case {Data, Length} of
+ {_, 0} ->
+ %% bs_context_to_binary would incorrectly set Data to the original
+ %% binary (before matching in the function head).
+ {{0, 0, 0}, Data};
+ {<<Y:16/little, M, D, Rest/binary>>, 4} ->
+ {{Y, M, D}, Rest}
+ end.
+
+do_erl_689_2(_, <<Length, Data/binary>>) ->
+ case {Length, Data} of
+ {0, _} ->
+ %% bs_context_to_binary would incorrectly set Data to the original
+ %% binary (before matching in the function head).
+ {{0, 0, 0}, Data};
+ {4, <<Y:16/little, M, D, Rest/binary>>} ->
+ {{Y, M, D}, Rest}
+ end.
+
check(F, R) ->
R = F().
diff --git a/lib/compiler/test/bs_utf_SUITE.erl b/lib/compiler/test/bs_utf_SUITE.erl
index ef3fc54b37..4330677260 100644
--- a/lib/compiler/test/bs_utf_SUITE.erl
+++ b/lib/compiler/test/bs_utf_SUITE.erl
@@ -31,7 +31,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[utf8_roundtrip, unused_utf_char, utf16_roundtrip,
utf32_roundtrip, guard, extreme_tripping, literals,
coverage].
@@ -40,6 +39,7 @@ groups() ->
[].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/compilation_SUITE.erl b/lib/compiler/test/compilation_SUITE.erl
index a4de125d32..3ba3ce7cdf 100644
--- a/lib/compiler/test/compilation_SUITE.erl
+++ b/lib/compiler/test/compilation_SUITE.erl
@@ -66,7 +66,6 @@ suite() ->
{timetrap,{minutes,10}}].
all() ->
- test_lib:recompile(?MODULE),
[self_compile_old_inliner,self_compile,
{group,p}].
@@ -88,6 +87,7 @@ groups() ->
string_table,otp_8949_a,split_cases]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/compilation_SUITE_data/opt_crash.erl b/lib/compiler/test/compilation_SUITE_data/opt_crash.erl
index c65ec31593..4643ce61f6 100644
--- a/lib/compiler/test/compilation_SUITE_data/opt_crash.erl
+++ b/lib/compiler/test/compilation_SUITE_data/opt_crash.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl
index a1de8961bd..1ecae06128 100644
--- a/lib/compiler/test/compile_SUITE.erl
+++ b/lib/compiler/test/compile_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -36,7 +36,7 @@
core_roundtrip/1, asm/1, optimized_guards/1,
sys_pre_attributes/1, dialyzer/1,
warnings/1, pre_load_check/1, env_compiler_options/1,
- bc_options/1
+ bc_options/1, deterministic_include/1
]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -46,7 +46,6 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
-spec all() -> all_return_type().
all() ->
- test_lib:recompile(?MODULE),
[app_test, appup_test, file_1, forms_2, module_mismatch, big_file, outdir,
binary, makedep, cond_and_ifdef, listings, listings_big,
other_output, kernel_listing, encrypted_abstr, tuple_calls,
@@ -54,12 +53,13 @@ all() ->
cover, env, core_pp, core_roundtrip, asm, optimized_guards,
sys_pre_attributes, dialyzer, warnings, pre_load_check,
env_compiler_options, custom_debug_info, bc_options,
- custom_compile_info].
+ custom_compile_info, deterministic_include].
groups() ->
[].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -1514,6 +1514,23 @@ highest_opcode(DataDir, Mod, Opt) ->
<<16:32,0:32,HighestOpcode:32,_/binary>> = Code,
HighestOpcode.
+deterministic_include(Config) when is_list(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ Simple = filename:join(DataDir, "simple"),
+
+ %% Files without +deterministic should differ if their include paths do,
+ %% as their debug info will be different.
+ {ok,_,NonDetA} = compile:file(Simple, [binary, {i,"gurka"}]),
+ {ok,_,NonDetB} = compile:file(Simple, [binary, {i,"gaffel"}]),
+ true = NonDetA =/= NonDetB,
+
+ %% ... but files with +deterministic shouldn't.
+ {ok,_,DetC} = compile:file(Simple, [binary, deterministic, {i,"gurka"}]),
+ {ok,_,DetD} = compile:file(Simple, [binary, deterministic, {i,"gaffel"}]),
+ true = DetC =:= DetD,
+
+ ok.
+
%%%
%%% Utilities.
%%%
diff --git a/lib/compiler/test/compile_SUITE_data/big.erl b/lib/compiler/test/compile_SUITE_data/big.erl
index 1db07755a1..765c71c07d 100644
--- a/lib/compiler/test/compile_SUITE_data/big.erl
+++ b/lib/compiler/test/compile_SUITE_data/big.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/core_SUITE.erl b/lib/compiler/test/core_SUITE.erl
index 0e07e8dd2e..e5611e99d1 100644
--- a/lib/compiler/test/core_SUITE.erl
+++ b/lib/compiler/test/core_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@
bs_shadowed_size_var/1,
cover_v3_kernel_1/1,cover_v3_kernel_2/1,cover_v3_kernel_3/1,
cover_v3_kernel_4/1,cover_v3_kernel_5/1,
- non_variable_apply/1]).
+ non_variable_apply/1,name_capture/1,fun_letrec_effect/1]).
-include_lib("common_test/include/ct.hrl").
@@ -47,7 +47,6 @@ suite() ->
{timetrap,{minutes,5}}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -58,11 +57,12 @@ groups() ->
bs_shadowed_size_var,
cover_v3_kernel_1,cover_v3_kernel_2,cover_v3_kernel_3,
cover_v3_kernel_4,cover_v3_kernel_5,
- non_variable_apply
+ non_variable_apply,name_capture,fun_letrec_effect
]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -93,6 +93,8 @@ end_per_group(_GroupName, Config) ->
?comp(cover_v3_kernel_4).
?comp(cover_v3_kernel_5).
?comp(non_variable_apply).
+?comp(name_capture).
+?comp(fun_letrec_effect).
try_it(Mod, Conf) ->
Src = filename:join(proplists:get_value(data_dir, Conf),
diff --git a/lib/compiler/test/core_SUITE_data/fun_letrec_effect.core b/lib/compiler/test/core_SUITE_data/fun_letrec_effect.core
new file mode 100644
index 0000000000..ab6f5b7940
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/fun_letrec_effect.core
@@ -0,0 +1,25 @@
+module 'fun_letrec_effect' ['fun_letrec_effect'/0, 'ok'/0, 'wat'/0]
+attributes []
+
+'fun_letrec_effect'/0 =
+ fun () ->
+ do apply 'wat'/0()
+ receive
+ <'bar'> when 'true' -> 'ok'
+ <_0> when 'true' -> 'failed'
+ after 'infinity' ->
+ 'true'
+
+%% The return value (bar) of the fun was optimized away because the result of
+%% the `letrec ... in` was unused, despite the fun's return value being
+%% relevant for the side-effect of the expression.
+'wat'/0 =
+ fun () ->
+ let <Self> = call 'erlang':'self'() in
+ do letrec 'f'/0 = fun () ->
+ do call 'maps':'put'('foo', 'bar', ~{}~)
+ 'bar'
+ in call 'erlang':'send'(Self, apply 'f'/0())
+ 'undefined'
+
+end
diff --git a/lib/compiler/test/core_SUITE_data/name_capture.core b/lib/compiler/test/core_SUITE_data/name_capture.core
new file mode 100644
index 0000000000..0969f95b72
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/name_capture.core
@@ -0,0 +1,110 @@
+module 'name_capture' ['module_info'/0,
+ 'module_info'/1,
+ 'name_capture'/0]
+ attributes ['compile' =
+ [{'inline',[{'badarg_exit',2}]}]]
+'name_capture'/0 =
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ let <_0> =
+ catch
+ apply 'first'/1
+ ('badarg')
+ in case _0 of
+ <{'EXIT',{'badarg',_7}}> when 'true' ->
+ let <Seq> =
+ call 'lists':'seq'
+ (7, 17)
+ in case apply 'first'/1
+ ({'ok',Seq}) of
+ <_8>
+ when call 'erlang':'=:='
+ (_8,
+ Seq) ->
+ let <SomeOtherTerm> =
+ {'some','other','term'}
+ in let <_5> =
+ catch
+ apply 'first'/1
+ (SomeOtherTerm)
+ in case _5 of
+ <{'EXIT',_9}>
+ when call 'erlang':'=:='
+ (_9,
+ SomeOtherTerm) ->
+ 'ok'
+ <_6> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_6})
+ end
+ <_3> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_3})
+ end
+ <_1> when 'true' ->
+ primop 'match_fail'
+ ({'badmatch',_1})
+ end
+ <> when 'true' ->
+ primop 'match_fail'
+ ({'function_clause'})
+ end
+'first'/1 =
+ fun (_0) ->
+ case _0 of
+ <Tab> when 'true' ->
+ let <_1> =
+ apply 'treq'/2
+ (Tab, 'first')
+ %% The _1 variable in the `let` must be renamed
+ %% to avoid a name capture problem.
+ in let <_0,_1> =
+ <_1,[Tab|[]]>
+ in case <_0,_1> of
+ <'badarg',A> when 'true' ->
+ call 'erlang':'error'
+ ('badarg', A)
+ <{'ok',Reply},_X_A> when 'true' ->
+ Reply
+ <Reply,_X_A> when 'true' ->
+ call 'erlang':'exit'
+ (Reply)
+ <_3,_2> when 'true' ->
+ primop 'match_fail'
+ ({'function_clause',_3,_2})
+ end
+ <_2> when 'true' ->
+ primop 'match_fail'
+ ({'function_clause',_2})
+ end
+'treq'/2 =
+ fun (_0,_1) ->
+ case <_0,_1> of
+ <Action,_4> when 'true' ->
+ Action
+ <_3,_2> when 'true' ->
+ primop 'match_fail'
+ ({'function_clause',_3,_2})
+ end
+'module_info'/0 =
+ fun () ->
+ case <> of
+ <> when 'true' ->
+ call 'erlang':'get_module_info'
+ ('name_capture')
+ <> when 'true' ->
+ primop 'match_fail'
+ ({'function_clause'})
+ end
+'module_info'/1 =
+ fun (_0) ->
+ case _0 of
+ <X> when 'true' ->
+ call 'erlang':'get_module_info'
+ ('name_capture', X)
+ <_1> when 'true' ->
+ primop 'match_fail'
+ ({'function_clause',_1})
+ end
+end
diff --git a/lib/compiler/test/core_alias_SUITE.erl b/lib/compiler/test/core_alias_SUITE.erl
index f3f15ef0f8..4f96576621 100644
--- a/lib/compiler/test/core_alias_SUITE.erl
+++ b/lib/compiler/test/core_alias_SUITE.erl
@@ -28,7 +28,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -36,6 +35,7 @@ groups() ->
[tuples, cons]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl
index ab7f36abf7..30d145582a 100644
--- a/lib/compiler/test/core_fold_SUITE.erl
+++ b/lib/compiler/test/core_fold_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@
mixed_matching_clauses/1,unnecessary_building/1,
no_no_file/1,configuration/1,supplies/1,
redundant_stack_frame/1,export_from_case/1,
- empty_values/1]).
+ empty_values/1,cover_letrec_effect/1]).
-export([foo/0,foo/1,foo/2,foo/3]).
@@ -37,7 +37,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -49,10 +48,11 @@ groups() ->
mixed_matching_clauses,unnecessary_building,
no_no_file,configuration,supplies,
redundant_stack_frame,export_from_case,
- empty_values]}].
+ empty_values,cover_letrec_effect]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -278,6 +278,8 @@ coverage(Config) when is_list(Config) ->
a = cover_remove_non_vars_alias({a,b,c}),
error = cover_will_match_lit_list(),
{ok,[a]} = cover_is_safe_bool_expr(a),
+ false = cover_is_safe_bool_expr2(a),
+ ok = cover_eval_is_function(fun id/1),
ok = cover_opt_guard_try(#cover_opt_guard_try{list=[a]}),
error = cover_opt_guard_try(#cover_opt_guard_try{list=[]}),
@@ -341,6 +343,15 @@ cover_is_safe_bool_expr(X) ->
false
end.
+cover_is_safe_bool_expr2(X) ->
+ try
+ V = [X],
+ is_function(V, 1)
+ catch
+ _:_ ->
+ false
+ end.
+
cover_opt_guard_try(Msg) ->
if
length(Msg#cover_opt_guard_try.list) =/= 1 ->
@@ -349,6 +360,12 @@ cover_opt_guard_try(Msg) ->
ok
end.
+cover_eval_is_function(X) ->
+ case X of
+ {a,_} -> is_function(X);
+ _ -> ok
+ end.
+
bsm_an_inlined(<<_:8>>, _) -> ok;
bsm_an_inlined(_, _) -> error.
@@ -598,5 +615,25 @@ empty_values(_Config) ->
do_empty_values() when (#{})#{} ->
c.
+cover_letrec_effect(_Config) ->
+ self() ! {tag,42},
+ _ = try
+ try
+ ignore
+ after
+ receive
+ {tag,Int}=Term ->
+ Res = #{k => {Term,<<Int:16>>}},
+ self() ! Res
+ end
+ end
+ after
+ ok
+ end,
+ receive
+ Any ->
+ #{k := {{tag,42},<<42:16>>}} = Any
+ end,
+ ok.
id(I) -> I.
diff --git a/lib/compiler/test/error_SUITE.erl b/lib/compiler/test/error_SUITE.erl
index 01c779b181..da291bdc8b 100644
--- a/lib/compiler/test/error_SUITE.erl
+++ b/lib/compiler/test/error_SUITE.erl
@@ -31,7 +31,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -40,6 +39,7 @@ groups() ->
transforms,maps_warnings,bad_utf8]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/float_SUITE.erl b/lib/compiler/test/float_SUITE.erl
index 08c3dd8593..39867021cb 100644
--- a/lib/compiler/test/float_SUITE.erl
+++ b/lib/compiler/test/float_SUITE.erl
@@ -27,7 +27,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[pending, bif_calls, math_functions,
mixed_float_and_int].
@@ -35,6 +34,7 @@ groups() ->
[].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/fun_SUITE.erl b/lib/compiler/test/fun_SUITE.erl
index 3c272a35a6..e00885fcd6 100644
--- a/lib/compiler/test/fun_SUITE.erl
+++ b/lib/compiler/test/fun_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,7 +32,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -41,6 +40,7 @@ groups() ->
eep37_dup,badarity,badfun]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl
index 0d6f8c6f98..99dc06b525 100644
--- a/lib/compiler/test/guard_SUITE.erl
+++ b/lib/compiler/test/guard_SUITE.erl
@@ -41,7 +41,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -59,6 +58,7 @@ groups() ->
cover_beam_dead]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/inline_SUITE.erl b/lib/compiler/test/inline_SUITE.erl
index ae59cc8026..fdf2fe88b4 100644
--- a/lib/compiler/test/inline_SUITE.erl
+++ b/lib/compiler/test/inline_SUITE.erl
@@ -32,7 +32,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -42,6 +41,7 @@ groups() ->
coverage]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Pa = "-pa " ++ filename:dirname(code:which(?MODULE)),
{ok,Node} = start_node(compiler, Pa),
[{testing_node,Node}|Config].
diff --git a/lib/compiler/test/lc_SUITE.erl b/lib/compiler/test/lc_SUITE.erl
index 699081470d..c80b7cc59e 100644
--- a/lib/compiler/test/lc_SUITE.erl
+++ b/lib/compiler/test/lc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,7 +33,6 @@ suite() ->
{timetrap,{minutes,1}}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -48,6 +47,7 @@ groups() ->
]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/map_SUITE.erl b/lib/compiler/test/map_SUITE.erl
index 6badc7a8b8..c004dca834 100644
--- a/lib/compiler/test/map_SUITE.erl
+++ b/lib/compiler/test/map_SUITE.erl
@@ -76,7 +76,6 @@
suite() -> [].
all() ->
- test_lib:recompile(?MODULE),
[
%% literals
t_build_and_match_literals, t_build_and_match_literals_large,
@@ -130,8 +129,12 @@ all() ->
groups() -> [].
-init_per_suite(Config) -> Config.
-end_per_suite(_Config) -> ok.
+init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
init_per_group(_GroupName, Config) -> Config.
end_per_group(_GroupName, Config) -> Config.
@@ -706,6 +709,12 @@ t_map_get(Config) when is_list(Config) ->
{'EXIT',{{badmap,[]},_}} = (catch map_get(a, [])),
{'EXIT',{{badmap,<<1,2,3>>},_}} = (catch map_get(a, <<1,2,3>>)),
{'EXIT',{{badmap,1},_}} = (catch map_get(a, 1)),
+
+ %% Test that beam_validator understands that NewMap is
+ %% a map after seeing map_get(a, NewMap).
+ NewMap = id(#{a=>b}),
+ b = map_get(a, NewMap),
+ #{a:=z} = NewMap#{a:=z},
ok.
check_map_value(Map, Key, Value) when map_get(Key, Map) =:= Value -> true;
@@ -1203,10 +1212,25 @@ t_guard_bifs(Config) when is_list(Config) ->
true = map_guard_empty_2(),
true = map_guard_head(#{a=>1}),
false = map_guard_head([]),
+
true = map_get_head(#{a=>1}),
+ false = map_get_head(#{}),
+ false = map_get_head([]),
+
+ true = map_get_head_not(#{a=>false}),
+ false = map_get_head_not(#{a=>true}),
+ false = map_get_head(#{}),
false = map_get_head([]),
+
true = map_is_key_head(#{a=>1}),
false = map_is_key_head(#{}),
+ false = map_is_key_head(not_a_map),
+
+ false = map_is_key_head_not(#{a=>1}),
+ true = map_is_key_head_not(#{b=>1}),
+ true = map_is_key_head_not(#{}),
+ false = map_is_key_head_not(not_a_map),
+
true = map_guard_body(#{a=>1}),
false = map_guard_body({}),
true = map_guard_pattern(#{a=>1, <<"hi">> => "hi" }),
@@ -1215,6 +1239,25 @@ t_guard_bifs(Config) when is_list(Config) ->
true = map_guard_ill_map_size(),
true = map_field_check_sequence(#{a=>1}),
false = map_field_check_sequence(#{}),
+
+ %% The guard BIFs used in a body.
+
+ v = map_get(a, id(#{a=>v})),
+ {'EXIT',{{badkey,a},_}} =
+ (catch map_get(a, id(#{}))),
+ {'EXIT',{{badmap,not_a_map},_}} =
+ (catch map_get(a, id(not_a_map))),
+
+ true = is_map_key(a, id(#{a=>1})),
+ false = is_map_key(b, id(#{a=>1})),
+ false = is_map_key(b, id(#{})),
+ {'EXIT',{{badmap,not_a_map},_}} =
+ (catch is_map_key(b, id(not_a_map))),
+
+ {true,v} = erl_699(#{k=>v}),
+ {'EXIT',{{badkey,k},_}} = (catch erl_699(#{})),
+ {'EXIT',{{badmap,not_a_map},_}} = (catch erl_699(not_a_map)),
+
ok.
map_guard_empty() when is_map(#{}); false -> true.
@@ -1227,8 +1270,14 @@ map_guard_head(_) -> false.
map_get_head(M) when map_get(a, M) =:= 1 -> true;
map_get_head(_) -> false.
+map_get_head_not(M) when not map_get(a, M) -> true;
+map_get_head_not(_) -> false.
+
map_is_key_head(M) when is_map_key(a, M) -> true;
-map_is_key_head(M) -> false.
+map_is_key_head(_) -> false.
+
+map_is_key_head_not(M) when not is_map_key(a, M) -> true;
+map_is_key_head_not(_) -> false.
map_guard_body(M) -> is_map(M).
@@ -1245,6 +1294,10 @@ map_field_check_sequence(M)
map_field_check_sequence(_) ->
false.
+erl_699(M) ->
+ %% Used to cause an internal consistency failure.
+ {is_map_key(k, M),maps:get(k, M)}.
+
t_guard_sequence(Config) when is_list(Config) ->
{1, "a"} = map_guard_sequence_1(#{seq=>1,val=>id("a")}),
{2, "b"} = map_guard_sequence_1(#{seq=>2,val=>id("b")}),
diff --git a/lib/compiler/test/match_SUITE.erl b/lib/compiler/test/match_SUITE.erl
index 4b26a8dcdc..e3f842b668 100644
--- a/lib/compiler/test/match_SUITE.erl
+++ b/lib/compiler/test/match_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,7 +32,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -45,6 +44,7 @@ groups() ->
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/misc_SUITE.erl b/lib/compiler/test/misc_SUITE.erl
index 4e39f4663e..a1d931b994 100644
--- a/lib/compiler/test/misc_SUITE.erl
+++ b/lib/compiler/test/misc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -61,7 +61,6 @@ suite() ->
-spec all() -> misc_SUITE_test_cases().
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -70,6 +69,7 @@ groups() ->
confused_literals,integer_encoding,override_bif]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/overridden_bif_SUITE.erl b/lib/compiler/test/overridden_bif_SUITE.erl
index ce18916515..a46abe8dcf 100644
--- a/lib/compiler/test/overridden_bif_SUITE.erl
+++ b/lib/compiler/test/overridden_bif_SUITE.erl
@@ -36,7 +36,6 @@ suite() ->
{timetrap,{minutes,1}}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -45,6 +44,7 @@ groups() ->
]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/receive_SUITE.erl b/lib/compiler/test/receive_SUITE.erl
index 5e386790c0..4219768d6f 100644
--- a/lib/compiler/test/receive_SUITE.erl
+++ b/lib/compiler/test/receive_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
export/1,recv/1,coverage/1,otp_7980/1,ref_opt/1,
- wait/1]).
+ wait/1,recv_in_try/1,double_recv/1]).
-include_lib("common_test/include/ct.hrl").
@@ -40,15 +40,16 @@ suite() ->
{timetrap,{minutes,2}}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
[{p,test_lib:parallel(),
- [recv,coverage,otp_7980,ref_opt,export,wait]}].
+ [recv,coverage,otp_7980,ref_opt,export,wait,
+ recv_in_try,double_recv]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
@@ -305,4 +306,76 @@ wait_1(r, _, _) ->
wait_1(A, B, C) ->
{A,B,C}.
+recv_in_try(_Config) ->
+ self() ! {ok,fh}, {ok,fh} = recv_in_try(infinity, native),
+ self() ! {ok,ignored}, {ok,42} = recv_in_try(infinity, plain),
+ self() ! {error,ignored}, nok = recv_in_try(infinity, plain),
+ timeout = recv_in_try(1, plain),
+ ok.
+
+recv_in_try(Timeout, Format) ->
+ try
+ receive
+ {Status,History} ->
+ %% {test,is_tuple,{f,148},[{x,0}]}.
+ %% {test,test_arity,{f,148},[{x,0},2]}.
+ %% {get_tuple_element,{x,0},0,{y,1}}. %y1 is fragile.
+ %%
+ %% %% Here the fragility of y1 would be be progated to
+ %% %% the 'catch' below. Incorrect, since get_tuple_element
+ %% %% can't fail.
+ %% {get_tuple_element,{x,0},1,{x,2}}.
+ %%
+ %% remove_message. %y1 fragility cleared.
+ FH = case Format of
+ native ->
+ id(History);
+ plain ->
+ id(42)
+ end,
+ case Status of
+ ok ->
+ {ok,FH};
+ error ->
+ nok
+ end
+ after Timeout ->
+ timeout
+ end
+ catch
+ %% The fragility of y1 incorrectly propagated to here.
+ %% beam_validator would complain.
+ throw:{error,Reason} ->
+ {nok,Reason}
+ end.
+
+%% ERL-703. The compiler would crash because beam_utils:anno_defs/1
+%% failed to take into account that code after loop_rec_end is
+%% unreachable.
+
+double_recv(_Config) ->
+ self() ! {more,{a,term}},
+ ok = do_double_recv({more,{a,term}}, any),
+ self() ! message,
+ ok = do_double_recv(whatever, message),
+
+ error = do_double_recv({more,42}, whatever),
+ error = do_double_recv(whatever, whatever),
+ ok.
+
+do_double_recv({more, Rest}, _Msg) ->
+ receive
+ {more, Rest} ->
+ ok
+ after 0 ->
+ error
+ end;
+do_double_recv(_, Msg) ->
+ receive
+ Msg ->
+ ok
+ after 0 ->
+ error
+ end.
+
id(I) -> I.
diff --git a/lib/compiler/test/record_SUITE.erl b/lib/compiler/test/record_SUITE.erl
index 5546765f26..118e0a241c 100644
--- a/lib/compiler/test/record_SUITE.erl
+++ b/lib/compiler/test/record_SUITE.erl
@@ -41,7 +41,6 @@ suite() ->
{timetrap,{minutes,2}}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -52,6 +51,7 @@ groups() ->
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/regressions_SUITE.erl b/lib/compiler/test/regressions_SUITE.erl
index 7a6fe08c73..f448d54933 100644
--- a/lib/compiler/test/regressions_SUITE.erl
+++ b/lib/compiler/test/regressions_SUITE.erl
@@ -21,13 +21,29 @@
-module(regressions_SUITE).
-include_lib("common_test/include/ct.hrl").
--export([all/0,groups/0,init_per_testcase/2,end_per_testcase/2,suite/0]).
+-export([all/0,groups/0,init_per_testcase/2,end_per_testcase/2,
+ init_per_group/2,end_per_group/2,
+ init_per_testcase/2,end_per_testcase/2,
+ suite/0]).
-export([maps/1]).
groups() ->
[{p,test_lib:parallel(),
[maps]}].
+init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
init_per_testcase(_Case, Config) ->
Config.
@@ -39,7 +55,6 @@ suite() ->
{timetrap,{minutes,2}}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
%%% test cases
diff --git a/lib/compiler/test/trycatch_SUITE.erl b/lib/compiler/test/trycatch_SUITE.erl
index d5a1dc642f..1b7ef4ddb0 100644
--- a/lib/compiler/test/trycatch_SUITE.erl
+++ b/lib/compiler/test/trycatch_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,7 +34,6 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -48,6 +47,7 @@ groups() ->
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl
index 857995b6a6..42ff4f6133 100644
--- a/lib/compiler/test/warnings_SUITE.erl
+++ b/lib/compiler/test/warnings_SUITE.erl
@@ -55,7 +55,6 @@ suite() ->
{timetrap,{minutes,2}}].
all() ->
- test_lib:recompile(?MODULE),
[{group,p}].
groups() ->
@@ -68,6 +67,7 @@ groups() ->
underscore,no_warnings,bit_syntax,inlining]}].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/test/z_SUITE.erl b/lib/compiler/test/z_SUITE.erl
index cd95d0e733..bfa8e279e8 100644
--- a/lib/compiler/test/z_SUITE.erl
+++ b/lib/compiler/test/z_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,13 +26,13 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- test_lib:recompile(?MODULE),
[loaded].
groups() ->
[].
init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
Config.
end_per_suite(_Config) ->
diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk
index ee75ee27fd..355113a94d 100644
--- a/lib/compiler/vsn.mk
+++ b/lib/compiler/vsn.mk
@@ -1 +1 @@
-COMPILER_VSN = 7.1.5
+COMPILER_VSN = 7.2.3
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index df4e2245f4..68d2c44b5e 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2010-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2010-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -155,6 +155,14 @@
# define HAVE_EC
#endif
+// (test for == 1.1.1pre8)
+#if OPENSSL_VERSION_NUMBER == (PACKED_OPENSSL_VERSION_PLAIN(1,1,1) - 7) \
+ && !defined(HAS_LIBRESSL) \
+ && defined(HAVE_EC)
+// EXPERIMENTAL:
+# define HAVE_EDDH
+#endif
+
#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,8,'c')
# define HAVE_AES_IGE
#endif
@@ -171,6 +179,7 @@
#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,1,0)
# ifndef HAS_LIBRESSL
# define HAVE_CHACHA20_POLY1305
+# define HAVE_RSA_OAEP_MD
# endif
#endif
@@ -501,6 +510,9 @@ static ERL_NIF_TERM srp_host_secret_nif(ErlNifEnv* env, int argc, const ERL_NIF_
static ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM evp_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM evp_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
static ERL_NIF_TERM rand_seed_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_gcm_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -544,6 +556,7 @@ static int zero_terminate(ErlNifBinary bin, char **buf);
#endif
static int library_refc = 0; /* number of users of this dynamic library */
+static int library_initialized = 0;
static ErlNifFunc nif_funcs[] = {
{"info_lib", 0, info_lib},
@@ -580,6 +593,10 @@ static ErlNifFunc nif_funcs[] = {
{"rsa_generate_key_nif", 2, rsa_generate_key_nif},
{"dh_generate_key_nif", 4, dh_generate_key_nif},
{"dh_compute_key_nif", 3, dh_compute_key_nif},
+
+ {"evp_compute_key_nif", 3, evp_compute_key_nif},
+ {"evp_generate_key_nif", 1, evp_generate_key_nif},
+
{"privkey_to_pubkey_nif", 2, privkey_to_pubkey_nif},
{"srp_value_B_nif", 5, srp_value_B_nif},
{"srp_user_secret_nif", 7, srp_user_secret_nif},
@@ -667,6 +684,13 @@ static ERL_NIF_TERM atom_blowfish_ecb;
static ERL_NIF_TERM atom_rsa;
static ERL_NIF_TERM atom_dss;
static ERL_NIF_TERM atom_ecdsa;
+
+#ifdef HAVE_EDDH
+static ERL_NIF_TERM atom_eddh;
+static ERL_NIF_TERM atom_x25519;
+static ERL_NIF_TERM atom_x448;
+#endif
+
static ERL_NIF_TERM atom_rsa_mgf1_md;
static ERL_NIF_TERM atom_rsa_oaep_label;
static ERL_NIF_TERM atom_rsa_oaep_md;
@@ -1005,14 +1029,14 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
PRINTF_ERR0("CRYPTO: Could not open resource type 'ENGINE_CTX'");
return __LINE__;
}
+#endif
- if (library_refc > 0) {
+ if (library_initialized) {
/* Repeated loading of this library (module upgrade).
* Atoms and callbacks are already set, we are done.
*/
return 0;
}
-#endif
atom_true = enif_make_atom(env,"true");
atom_false = enif_make_atom(env,"false");
@@ -1074,6 +1098,11 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_rsa = enif_make_atom(env,"rsa");
atom_dss = enif_make_atom(env,"dss");
atom_ecdsa = enif_make_atom(env,"ecdsa");
+#ifdef HAVE_EDDH
+ atom_eddh = enif_make_atom(env,"eddh");
+ atom_x25519 = enif_make_atom(env,"x25519");
+ atom_x448 = enif_make_atom(env,"x448");
+#endif
atom_rsa_mgf1_md = enif_make_atom(env,"rsa_mgf1_md");
atom_rsa_oaep_label = enif_make_atom(env,"rsa_oaep_label");
atom_rsa_oaep_md = enif_make_atom(env,"rsa_oaep_md");
@@ -1119,9 +1148,6 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_password = enif_make_atom(env,"password");
#endif
- init_digest_types(env);
- init_cipher_types(env);
- init_algorithms_types(env);
#ifdef HAVE_DYNAMIC_CRYPTO_LIB
{
@@ -1168,6 +1194,11 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
}
#endif /* OPENSSL_THREADS */
+ init_digest_types(env);
+ init_cipher_types(env);
+ init_algorithms_types(env);
+
+ library_initialized = 1;
return 0;
}
@@ -1209,11 +1240,13 @@ static void unload(ErlNifEnv* env, void* priv_data)
static int algo_hash_cnt, algo_hash_fips_cnt;
static ERL_NIF_TERM algo_hash[8]; /* increase when extending the list */
static int algo_pubkey_cnt, algo_pubkey_fips_cnt;
-static ERL_NIF_TERM algo_pubkey[7]; /* increase when extending the list */
+static ERL_NIF_TERM algo_pubkey[11]; /* increase when extending the list */
static int algo_cipher_cnt, algo_cipher_fips_cnt;
static ERL_NIF_TERM algo_cipher[24]; /* increase when extending the list */
static int algo_mac_cnt, algo_mac_fips_cnt;
static ERL_NIF_TERM algo_mac[2]; /* increase when extending the list */
+static int algo_curve_cnt, algo_curve_fips_cnt;
+static ERL_NIF_TERM algo_curve[87]; /* increase when extending the list */
static void init_algorithms_types(ErlNifEnv* env)
{
@@ -1251,6 +1284,9 @@ static void init_algorithms_types(ErlNifEnv* env)
#endif
// Non-validated algorithms follow
algo_pubkey_fips_cnt = algo_pubkey_cnt;
+#ifdef HAVE_EDDH
+ algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "eddh");
+#endif
algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "srp");
// Validated algorithms first
@@ -1306,10 +1342,113 @@ static void init_algorithms_types(ErlNifEnv* env)
// Non-validated algorithms follow
algo_mac_fips_cnt = algo_mac_cnt;
+ // Validated algorithms first
+ algo_curve_cnt = 0;
+#if defined(HAVE_EC)
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp160k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp160r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp160r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp192r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp192k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp224k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp224r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp256k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp256r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp384r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp521r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime192v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime192v2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime192v3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime239v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime239v2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime239v3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime256v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls7");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls9");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls12");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP160r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP160t1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP192r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP192t1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP224r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP224t1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP256r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP256t1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP320r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP320t1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP384r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP384t1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP512r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP512t1");
+#if !defined(OPENSSL_NO_EC2M)
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect163k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect163r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect163r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect193r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect193r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect233k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect233r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect239k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect283k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect283r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect409k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect409r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect571k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect571r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb163v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb163v2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb163v3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb176v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb191v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb191v2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb191v3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb208w1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb239v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb239v2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb239v3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb272w1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb304w1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb359v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb368w1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb431r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls5");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls10");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls11");
+#endif
+#endif
+ // Non-validated algorithms follow
+ algo_curve_fips_cnt = algo_curve_cnt;
+#if defined(HAVE_EC)
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp112r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp112r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp128r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp128r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls6");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls8");
+#if !defined(OPENSSL_NO_EC2M)
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect113r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect113r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect131r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect131r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls4");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"ipsec3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"ipsec4");
+#endif
+#endif
+ //--
+#ifdef HAVE_EDDH
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"x25519");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"x448");
+#endif
+
+ // Check that the max number of algos is updated
ASSERT(algo_hash_cnt <= sizeof(algo_hash)/sizeof(ERL_NIF_TERM));
ASSERT(algo_pubkey_cnt <= sizeof(algo_pubkey)/sizeof(ERL_NIF_TERM));
ASSERT(algo_cipher_cnt <= sizeof(algo_cipher)/sizeof(ERL_NIF_TERM));
ASSERT(algo_mac_cnt <= sizeof(algo_mac)/sizeof(ERL_NIF_TERM));
+ ASSERT(algo_curve_cnt <= sizeof(algo_curve)/sizeof(ERL_NIF_TERM));
}
static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -1320,17 +1459,20 @@ static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
int pubkey_cnt = fips_mode ? algo_pubkey_fips_cnt : algo_pubkey_cnt;
int cipher_cnt = fips_mode ? algo_cipher_fips_cnt : algo_cipher_cnt;
int mac_cnt = fips_mode ? algo_mac_fips_cnt : algo_mac_cnt;
+ int curve_cnt = fips_mode ? algo_curve_fips_cnt : algo_curve_cnt;
#else
int hash_cnt = algo_hash_cnt;
int pubkey_cnt = algo_pubkey_cnt;
int cipher_cnt = algo_cipher_cnt;
int mac_cnt = algo_mac_cnt;
+ int curve_cnt = algo_curve_cnt;
#endif
- return enif_make_tuple4(env,
- enif_make_list_from_array(env, algo_hash, hash_cnt),
+ return enif_make_tuple5(env,
+ enif_make_list_from_array(env, algo_hash, hash_cnt),
enif_make_list_from_array(env, algo_pubkey, pubkey_cnt),
enif_make_list_from_array(env, algo_cipher, cipher_cnt),
- enif_make_list_from_array(env, algo_mac, mac_cnt)
+ enif_make_list_from_array(env, algo_mac, mac_cnt),
+ enif_make_list_from_array(env, algo_curve, curve_cnt)
);
}
@@ -1751,6 +1893,7 @@ static ERL_NIF_TERM hash_final_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
}
#endif /* OPENSSL_VERSION_NUMBER < 1.0 */
+
static ERL_NIF_TERM hmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Type, Key, Data) or (Type, Key, Data, MacSize) */
struct digest_type_t *digp = NULL;
@@ -3016,201 +3159,187 @@ static ERL_NIF_TERM rsa_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF
static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (PrivKey|undefined, DHParams=[P,G], Mpint, Len|0) */
- DH* dh_params = NULL;
- int pub_len, prv_len;
- unsigned char *pub_ptr, *prv_ptr;
- ERL_NIF_TERM ret, ret_pub, ret_prv, head, tail;
+ DH *dh_params = NULL;
int mpint; /* 0 or 4 */
- BIGNUM *priv_key_in = NULL;
- BIGNUM *dh_p = NULL, *dh_g = NULL;
- unsigned long len = 0;
-#ifdef HAS_EVP_PKEY_CTX
- EVP_PKEY_CTX *ctx = NULL;
- EVP_PKEY *dhkey = NULL,
- *params = NULL;
-#endif
- if (!(get_bn_from_bin(env, argv[0], &priv_key_in)
- || argv[0] == atom_undefined)
- || !enif_get_list_cell(env, argv[1], &head, &tail)
- || !get_bn_from_bin(env, head, &dh_p)
- || !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_bin(env, head, &dh_g)
- || !enif_is_empty_list(env, tail)
- || !enif_get_int(env, argv[2], &mpint) || (mpint & ~4)
- || !enif_get_ulong(env, argv[3], &len)
-
- /* Load dh_params with values to use by the generator.
- Mem mgmnt transfered from dh_p etc to dh_params */
- || !(dh_params = DH_new())
- || (priv_key_in && !DH_set0_key(dh_params, NULL, priv_key_in))
- || !DH_set0_pqg(dh_params, dh_p, NULL, dh_g)
- ) {
- if (priv_key_in) BN_free(priv_key_in);
- if (dh_p) BN_free(dh_p);
- if (dh_g) BN_free(dh_g);
- if (dh_params) DH_free(dh_params);
- return enif_make_badarg(env);
- }
-
- if (len) {
- if (len < BN_num_bits(dh_p))
- DH_set_length(dh_params, len);
- else {
+ {
+ ERL_NIF_TERM head, tail;
+ BIGNUM
+ *dh_p = NULL,
+ *dh_g = NULL,
+ *priv_key_in = NULL;
+ unsigned long
+ len = 0;
+
+ if (!(get_bn_from_bin(env, argv[0], &priv_key_in)
+ || argv[0] == atom_undefined)
+ || !enif_get_list_cell(env, argv[1], &head, &tail)
+ || !get_bn_from_bin(env, head, &dh_p)
+ || !enif_get_list_cell(env, tail, &head, &tail)
+ || !get_bn_from_bin(env, head, &dh_g)
+ || !enif_is_empty_list(env, tail)
+ || !enif_get_int(env, argv[2], &mpint) || (mpint & ~4)
+ || !enif_get_ulong(env, argv[3], &len)
+
+ /* Load dh_params with values to use by the generator.
+ Mem mgmnt transfered from dh_p etc to dh_params */
+ || !(dh_params = DH_new())
+ || (priv_key_in && !DH_set0_key(dh_params, NULL, priv_key_in))
+ || !DH_set0_pqg(dh_params, dh_p, NULL, dh_g)
+ ) {
if (priv_key_in) BN_free(priv_key_in);
if (dh_p) BN_free(dh_p);
if (dh_g) BN_free(dh_g);
if (dh_params) DH_free(dh_params);
return enif_make_badarg(env);
}
+
+ if (len) {
+ if (len < BN_num_bits(dh_p))
+ DH_set_length(dh_params, len);
+ else {
+ if (priv_key_in) BN_free(priv_key_in);
+ if (dh_p) BN_free(dh_p);
+ if (dh_g) BN_free(dh_g);
+ if (dh_params) DH_free(dh_params);
+ return enif_make_badarg(env);
+ }
+ }
}
#ifdef HAS_EVP_PKEY_CTX
- if ((dhkey = EVP_PKEY_new())
- && (params = EVP_PKEY_new())
- && EVP_PKEY_set1_DH(params, dh_params) /* set the key referenced by params to dh_params.
- dh_params (and params) must be freed by us*/
- && (ctx = EVP_PKEY_CTX_new(params, NULL))
- && EVP_PKEY_keygen_init(ctx)
- && EVP_PKEY_keygen(ctx, &dhkey)
- && (dh_params = EVP_PKEY_get1_DH(dhkey)) /* return the referenced key. dh_params and dhkey must be freed */
- ) {
+ {
+ EVP_PKEY_CTX *ctx;
+ EVP_PKEY *dhkey, *params;
+ int success;
+
+ params = EVP_PKEY_new();
+ success = EVP_PKEY_set1_DH(params, dh_params); /* set the key referenced by params to dh_params... */
+ DH_free(dh_params); /* ...dh_params (and params) must be freed */
+ if (!success) return atom_error;
+
+ ctx = EVP_PKEY_CTX_new(params, NULL);
+ EVP_PKEY_free(params);
+ if (!ctx) {
+ return atom_error;
+ }
+
+ if (!EVP_PKEY_keygen_init(ctx)) {
+ /* EVP_PKEY_CTX_free(ctx); */
+ return atom_error;
+ }
+
+ dhkey = EVP_PKEY_new();
+ if (!EVP_PKEY_keygen(ctx, &dhkey)) { /* "performs a key generation operation, the ... */
+ /*... generated key is written to ppkey." (=last arg) */
+ /* EVP_PKEY_CTX_free(ctx); */
+ /* EVP_PKEY_free(dhkey); */
+ return atom_error;
+ }
+
+ dh_params = EVP_PKEY_get1_DH(dhkey); /* return the referenced key. dh_params and dhkey must be freed */
+ EVP_PKEY_free(dhkey);
+ if (!dh_params) {
+ /* EVP_PKEY_CTX_free(ctx); */
+ return atom_error;
+ }
+ EVP_PKEY_CTX_free(ctx);
+ }
#else
- if (DH_generate_key(dh_params)) {
-#endif
+ if (!DH_generate_key(dh_params)) return atom_error;
+#endif
+ {
+ unsigned char *pub_ptr, *prv_ptr;
+ int pub_len, prv_len;
+ ERL_NIF_TERM ret_pub, ret_prv;
const BIGNUM *pub_key_gen, *priv_key_gen;
-
- DH_get0_key(dh_params,
- &pub_key_gen, &priv_key_gen); /* Get pub_key_gen and priv_key_gen.
- "The values point to the internal representation of
- the public key and private key values. This memory
+
+ DH_get0_key(dh_params,
+ &pub_key_gen, &priv_key_gen); /* Get pub_key_gen and priv_key_gen.
+ "The values point to the internal representation of
+ the public key and private key values. This memory
should not be freed directly." says man */
- pub_len = BN_num_bytes(pub_key_gen);
- prv_len = BN_num_bytes(priv_key_gen);
- pub_ptr = enif_make_new_binary(env, pub_len+mpint, &ret_pub);
- prv_ptr = enif_make_new_binary(env, prv_len+mpint, &ret_prv);
- if (mpint) {
- put_int32(pub_ptr, pub_len); pub_ptr += 4;
- put_int32(prv_ptr, prv_len); prv_ptr += 4;
- }
- BN_bn2bin(pub_key_gen, pub_ptr);
- BN_bn2bin(priv_key_gen, prv_ptr);
- ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr, pub_len);
- ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr, prv_len);
- ret = enif_make_tuple2(env, ret_pub, ret_prv);
- }
- else {
- ret = atom_error;
- }
+ pub_len = BN_num_bytes(pub_key_gen);
+ prv_len = BN_num_bytes(priv_key_gen);
+ pub_ptr = enif_make_new_binary(env, pub_len+mpint, &ret_pub);
+ prv_ptr = enif_make_new_binary(env, prv_len+mpint, &ret_prv);
+ if (mpint) {
+ put_int32(pub_ptr, pub_len); pub_ptr += 4;
+ put_int32(prv_ptr, prv_len); prv_ptr += 4;
+ }
+ BN_bn2bin(pub_key_gen, pub_ptr);
+ BN_bn2bin(priv_key_gen, prv_ptr);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(pub_ptr, pub_len);
+ ERL_VALGRIND_MAKE_MEM_DEFINED(prv_ptr, prv_len);
- DH_free(dh_params);
-#ifdef HAS_EVP_PKEY_CTX
- if (ctx) EVP_PKEY_CTX_free(ctx);
- /* if (dhkey) EVP_PKEY_free(dhkey); */
- /* if (params) EVP_PKEY_free(params); */
-#endif
- return ret;
+ DH_free(dh_params);
+
+ return enif_make_tuple2(env, ret_pub, ret_prv);
+ }
}
static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (OthersPublicKey, MyPrivateKey, DHParams=[P,G]) */
- BIGNUM *dummy_pub_key = NULL,
- *priv_key = NULL,
- *other_pub_key = NULL,
+ BIGNUM *other_pub_key = NULL,
*dh_p = NULL,
*dh_g = NULL;
- ErlNifBinary ret_bin;
- ERL_NIF_TERM ret, head, tail;
- DH *dh_priv = DH_new(), *dh_pub = DH_new();
-#ifdef HAS_EVP_PKEY_CTX
- EVP_PKEY_CTX *ctx = NULL;
- EVP_PKEY *my_priv_key = NULL, *peer_pub_key = NULL;
- size_t skeylen;
-#else
- int i;
-#endif
+ DH *dh_priv = DH_new();
- if (!get_bn_from_bin(env, argv[0], &other_pub_key)
- || !get_bn_from_bin(env, argv[1], &priv_key)
- || !enif_get_list_cell(env, argv[2], &head, &tail)
- || !get_bn_from_bin(env, head, &dh_p)
- || !enif_get_list_cell(env, tail, &head, &tail)
- || !get_bn_from_bin(env, head, &dh_g)
- || !enif_is_empty_list(env, tail)
+ /* Check the arguments and get
+ my private key (dh_priv),
+ the peer's public key (other_pub_key),
+ the parameters p & q
+ */
- /* Note: DH_set0_key() does not allow setting only the
- * private key, although DH_compute_key() does not use the
- * public key. Work around this limitation by setting
- * the public key to a copy of the private key.
- */
- || !(dummy_pub_key = BN_dup(priv_key))
- || !DH_set0_key(dh_priv, dummy_pub_key, priv_key)
- || !DH_set0_pqg(dh_priv, dh_p, NULL, dh_g)
- ) {
- if (dh_p) BN_free(dh_p);
- if (dh_g) BN_free(dh_g);
- if (other_pub_key) BN_free(other_pub_key);
- if (dummy_pub_key) BN_free(dummy_pub_key);
- if (priv_key) BN_free(priv_key);
- return enif_make_badarg(env);
- }
-
-#ifdef HAS_EVP_PKEY_CTX
- if (!(my_priv_key = EVP_PKEY_new())
- || !EVP_PKEY_set1_DH(my_priv_key, dh_priv) /* set the key referenced by my_priv_key to dh_priv.
- dh_priv (and my_priv_key) must be freed by us*/
-
- || !(peer_pub_key = EVP_PKEY_new())
- || !DH_set0_key(dh_pub, other_pub_key, NULL)
- || !DH_set0_pqg(dh_pub, dh_p, NULL, dh_g)
- || !EVP_PKEY_set1_DH(peer_pub_key, dh_pub)
-
- || !(ctx = EVP_PKEY_CTX_new(my_priv_key, NULL))
- || (EVP_PKEY_derive_init(ctx) <= 0)
- || (EVP_PKEY_derive_set_peer(ctx, peer_pub_key) <= 0)
- || (EVP_PKEY_derive(ctx, NULL, &skeylen) <= 0)) {
-
- ret = atom_error;
- }
- else {
- enif_alloc_binary(skeylen, &ret_bin);
-
- if ((EVP_PKEY_derive(ctx, ret_bin.data, &skeylen) > 0)
- && (ret_bin.size >= skeylen)) {
- /* Derivation succeded */
- if (ret_bin.size > skeylen) enif_realloc_binary(&ret_bin, skeylen);
- ret = enif_make_binary(env, &ret_bin);
+ {
+ BIGNUM *dummy_pub_key = NULL,
+ *priv_key = NULL;
+ ERL_NIF_TERM head, tail;
+
+ if (!get_bn_from_bin(env, argv[0], &other_pub_key)
+ || !get_bn_from_bin(env, argv[1], &priv_key)
+ || !enif_get_list_cell(env, argv[2], &head, &tail)
+ || !get_bn_from_bin(env, head, &dh_p)
+ || !enif_get_list_cell(env, tail, &head, &tail)
+ || !get_bn_from_bin(env, head, &dh_g)
+ || !enif_is_empty_list(env, tail)
+
+ /* Note: DH_set0_key() does not allow setting only the
+ * private key, although DH_compute_key() does not use the
+ * public key. Work around this limitation by setting
+ * the public key to a copy of the private key.
+ */
+ || !(dummy_pub_key = BN_dup(priv_key))
+ || !DH_set0_key(dh_priv, dummy_pub_key, priv_key)
+ || !DH_set0_pqg(dh_priv, dh_p, NULL, dh_g)
+ ) {
+ if (dh_p) BN_free(dh_p);
+ if (dh_g) BN_free(dh_g);
+ if (other_pub_key) BN_free(other_pub_key);
+ if (dummy_pub_key) BN_free(dummy_pub_key);
+ if (priv_key) BN_free(priv_key);
+ return enif_make_badarg(env);
}
- else {
+ }
+ {
+ ErlNifBinary ret_bin;
+ int size;
+
+ enif_alloc_binary(DH_size(dh_priv), &ret_bin);
+ size = DH_compute_key(ret_bin.data, other_pub_key, dh_priv);
+ BN_free(other_pub_key);
+ DH_free(dh_priv);
+ if (size<=0) {
enif_release_binary(&ret_bin);
- ret = atom_error;
+ return atom_error;
}
- }
-#else
- enif_alloc_binary(DH_size(dh_priv), &ret_bin);
- i = DH_compute_key(ret_bin.data, other_pub_key, dh_priv);
- if (i > 0) {
- if (i != ret_bin.size) enif_realloc_binary(&ret_bin, i);
- ret = enif_make_binary(env, &ret_bin);
+ if (size != ret_bin.size) enif_realloc_binary(&ret_bin, size);
+ return enif_make_binary(env, &ret_bin);
}
- else {
- enif_release_binary(&ret_bin);
- ret = atom_error;
- }
-#endif
-
- if (other_pub_key) BN_free(other_pub_key);
- if (dh_priv) DH_free(dh_priv);
- if (dh_pub) DH_free(dh_pub);
-#ifdef HAS_EVP_PKEY_CTX
- if (ctx) EVP_PKEY_CTX_free(ctx);
- /* if (my_priv_key) EVP_PKEY_free(my_priv_key); */
- /* if (peer_pub_key) EVP_PKEY_free(peer_pub_key); */
-#endif
- return ret;
}
+
static ERL_NIF_TERM srp_value_B_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Multiplier, Verifier, Generator, Exponent, Prime) */
BIGNUM *bn_verifier = NULL;
@@ -3772,7 +3901,7 @@ static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF
int i;
EC_GROUP *group;
const BIGNUM *priv_key;
- EC_POINT *my_ecpoint;
+ EC_POINT *my_ecpoint = NULL;
EC_KEY *other_ecdh = NULL;
if (!get_ec_key(env, argv[1], argv[2], atom_undefined, &key))
@@ -3815,6 +3944,102 @@ out_err:
#endif
}
+// EXPERIMENTAL!
+static ERL_NIF_TERM evp_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+ /* (Curve, PeerBin, MyBin) */
+{
+#ifdef HAVE_EDDH
+ int type;
+ EVP_PKEY_CTX *ctx;
+ ErlNifBinary peer_bin, my_bin, key_bin;
+ EVP_PKEY *peer_key, *my_key;
+ size_t max_size;
+
+ if (argv[0] == atom_x25519) type = EVP_PKEY_X25519;
+ else if (argv[0] == atom_x448) type = EVP_PKEY_X448;
+ else return enif_make_badarg(env);
+
+ if (!enif_inspect_binary(env, argv[1], &peer_bin) ||
+ !enif_inspect_binary(env, argv[2], &my_bin)) {
+ return enif_make_badarg(env);
+ }
+
+ if (!(my_key = EVP_PKEY_new_raw_private_key(type, NULL, my_bin.data, my_bin.size)) ||
+ !(ctx = EVP_PKEY_CTX_new(my_key, NULL))) {
+ return enif_make_badarg(env);
+ }
+
+ if (!EVP_PKEY_derive_init(ctx)) {
+ return enif_make_badarg(env);
+ }
+
+ if (!(peer_key = EVP_PKEY_new_raw_public_key(type, NULL, peer_bin.data, peer_bin.size)) ||
+ !EVP_PKEY_derive_set_peer(ctx, peer_key)) {
+ return enif_make_badarg(env);
+ }
+
+ if (!EVP_PKEY_derive(ctx, NULL, &max_size)) {
+ return enif_make_badarg(env);
+ }
+
+ if (!enif_alloc_binary(max_size, &key_bin) ||
+ !EVP_PKEY_derive(ctx, key_bin.data, &key_bin.size)) {
+ return enif_make_badarg(env);
+ }
+
+ if (key_bin.size < max_size) {
+ size_t actual_size = key_bin.size;
+ if (!enif_realloc_binary(&key_bin, actual_size)) {
+ return enif_make_badarg(env);
+ }
+ }
+
+ return enif_make_binary(env, &key_bin);
+#else
+ return atom_notsup;
+#endif
+}
+
+// EXPERIMENTAL!
+static ERL_NIF_TERM evp_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+/* (Curve) */
+{
+#ifdef HAVE_EDDH
+ int type;
+ EVP_PKEY_CTX *ctx;
+ EVP_PKEY *pkey = NULL;
+ ERL_NIF_TERM ret_pub, ret_prv;
+ size_t key_len;
+
+ if (argv[0] == atom_x25519) type = EVP_PKEY_X25519;
+ else if (argv[0] == atom_x448) type = EVP_PKEY_X448;
+ else return enif_make_badarg(env);
+
+ if (!(ctx = EVP_PKEY_CTX_new_id(type, NULL))) return enif_make_badarg(env);
+
+ if (!EVP_PKEY_keygen_init(ctx)) return enif_make_atom(env,"EVP_PKEY_keygen_init failed");
+ if (!EVP_PKEY_keygen(ctx, &pkey)) return enif_make_atom(env,"EVP_PKEY_keygen failed");
+
+ if (!EVP_PKEY_get_raw_public_key(pkey, NULL, &key_len))
+ return enif_make_atom(env,"EVP_PKEY_get_raw_public_key 1 failed");
+ if (!EVP_PKEY_get_raw_public_key(pkey,
+ enif_make_new_binary(env, key_len, &ret_pub),
+ &key_len))
+ return enif_make_atom(env,"EVP_PKEY_get_raw_public_key 2 failed");
+
+ if (!EVP_PKEY_get_raw_private_key(pkey, NULL, &key_len))
+ return enif_make_atom(env,"EVP_PKEY_get_raw_private_key 1 failed");
+ if (!EVP_PKEY_get_raw_private_key(pkey,
+ enif_make_new_binary(env, key_len, &ret_prv),
+ &key_len))
+ return enif_make_atom(env,"EVP_PKEY_get_raw_private_key 2 failed");
+
+ return enif_make_tuple2(env, ret_pub, ret_prv);
+#else
+ return atom_notsup;
+#endif
+}
+
/*================================================================*/
#define PKEY_BADARG -1
#define PKEY_NOTSUP 0
diff --git a/lib/crypto/c_src/otp_test_engine.c b/lib/crypto/c_src/otp_test_engine.c
index d0e23a2a3e..b6c9067964 100644
--- a/lib/crypto/c_src/otp_test_engine.c
+++ b/lib/crypto/c_src/otp_test_engine.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2017-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2017-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/lib/crypto/doc/src/Makefile b/lib/crypto/doc/src/Makefile
index aa987d2b39..2148062e78 100644
--- a/lib/crypto/doc/src/Makefile
+++ b/lib/crypto/doc/src/Makefile
@@ -89,6 +89,7 @@ debug opt valgrind:
clean clean_docs clean_tex:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(MAN6DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index af676d9021..85d5ccaa34 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1999</year><year>2017</year>
+ <year>1999</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -830,7 +830,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
</p>
<note>
<p>
- The state returned from this function can not be used
+ The state returned from this function cannot be used
to get a reproducable random sequence as from
the other
<seealso marker="stdlib:rand">rand</seealso>
@@ -920,7 +920,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
</p>
<note>
<p>
- The state returned from this function can not be used
+ The state returned from this function cannot be used
to get a reproducable random sequence as from
the other
<seealso marker="stdlib:rand">rand</seealso>
diff --git a/lib/crypto/doc/src/engine_keys.xml b/lib/crypto/doc/src/engine_keys.xml
index 38714fed8a..80d811c47e 100644
--- a/lib/crypto/doc/src/engine_keys.xml
+++ b/lib/crypto/doc/src/engine_keys.xml
@@ -40,7 +40,7 @@
</p>
<p>
An engine could among other tasks provide a storage for
- private or public keys. Such a storage could be made safer than the normal file system. Thoose techniques are not
+ private or public keys. Such a storage could be made safer than the normal file system. Those techniques are not
described in this User's Guide. Here we concentrate on how to use private or public keys stored in
such an engine.
</p>
diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml
index 66619c9e11..5e0851f6b8 100644
--- a/lib/crypto/doc/src/notes.xml
+++ b/lib/crypto/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1999</year><year>2017</year>
+ <year>1999</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,85 @@
</header>
<p>This document describes the changes made to the Crypto application.</p>
+<section><title>Crypto 4.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a node crash in <c>crypto:compute_key(ecdh,
+ ...)</c> when passing a wrongly typed Others
+ argument.</p>
+ <p>
+ Own Id: OTP-15194 Aux Id: ERL-673 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Crypto 4.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Removed two undocumented and erroneous functions
+ (<c>crypto:dh_generate_parameters/2</c> and
+ <c>crypto:dh_check/1</c>).</p>
+ <p>
+ Own Id: OTP-14956 Aux Id: ERL-579 </p>
+ </item>
+ <item>
+ <p>
+ Fixed bug causing VM crash if doing runtime upgrade of a
+ crypto module built against OpenSSL older than 0.9.8h.
+ Bug exists since OTP-20.2.</p>
+ <p>
+ Own Id: OTP-15088</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ A new <c>rand</c> plugin algorithm has been implemented
+ in <c>crypto</c>, that is: <c>crypto_cache</c>. It uses
+ strong random bytes as randomness source and caches them
+ to get good speed. See <c>crypto:rand_seed_alg/1</c>.</p>
+ <p>
+ Own Id: OTP-13370 Aux Id: PR-1573 </p>
+ </item>
+ <item>
+ <p>
+ Diffie-Hellman key functions are re-written with the
+ EVP_PKEY api.</p>
+ <p>
+ Own Id: OTP-14864</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Crypto 4.2.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a node crash in <c>crypto:compute_key(ecdh,
+ ...)</c> when passing a wrongly typed Others
+ argument.</p>
+ <p>
+ Own Id: OTP-15194 Aux Id: ERL-673 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Crypto 4.2.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/crypto/doc/src/usersguide.xml b/lib/crypto/doc/src/usersguide.xml
index e2ba1fe160..0124121433 100644
--- a/lib/crypto/doc/src/usersguide.xml
+++ b/lib/crypto/doc/src/usersguide.xml
@@ -4,7 +4,7 @@
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2003</year><year>2016</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/crypto/src/Makefile b/lib/crypto/src/Makefile
index edad0e6b61..1753ba4f36 100644
--- a/lib/crypto/src/Makefile
+++ b/lib/crypto/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
+# Copyright Ericsson AB 1999-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 46775989ae..835cadce47 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -107,12 +107,12 @@ stop() ->
application:stop(crypto).
supports()->
- {Hashs, PubKeys, Ciphers, Macs} = algorithms(),
-
+ {Hashs, PubKeys, Ciphers, Macs, Curves} = algorithms(),
[{hashs, Hashs},
{ciphers, Ciphers},
{public_keys, PubKeys},
- {macs, Macs}
+ {macs, Macs},
+ {curves, Curves}
].
info_lib() -> ?nif_stub.
@@ -586,9 +586,18 @@ generate_key(rsa, {ModulusSize, PublicExponent}, undefined) ->
{lists:sublist(Private, 2), Private}
end;
+
+generate_key(ecdh, Curve, undefined) when Curve == x448 ;
+ Curve == x25519 ->
+ evp_generate_key_nif(Curve);
generate_key(ecdh, Curve, PrivKey) ->
ec_key_generate(nif_curve_params(Curve), ensure_int_as_bin(PrivKey)).
+
+evp_generate_key_nif(_Curve) -> ?nif_stub.
+
+
+
compute_key(dh, OthersPublicKey, MyPrivateKey, DHParameters) ->
case dh_compute_key_nif(ensure_int_as_bin(OthersPublicKey),
ensure_int_as_bin(MyPrivateKey),
@@ -628,11 +637,18 @@ compute_key(srp, UserPublic, {HostPublic, HostPrivate},
srp_host_secret_nif(Verifier, ensure_int_as_bin(HostPrivate), Scrambler,
UserPubBin, Prime));
+compute_key(ecdh, Others, My, Curve) when Curve == x448 ;
+ Curve == x25519 ->
+ evp_compute_key_nif(Curve, ensure_int_as_bin(Others), ensure_int_as_bin(My));
+
compute_key(ecdh, Others, My, Curve) ->
ecdh_compute_key_nif(ensure_int_as_bin(Others),
nif_curve_params(Curve),
ensure_int_as_bin(My)).
+
+evp_compute_key_nif(_Curve, _OthersBin, _MyBin) -> ?nif_stub.
+
%%======================================================================
%% Engine functions
%%======================================================================
@@ -1144,7 +1160,11 @@ nif_curve_params({PrimeField, Curve, BasePoint, Order, CoFactor}) ->
{term_to_nif_prime(PrimeField), term_to_nif_curve(Curve), ensure_int_as_bin(BasePoint), ensure_int_as_bin(Order), ensure_int_as_bin(CoFactor)};
nif_curve_params(Curve) when is_atom(Curve) ->
%% named curve
- crypto_ec_curves:curve(Curve).
+ case Curve of
+ x448 -> {evp,Curve};
+ x25519 -> {evp,Curve};
+ _ -> crypto_ec_curves:curve(Curve)
+ end.
%% MISC --------------------------------------------------------------------
diff --git a/lib/crypto/src/crypto_ec_curves.erl b/lib/crypto/src/crypto_ec_curves.erl
index 9602a7e24b..a0a2f99601 100644
--- a/lib/crypto/src/crypto_ec_curves.erl
+++ b/lib/crypto/src/crypto_ec_curves.erl
@@ -3,41 +3,7 @@
-export([curve/1, curves/0]).
curves() ->
- CryptoSupport = crypto:supports(),
- PubKeys = proplists:get_value(public_keys, CryptoSupport),
- HasEC = proplists:get_bool(ecdh, PubKeys),
- HasGF2m = proplists:get_bool(ec_gf2m, PubKeys),
- FIPSMode = crypto:info_fips() == enabled,
- prime_curves(HasEC, FIPSMode) ++ characteristic_two_curves(HasGF2m, FIPSMode).
-
-
-prime_curves(true, true) ->
- [secp160k1,secp160r1,secp160r2,
- secp192r1,secp192k1,secp224k1,secp224r1,secp256k1,secp256r1,secp384r1,
- secp521r1,prime192v1,prime192v2,prime192v3,prime239v1,prime239v2,prime239v3,
- prime256v1,wtls7,wtls9,wtls12,
- brainpoolP160r1,brainpoolP160t1,brainpoolP192r1,brainpoolP192t1,
- brainpoolP224r1,brainpoolP224t1,brainpoolP256r1,brainpoolP256t1,
- brainpoolP320r1,brainpoolP320t1,brainpoolP384r1,brainpoolP384t1,
- brainpoolP512r1,brainpoolP512t1];
-prime_curves(true, false) ->
- [secp112r1,secp112r2,secp128r1,secp128r2,wtls6,wtls8]
- ++ prime_curves(true, true);
-prime_curves(_, _) ->
- [].
-
-characteristic_two_curves(true, true) ->
- [sect163k1,sect163r1,
- sect163r2,sect193r1,sect193r2,sect233k1,sect233r1,sect239k1,sect283k1,
- sect283r1,sect409k1,sect409r1,sect571k1,sect571r1,c2pnb163v1,c2pnb163v2,
- c2pnb163v3,c2pnb176v1,c2tnb191v1,c2tnb191v2,c2tnb191v3,c2pnb208w1,c2tnb239v1,
- c2tnb239v2,c2tnb239v3,c2pnb272w1,c2pnb304w1,c2tnb359v1,c2pnb368w1,c2tnb431r1,
- wtls3,wtls5,wtls10,wtls11];
-characteristic_two_curves(true, _) ->
- [sect113r1,sect113r2,sect131r1,sect131r2,wtls1,wtls4,ipsec3,ipsec4]
- ++ characteristic_two_curves(true, true);
-characteristic_two_curves(_, _) ->
- [].
+ proplists:get_value(curves, crypto:supports()) -- [x25519,x448].
curve(secp112r1) ->
{
diff --git a/lib/crypto/test/blowfish_SUITE.erl b/lib/crypto/test/blowfish_SUITE.erl
index c9033ac4f8..a931ebb47e 100644
--- a/lib/crypto/test/blowfish_SUITE.erl
+++ b/lib/crypto/test/blowfish_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index d148fa3856..1027a8d945 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[app,
+ {group, api_errors},
appup,
{group, fips},
{group, non_fips},
@@ -133,7 +134,7 @@ groups() ->
]},
{dh, [], [generate_compute,
compute_bug]},
- {ecdh, [], [compute, generate]},
+ {ecdh, [], [generate_all_supported, compute, generate]},
{srp, [], [generate_compute]},
{des_cbc, [], [block]},
{des_cfb, [], [block]},
@@ -170,7 +171,8 @@ groups() ->
{no_aes_ige256, [], [no_support, no_block]},
{no_chacha20_poly1305, [], [no_support, no_aead]},
{no_rc2_cbc, [], [no_support, no_block]},
- {no_rc4, [], [no_support, no_stream]}
+ {no_rc4, [], [no_support, no_stream]},
+ {api_errors, [], [api_errors_ecdh]}
].
%%-------------------------------------------------------------------
@@ -205,7 +207,7 @@ init_per_suite(Config) ->
Config
end
catch _:_ ->
- {skip, "Crypto did not start"}
+ {fail, "Crypto did not start"}
end.
end_per_suite(_Config) ->
@@ -238,6 +240,8 @@ init_per_group(non_fips, Config) ->
_NotEnabled ->
NonFIPSConfig
end;
+init_per_group(api_errors, Config) ->
+ Config;
init_per_group(GroupName, Config) ->
case atom_to_list(GroupName) of
"no_" ++ TypeStr ->
@@ -506,6 +510,33 @@ compute(Config) when is_list(Config) ->
Gen = proplists:get_value(compute, Config),
lists:foreach(fun do_compute/1, Gen).
%%--------------------------------------------------------------------
+generate_all_supported() ->
+ [{doc, " Test that all curves from crypto:ec_curves/0 returns two binaries"}].
+generate_all_supported(_Config) ->
+ Results =
+ [try
+ crypto:generate_key(ecdh, C)
+ of
+ {B1,B2} when is_binary(B1) and is_binary(B2) ->
+ %% That is, seems like it works as expected.
+ {ok,C};
+ Err ->
+ ct:log("ERROR: Curve ~p generated ~p", [C,Err]),
+ {error,{C,Err}}
+ catch
+ Cls:Err:Stack ->
+ ct:log("ERROR: Curve ~p exception ~p:~p~n~p", [C,Cls,Err,Stack]),
+ {error,{C,{Cls,Err}}}
+ end
+ || C <- crypto:ec_curves()
+ ],
+ OK = [C || {ok,C} <- Results],
+ ct:log("Ok (len=~p): ~p", [length(OK), OK]),
+ false = lists:any(fun({error,_}) -> true;
+ (_) -> false
+ end, Results).
+
+%%--------------------------------------------------------------------
generate() ->
[{doc, " Test crypto:generate_key"}].
generate(Config) when is_list(Config) ->
@@ -811,7 +842,7 @@ do_sign_verify({Type, Hash, Public, Private, Msg, Options}) ->
error:notsup when NotSupLow == true,
is_integer(LibVer),
LibVer < 16#10001000 ->
- %% Thoose opts where introduced in 1.0.1
+ %% Those opts where introduced in 1.0.1
ct:log("notsup but OK in old cryptolib crypto:sign(~p, ~p, ..., ..., ..., ~p)",
[Type,Hash,Options]),
true;
@@ -836,26 +867,69 @@ negative_verify(Type, Hash, Msg, Signature, Public, Options) ->
ok
end.
+-define(PUB_PRIV_ENC_DEC_CATCH(Type,Padding),
+ CC:EE ->
+ ct:log("~p:~p in ~p:~p/~p, line ~p.~n"
+ "Type = ~p~nPadding = ~p",
+ [CC,EE,?MODULE,?FUNCTION_NAME,?FUNCTION_ARITY,?LINE,(Type),(Padding)]),
+ MaybeUnsupported =
+ case crypto:info_lib() of
+ [{<<"OpenSSL">>,_,_}] ->
+ is_list(Padding) andalso
+ lists:any(fun(P) -> lists:member(P,(Padding)) end,
+ [{rsa_padding, rsa_pkcs1_oaep_padding},
+ {rsa_padding, rsa_sslv23_padding},
+ {rsa_padding, rsa_x931_padding}]);
+ _ ->
+ false
+ end,
+ case CC of
+ error when MaybeUnsupported ->
+ ct:comment("Padding unsupported?",[]);
+ _ ->
+ ct:fail({?FUNCTION_NAME,CC,EE,(Type),(Padding)})
+ end
+ ).
+
do_public_encrypt({Type, Public, Private, Msg, Padding}) ->
- PublicEcn = (catch crypto:public_encrypt(Type, Msg, Public, Padding)),
- case crypto:private_decrypt(Type, PublicEcn, Private, Padding) of
- Msg ->
- ok;
- Other ->
- ct:fail({{crypto, private_decrypt, [Type, PublicEcn, Private, Padding]}, {expected, Msg}, {got, Other}})
+ try
+ crypto:public_encrypt(Type, Msg, Public, Padding)
+ of
+ PublicEcn ->
+ try
+ crypto:private_decrypt(Type, PublicEcn, Private, Padding)
+ of
+ Msg ->
+ ok;
+ Other ->
+ ct:fail({{crypto, private_decrypt, [Type, PublicEcn, Private, Padding]}, {expected, Msg}, {got, Other}})
+ catch
+ ?PUB_PRIV_ENC_DEC_CATCH(Type, Padding)
+ end
+ catch
+ ?PUB_PRIV_ENC_DEC_CATCH(Type, Padding)
end.
-do_private_encrypt({_Type, _Public, _Private, _Msg, rsa_pkcs1_oaep_padding}) ->
- ok; %% Not supported by openssl
+
do_private_encrypt({Type, Public, Private, Msg, Padding}) ->
- PrivEcn = (catch crypto:private_encrypt(Type, Msg, Private, Padding)),
- case crypto:public_decrypt(Type, PrivEcn, Public, Padding) of
- Msg ->
- ok;
- Other ->
- ct:fail({{crypto, public_decrypt, [Type, PrivEcn, Public, Padding]}, {expected, Msg}, {got, Other}})
+ try
+ crypto:private_encrypt(Type, Msg, Private, Padding)
+ of
+ PrivEcn ->
+ try
+ crypto:public_decrypt(Type, PrivEcn, Public, Padding)
+ of
+ Msg ->
+ ok;
+ Other ->
+ ct:fail({{crypto, public_decrypt, [Type, PrivEcn, Public, Padding]}, {expected, Msg}, {got, Other}})
+ catch
+ ?PUB_PRIV_ENC_DEC_CATCH(Type, Padding)
+ end
+ catch
+ ?PUB_PRIV_ENC_DEC_CATCH(Type, Padding)
end.
-
+
do_generate_compute({srp = Type, UserPrivate, UserGenParams, UserComParams,
HostPublic, HostPrivate, HostGenParams, HostComParam, SessionKey}) ->
{UserPublic, UserPrivate} = crypto:generate_key(Type, UserGenParams, UserPrivate),
@@ -1241,7 +1315,12 @@ group_config(rsa = Type, Config) ->
end,
MsgPubEnc = <<"7896345786348 Asldi">>,
PubPrivEnc = [{rsa, PublicS, PrivateS, MsgPubEnc, rsa_pkcs1_padding},
+ {rsa, PublicS, PrivateS, MsgPubEnc, [{rsa_padding, rsa_pkcs1_padding}]},
+ {rsa, PublicS, PrivateS, MsgPubEnc, [{rsa_padding, rsa_sslv23_padding}]},
+ {rsa, PublicS, PrivateS, MsgPubEnc, [{rsa_padding, rsa_x931_padding}]},
rsa_oaep(),
+ rsa_oaep_label(),
+ rsa_oaep256(),
no_padding()
],
Generate = [{rsa, 1024, 3}, {rsa, 2048, 17}, {rsa, 3072, 65537}],
@@ -2334,7 +2413,32 @@ rsa_oaep() ->
hexstr2bin("4f456c502493bdc0ed2ab756a3a6ed4d67352a697d4216e93212b127a63d5411ce6fa98d5dbefd73263e3728142743818166ed7dd63687dd2a8ca1d2f4fbd8e1")],
%%Msg = hexstr2bin("6628194e12073db03ba94cda9ef9532397d50dba79b987004afefe34"),
Msg = hexstr2bin("750c4047f547e8e41411856523298ac9bae245efaf1397fbe56f9dd5"),
- {rsa, Public, Private, Msg, rsa_pkcs1_oaep_padding}.
+ {rsa, Public, Private, Msg, [{rsa_padding, rsa_pkcs1_oaep_padding}]}.
+
+rsa_oaep_label() ->
+ Public = [hexstr2bin("010001"),
+ hexstr2bin("a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0cbc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bdbf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb")],
+ Private = Public ++ [hexstr2bin("53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf119517ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d65a732c483116ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb04724dc7369b31def37d0cf539e9cfcdd3de653729ead5d1"),
+ hexstr2bin("d32737e7267ffe1341b2d5c0d150a81b586fb3132bed2f8d5262864a9cb9f30af38be448598d413a172efb802c21acf1c11c520c2f26a471dcad212eac7ca39d"),
+ hexstr2bin("cc8853d1d54da630fac004f471f281c7b8982d8224a490edbeb33d3e3d5cc93c4765703d1dd791642f1f116a0dd852be2419b2af72bfe9a030e860b0288b5d77"),
+ hexstr2bin("0e12bf1718e9cef5599ba1c3882fe8046a90874eefce8f2ccc20e4f2741fb0a33a3848aec9c9305fbecbd2d76819967d4671acc6431e4037968db37878e695c1"),
+ hexstr2bin("95297b0f95a2fa67d00707d609dfd4fc05c89dafc2ef6d6ea55bec771ea333734d9251e79082ecda866efef13c459e1a631386b7e354c899f5f112ca85d71583"),
+ hexstr2bin("4f456c502493bdc0ed2ab756a3a6ed4d67352a697d4216e93212b127a63d5411ce6fa98d5dbefd73263e3728142743818166ed7dd63687dd2a8ca1d2f4fbd8e1")],
+ Msg = hexstr2bin("750c4047f547e8e41411856523298ac9bae245efaf1397fbe56f9dd5"),
+ Lbl = hexstr2bin("1332a67ca7088f75c9b8fb5e3d072882"),
+ {rsa, Public, Private, Msg, [{rsa_padding, rsa_pkcs1_oaep_padding}, {rsa_oaep_label, Lbl}]}.
+
+rsa_oaep256() ->
+ Public = [hexstr2bin("010001"),
+ hexstr2bin("a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0cbc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bdbf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb")],
+ Private = Public ++ [hexstr2bin("53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf119517ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d65a732c483116ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb04724dc7369b31def37d0cf539e9cfcdd3de653729ead5d1"),
+ hexstr2bin("d32737e7267ffe1341b2d5c0d150a81b586fb3132bed2f8d5262864a9cb9f30af38be448598d413a172efb802c21acf1c11c520c2f26a471dcad212eac7ca39d"),
+ hexstr2bin("cc8853d1d54da630fac004f471f281c7b8982d8224a490edbeb33d3e3d5cc93c4765703d1dd791642f1f116a0dd852be2419b2af72bfe9a030e860b0288b5d77"),
+ hexstr2bin("0e12bf1718e9cef5599ba1c3882fe8046a90874eefce8f2ccc20e4f2741fb0a33a3848aec9c9305fbecbd2d76819967d4671acc6431e4037968db37878e695c1"),
+ hexstr2bin("95297b0f95a2fa67d00707d609dfd4fc05c89dafc2ef6d6ea55bec771ea333734d9251e79082ecda866efef13c459e1a631386b7e354c899f5f112ca85d71583"),
+ hexstr2bin("4f456c502493bdc0ed2ab756a3a6ed4d67352a697d4216e93212b127a63d5411ce6fa98d5dbefd73263e3728142743818166ed7dd63687dd2a8ca1d2f4fbd8e1")],
+ Msg = hexstr2bin("750c4047f547e8e41411856523298ac9bae245efaf1397fbe56f9dd5"),
+ {rsa, Public, Private, Msg, [{rsa_padding, rsa_pkcs1_oaep_padding}, {rsa_oaep_md, sha256}]}.
ecc() ->
%% http://point-at-infinity.org/ecc/nisttv
@@ -2510,3 +2614,14 @@ parse_rsp_cmac(Type, Key0, Msg0, Mlen0, Tlen, MAC0, Next, Acc) ->
I ->
parse_rsp(Type, Next, [{Type, Key, Msg, I, MAC}|Acc])
end.
+
+api_errors_ecdh(Config) when is_list(Config) ->
+ %% Check that we don't segfault when fed garbage.
+ Test = fun(Others, Curve) ->
+ {_Pub, Priv} = crypto:generate_key(ecdh, Curve),
+ crypto:compute_key(ecdh, Others, Priv, Curve)
+ end,
+ Others = [gurka, 0, <<0>>],
+ Curves = [gaffel, 0, sect571r1],
+ [_= (catch Test(O, C)) || O <- Others, C <- Curves],
+ ok.
diff --git a/lib/crypto/test/engine_SUITE.erl b/lib/crypto/test/engine_SUITE.erl
index 3f176f165d..bb9aa49b50 100644
--- a/lib/crypto/test/engine_SUITE.erl
+++ b/lib/crypto/test/engine_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -425,7 +425,7 @@ ctrl_cmd_string_optional(Config) when is_list(Config) ->
end.
%%%----------------------------------------------------------------
-%%% Pub/priv key storage tests. Thoose are for testing the crypto.erl
+%%% Pub/priv key storage tests. Those are for testing the crypto.erl
%%% support for using priv/pub keys stored in an engine.
sign_verify_rsa(Config) ->
diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk
index 778aff9d13..0d7b0e5575 100644
--- a/lib/crypto/vsn.mk
+++ b/lib/crypto/vsn.mk
@@ -1 +1 @@
-CRYPTO_VSN = 4.2.2
+CRYPTO_VSN = 4.3.1
diff --git a/lib/debugger/doc/src/Makefile b/lib/debugger/doc/src/Makefile
index cc0b8861d3..56d6085e9c 100644
--- a/lib/debugger/doc/src/Makefile
+++ b/lib/debugger/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -99,6 +99,7 @@ gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/debugger/doc/src/notes.xml b/lib/debugger/doc/src/notes.xml
index e71746e30d..9f7214ac69 100644
--- a/lib/debugger/doc/src/notes.xml
+++ b/lib/debugger/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -33,6 +33,21 @@
<p>This document describes the changes made to the Debugger
application.</p>
+<section><title>Debugger 4.2.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug where calling a fun inside a binary would
+ crash the Debugger. </p>
+ <p>
+ Own Id: OTP-14957 Aux Id: PR-1741 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Debugger 4.2.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/debugger/src/dbg_debugged.erl b/lib/debugger/src/dbg_debugged.erl
index 8b64a60a9c..5296b8d892 100644
--- a/lib/debugger/src/dbg_debugged.erl
+++ b/lib/debugger/src/dbg_debugged.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/debugger/src/dbg_icmd.erl b/lib/debugger/src/dbg_icmd.erl
index 4cd3dce670..0eb258567f 100644
--- a/lib/debugger/src/dbg_icmd.erl
+++ b/lib/debugger/src/dbg_icmd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -248,7 +248,7 @@ handle_int_msg({attached, AttPid}, Status, _Bs,
tell_attached({attached, M, Line, get(trace)}),
%% Give info about status and call level as well
- %% In this case, Status can not be exit_at
+ %% In this case, Status cannot be exit_at
Msg = case Status of
idle -> {func_at,M,Line,Le};
break -> {break_at,M,Line,Le};
@@ -467,7 +467,7 @@ mark_break(Cm, LineNo, Le) ->
parse_cmd(Cmd, LineNo) ->
{ok,Tokens,_} = erl_scan:string(Cmd, LineNo, [text]),
- {ok,Forms,Bs} = lib:extended_parse_exprs(Tokens),
+ {ok,Forms,Bs} = erl_eval:extended_parse_exprs(Tokens),
{Forms, Bs}.
%%====================================================================
diff --git a/lib/debugger/src/dbg_ieval.erl b/lib/debugger/src/dbg_ieval.erl
index 9840cebc1a..b6703d5d9e 100644
--- a/lib/debugger/src/dbg_ieval.erl
+++ b/lib/debugger/src/dbg_ieval.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/debugger/src/dbg_wx_mon.erl b/lib/debugger/src/dbg_wx_mon.erl
index 00aee62a87..08b20d3f69 100644
--- a/lib/debugger/src/dbg_wx_mon.erl
+++ b/lib/debugger/src/dbg_wx_mon.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/debugger/src/dbg_wx_trace.erl b/lib/debugger/src/dbg_wx_trace.erl
index 505d53005f..25f32ca7e7 100644
--- a/lib/debugger/src/dbg_wx_trace.erl
+++ b/lib/debugger/src/dbg_wx_trace.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -518,8 +518,8 @@ gui_cmd({user_command, Cmd}, State) ->
gui_cmd({edit, {Var, Value}}, State) ->
Window = dbg_wx_trace_win:get_window(State#state.win),
Val = case State#state.strings of
- [] -> dbg_wx_win:to_string("~999999lp",[Value]);
- [str_on] -> dbg_wx_win:to_string("~999999tp",[Value])
+ [] -> dbg_wx_win:to_string("~0lp",[Value]);
+ [str_on] -> dbg_wx_win:to_string("~0tp",[Value])
end,
case dbg_wx_win:entry(Window, "Edit variable", Var, {term, Val}) of
cancel ->
diff --git a/lib/debugger/src/dbg_wx_win.erl b/lib/debugger/src/dbg_wx_win.erl
index f1298154ab..4391ad1598 100644
--- a/lib/debugger/src/dbg_wx_win.erl
+++ b/lib/debugger/src/dbg_wx_win.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -275,7 +275,7 @@ entry(Parent, Title, Prompt, {Type, Value}) ->
verify(Type, Str) ->
case erl_scan:string(Str, 1, [text]) of
{ok, Tokens, _EndLine} when Type==term ->
- case lib:extended_parse_term(Tokens++[{dot, erl_anno:new(1)}]) of
+ case erl_eval:extended_parse_term(Tokens++[{dot, erl_anno:new(1)}]) of
{ok, Value} -> {edit, Value};
_Error ->
ignore
diff --git a/lib/debugger/src/debugger.app.src b/lib/debugger/src/debugger.app.src
index 37a41c1a56..c8a8b0fd43 100644
--- a/lib/debugger/src/debugger.app.src
+++ b/lib/debugger/src/debugger.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/debugger/test/guard_SUITE.erl b/lib/debugger/test/guard_SUITE.erl
index e781ea932f..02a1bbd66b 100644
--- a/lib/debugger/test/guard_SUITE.erl
+++ b/lib/debugger/test/guard_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/debugger/test/int_eval_SUITE.erl b/lib/debugger/test/int_eval_SUITE.erl
index da1d6734f8..0542e45142 100644
--- a/lib/debugger/test/int_eval_SUITE.erl
+++ b/lib/debugger/test/int_eval_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/debugger/test/int_eval_SUITE_data/my_int_eval_module.erl b/lib/debugger/test/int_eval_SUITE_data/my_int_eval_module.erl
index 384d61f051..aa26a44686 100644
--- a/lib/debugger/test/int_eval_SUITE_data/my_int_eval_module.erl
+++ b/lib/debugger/test/int_eval_SUITE_data/my_int_eval_module.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/debugger/vsn.mk b/lib/debugger/vsn.mk
index 57da7e5618..d62e5915a7 100644
--- a/lib/debugger/vsn.mk
+++ b/lib/debugger/vsn.mk
@@ -1 +1 @@
-DEBUGGER_VSN = 4.2.4
+DEBUGGER_VSN = 4.2.5
diff --git a/lib/dialyzer/doc/src/Makefile b/lib/dialyzer/doc/src/Makefile
index 3463b589e6..3ce777392b 100644
--- a/lib/dialyzer/doc/src/Makefile
+++ b/lib/dialyzer/doc/src/Makefile
@@ -91,6 +91,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/dialyzer/doc/src/notes.xml b/lib/dialyzer/doc/src/notes.xml
index 8d11252bff..4ec72eecd9 100644
--- a/lib/dialyzer/doc/src/notes.xml
+++ b/lib/dialyzer/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2006</year><year>2017</year>
+ <year>2006</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,60 @@
<p>This document describes the changes made to the Dialyzer
application.</p>
+<section><title>Dialyzer 3.3</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>Changed the default behaviour of <c>.erlang</c>
+ loading: <c>.erlang</c> is no longer loaded from the
+ current directory. <c>c:erlangrc(PathList)</c> can be
+ used to search and load an <c>.erlang</c> file from user
+ specified directories.</p> <p><c>escript</c>,
+ <c>erlc</c>, <c>dialyzer</c> and <c>typer</c> no longer
+ load an <c>.erlang</c> at all.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14439</p>
+ </item>
+ <item>
+ <p> Dialyzer can no longer read BEAM files created with
+ OTP 19 or earlier. </p>
+ <p>
+ Own Id: OTP-14493 Aux Id: PR-1434 </p>
+ </item>
+ <item>
+ <p> Speed up the computation of MD5 sums. </p>
+ <p>
+ Own Id: OTP-14937 Aux Id: PR-1719 </p>
+ </item>
+ <item>
+ <p> Fix a situation where Dialyzer unnecessarily
+ discarded contract information, resulting in missed
+ warnings. </p>
+ <p>
+ Own Id: OTP-14970 Aux Id: PR-1722 </p>
+ </item>
+ <item>
+ <p> The (not recommended) option <c>-Woverspecs</c> is
+ somewhat refined, and generates warnings in a few more
+ cases. </p>
+ <p>
+ Own Id: OTP-14982 Aux Id: OTP-14970, PR-1722 </p>
+ </item>
+ <item>
+ <p> Do not emit warnings for fun expressions residing in
+ code that cannot be run. This is consistent with how
+ Dialyzer treats other code that cannot be run. </p>
+ <p>
+ Own Id: OTP-15079 Aux Id: ERL-593 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Dialyzer 3.2.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl
index 1538174d4a..185c8c9ae6 100644
--- a/lib/dialyzer/src/dialyzer.erl
+++ b/lib/dialyzer/src/dialyzer.erl
@@ -409,6 +409,10 @@ message_to_string({extra_range, [M, F, A, ExtraRanges, SigRange]}) ->
io_lib:format("The specification for ~w:~tw/~w states that the function"
" might also return ~ts but the inferred return is ~ts\n",
[M, F, A, ExtraRanges, SigRange]);
+message_to_string({missing_range, [M, F, A, ExtraRanges, ContrRange]}) ->
+ io_lib:format("The success typing for ~w:~tw/~w implies that the function"
+ " might also return ~ts but the specification return is ~ts\n",
+ [M, F, A, ExtraRanges, ContrRange]);
message_to_string({overlapping_contract, [M, F, A]}) ->
io_lib:format("Overloaded contract for ~w:~tw/~w has overlapping domains;"
" such contracts are currently unsupported and are simply ignored\n",
diff --git a/lib/dialyzer/src/dialyzer_contracts.erl b/lib/dialyzer/src/dialyzer_contracts.erl
index 0df15e55f9..af7f4385ad 100644
--- a/lib/dialyzer/src/dialyzer_contracts.erl
+++ b/lib/dialyzer/src/dialyzer_contracts.erl
@@ -197,9 +197,11 @@ check_contracts(Contracts, Callgraph, FunTypes, ModOpaques) ->
false ->
[{MFA, Contract}|NewContracts]
end;
- {error, {extra_range, _, _}} ->
- %% do not treat extra range as an error in this check
- %% since that prevents discovering other actual errors
+ {range_warnings, _} ->
+ %% do not treat extra range, either in contract or
+ %% in success typing, as an error in this check
+ %% since that prevents discovering other actual
+ %% errors
[{MFA, Contract}|NewContracts];
{error, _Error} -> NewContracts
end;
@@ -210,14 +212,26 @@ check_contracts(Contracts, Callgraph, FunTypes, ModOpaques) ->
end,
orddict:from_list(lists:foldl(FoldFun, [], orddict:to_list(FunTypes))).
+-type check_contract_return() ::
+ 'ok'
+ | {'error',
+ 'invalid_contract'
+ | {'opaque_mismatch', erl_types:erl_type()}
+ | {'overlapping_contract', [module() | atom() | byte()]}
+ | string()}
+ | {'range_warnings',
+ [{'error', {'extra_range' | 'missing_range',
+ erl_types:erl_type(),
+ erl_types:erl_type()}}]}.
+
%% Checks all components of a contract
--spec check_contract(#contract{}, erl_types:erl_type()) -> 'ok' | {'error', term()}.
+-spec check_contract(#contract{}, erl_types:erl_type()) -> check_contract_return().
check_contract(Contract, SuccType) ->
check_contract(Contract, SuccType, 'universe').
-spec check_contract(#contract{}, erl_types:erl_type(), erl_types:opaques()) ->
- 'ok' | {'error', term()}.
+ check_contract_return().
check_contract(#contract{contracts = Contracts}, SuccType, Opaques) ->
try
@@ -290,15 +304,23 @@ check_contract_inf_list([], _SuccType, _Opaques, OM) ->
check_extraneous([], _SuccType) -> ok;
check_extraneous([C|Cs], SuccType) ->
case check_extraneous_1(C, SuccType) of
- ok -> check_extraneous(Cs, SuccType);
- Error -> Error
+ {error, invalid_contract} = Error ->
+ Error;
+ {error, {extra_range, _, _}} = Error ->
+ {range_warnings, [Error | check_missing(C, SuccType)]};
+ ok ->
+ case check_missing(C, SuccType) of
+ [] -> check_extraneous(Cs, SuccType);
+ ErrorL -> {range_warnings, ErrorL}
+ end
end.
check_extraneous_1(Contract, SuccType) ->
CRng = erl_types:t_fun_range(Contract),
CRngs = erl_types:t_elements(CRng),
STRng = erl_types:t_fun_range(SuccType),
- ?debug("CR = ~tp\nSR = ~tp\n", [CRngs, STRng]),
+ ?debug("\nCR = ~ts\nSR = ~ts\n", [erl_types:t_to_string(CRng),
+ erl_types:t_to_string(STRng)]),
case [CR || CR <- CRngs,
erl_types:t_is_none(erl_types:t_inf(CR, STRng))] of
[] ->
@@ -341,6 +363,18 @@ map_part(Type) ->
is_empty_map(Type) ->
erl_types:t_is_equal(Type, erl_types:t_from_term(#{})).
+check_missing(Contract, SuccType) ->
+ CRng = erl_types:t_fun_range(Contract),
+ STRng = erl_types:t_fun_range(SuccType),
+ STRngs = erl_types:t_elements(STRng),
+ ?debug("\nCR = ~ts\nSR = ~ts\n", [erl_types:t_to_string(CRng),
+ erl_types:t_to_string(STRng)]),
+ case [STR || STR <- STRngs,
+ erl_types:t_is_none(erl_types:t_inf(STR, CRng))] of
+ [] -> [];
+ STRs -> [{error, {missing_range, erl_types:t_sup(STRs), CRng}}]
+ end.
+
%% This is the heart of the "range function"
-spec process_contracts([contract_pair()], [erl_types:erl_type()]) ->
erl_types:erl_type().
@@ -712,22 +746,30 @@ get_invalid_contract_warnings_funs([{MFA, {FileLine, Contract, _Xtra}}|Left],
[W|Acc];
{error, {overlapping_contract, []}} ->
[overlapping_contract_warning(MFA, WarningInfo)|Acc];
- {error, {extra_range, ExtraRanges, STRange}} ->
- Warn =
- case t_from_forms_without_remote(Contract#contract.forms,
- MFA, RecDict) of
- {ok, NoRemoteType} ->
- CRet = erl_types:t_fun_range(NoRemoteType),
- erl_types:t_is_subtype(ExtraRanges, CRet);
- unsupported ->
- true
- end,
- case Warn of
- true ->
- [extra_range_warning(MFA, WarningInfo, ExtraRanges, STRange)|Acc];
- false ->
- Acc
- end;
+ {range_warnings, Errors} ->
+ Fun =
+ fun({error, {extra_range, ExtraRanges, STRange}}, Acc0) ->
+ Warn =
+ case t_from_forms_without_remote(Contract#contract.forms,
+ MFA, RecDict) of
+ {ok, NoRemoteType} ->
+ CRet = erl_types:t_fun_range(NoRemoteType),
+ erl_types:t_is_subtype(ExtraRanges, CRet);
+ unsupported ->
+ true
+ end,
+ case Warn of
+ true ->
+ [extra_range_warning(MFA, WarningInfo,
+ ExtraRanges, STRange)|Acc0];
+ false ->
+ Acc0
+ end;
+ ({error, {missing_range, ExtraRanges, CRange}}, Acc0) ->
+ [missing_range_warning(MFA, WarningInfo,
+ ExtraRanges, CRange)|Acc0]
+ end,
+ lists:foldl(Fun, Acc, Errors);
{error, Msg} ->
[{?WARN_CONTRACT_SYNTAX, WarningInfo, Msg}|Acc];
ok ->
@@ -745,6 +787,9 @@ get_invalid_contract_warnings_funs([{MFA, {FileLine, Contract, _Xtra}}|Left],
{error, _} ->
[invalid_contract_warning(MFA, WarningInfo, BifSig, RecDict)
|Acc];
+ {range_warnings, _} ->
+ picky_contract_check(CSig, BifSig, MFA, WarningInfo,
+ Contract, RecDict, Acc);
ok ->
picky_contract_check(CSig, BifSig, MFA, WarningInfo,
Contract, RecDict, Acc)
@@ -778,6 +823,12 @@ extra_range_warning({M, F, A}, WarningInfo, ExtraRanges, STRange) ->
{?WARN_CONTRACT_SUPERTYPE, WarningInfo,
{extra_range, [M, F, A, ERangesStr, STRangeStr]}}.
+missing_range_warning({M, F, A}, WarningInfo, ExtraRanges, CRange) ->
+ ERangesStr = erl_types:t_to_string(ExtraRanges),
+ CRangeStr = erl_types:t_to_string(CRange),
+ {?WARN_CONTRACT_SUBTYPE, WarningInfo,
+ {missing_range, [M, F, A, ERangesStr, CRangeStr]}}.
+
picky_contract_check(CSig0, Sig0, MFA, WarningInfo, Contract, RecDict, Acc) ->
CSig = erl_types:t_abstract_records(CSig0, RecDict),
Sig = erl_types:t_abstract_records(Sig0, RecDict),
diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl
index c5f93a3392..45b4abb253 100644
--- a/lib/dialyzer/src/dialyzer_dataflow.erl
+++ b/lib/dialyzer/src/dialyzer_dataflow.erl
@@ -102,6 +102,8 @@
| 'undefined', % race
fun_homes :: dict:dict(label(), mfa())
| 'undefined', % race
+ reachable_funs :: sets:set(label())
+ | 'undefined', % race
plt :: dialyzer_plt:plt()
| 'undefined', % race
opaques :: [type()]
@@ -269,9 +271,11 @@ traverse(Tree, Map, State) ->
case state__warning_mode(State) of
true -> {State, Map, Type};
false ->
- State2 = state__add_work(get_label(Tree), State),
+ FunLbl = get_label(Tree),
+ State2 = state__add_work(FunLbl, State),
State3 = state__update_fun_env(Tree, Map, State2),
- {State3, Map, Type}
+ State4 = state__add_reachable(FunLbl, State3),
+ {State4, Map, Type}
end;
'let' ->
handle_let(Tree, Map, State);
@@ -3039,25 +3043,35 @@ state__new(Callgraph, Codeserver, Tree, Plt, Module, Records) ->
{TreeMap, FunHomes} = build_tree_map(Tree, Callgraph),
Funs = dict:fetch_keys(TreeMap),
FunTab = init_fun_tab(Funs, dict:new(), TreeMap, Callgraph, Plt),
- ExportedFuns =
- [Fun || Fun <- Funs--[top], dialyzer_callgraph:is_escaping(Fun, Callgraph)],
- Work = init_work(ExportedFuns),
+ ExportedFunctions =
+ [Fun ||
+ Fun <- Funs--[top],
+ dialyzer_callgraph:is_escaping(Fun, Callgraph),
+ dialyzer_callgraph:lookup_name(Fun, Callgraph) =/= error
+ ],
+ Work = init_work(ExportedFunctions),
Env = lists:foldl(fun(Fun, Env) -> dict:store(Fun, map__new(), Env) end,
dict:new(), Funs),
#state{callgraph = Callgraph, codeserver = Codeserver,
envs = Env, fun_tab = FunTab, fun_homes = FunHomes, opaques = Opaques,
plt = Plt, races = dialyzer_races:new(), records = Records,
warning_mode = false, warnings = [], work = Work, tree_map = TreeMap,
- module = Module}.
+ module = Module, reachable_funs = sets:new()}.
state__warning_mode(#state{warning_mode = WM}) ->
WM.
state__set_warning_mode(#state{tree_map = TreeMap, fun_tab = FunTab,
- races = Races} = State) ->
+ races = Races, callgraph = Callgraph,
+ reachable_funs = ReachableFuns} = State) ->
?debug("==========\nStarting warning pass\n==========\n", []),
Funs = dict:fetch_keys(TreeMap),
- State#state{work = init_work([top|Funs--[top]]),
+ Work =
+ [Fun ||
+ Fun <- Funs--[top],
+ dialyzer_callgraph:lookup_name(Fun, Callgraph) =/= error orelse
+ sets:is_element(Fun, ReachableFuns)],
+ State#state{work = init_work(Work),
fun_tab = FunTab, warning_mode = true,
races = dialyzer_races:put_race_analysis(true, Races)}.
@@ -3149,7 +3163,8 @@ state__get_race_warnings(#state{races = Races} = State) ->
State1#state{races = Races1}.
state__get_warnings(#state{tree_map = TreeMap, fun_tab = FunTab,
- callgraph = Callgraph, plt = Plt} = State) ->
+ callgraph = Callgraph, plt = Plt,
+ reachable_funs = ReachableFuns} = State) ->
FoldFun =
fun({top, _}, AccState) -> AccState;
({FunLbl, Fun}, AccState) ->
@@ -3184,7 +3199,12 @@ state__get_warnings(#state{tree_map = TreeMap, fun_tab = FunTab,
GenRet = dialyzer_contracts:get_contract_return(C),
not t_is_unit(GenRet)
end,
- case Warn of
+ %% Do not output warnings for unreachable funs.
+ case
+ Warn andalso
+ (dialyzer_callgraph:lookup_name(FunLbl, Callgraph) =/= error
+ orelse sets:is_element(FunLbl, ReachableFuns))
+ of
true ->
case classify_returns(Fun) of
no_match ->
@@ -3255,6 +3275,10 @@ state__get_args_and_status(Tree, #state{fun_tab = FunTab}) ->
{ok, {ArgTypes, _}} -> {ArgTypes, true}
end.
+state__add_reachable(FunLbl, #state{reachable_funs = ReachableFuns}=State) ->
+ NewReachableFuns = sets:add_element(FunLbl, ReachableFuns),
+ State#state{reachable_funs = NewReachableFuns}.
+
build_tree_map(Tree, Callgraph) ->
Fun =
fun(T, {Dict, Homes, FunLbls} = Acc) ->
diff --git a/lib/dialyzer/src/typer.erl b/lib/dialyzer/src/typer.erl
index 9d3d9ce438..5a1b8619c9 100644
--- a/lib/dialyzer/src/typer.erl
+++ b/lib/dialyzer/src/typer.erl
@@ -401,7 +401,7 @@ get_type({{M, F, A} = MFA, Range, Arg}, CodeServer, Records) ->
Sig = erl_types:t_fun(Arg, Range),
case dialyzer_contracts:check_contract(Contract, Sig) of
ok -> {{F, A}, {contract, Contract}};
- {error, {extra_range, _, _}} ->
+ {range_warnings, _} ->
{{F, A}, {contract, Contract}};
{error, {overlapping_contract, []}} ->
{{F, A}, {contract, Contract}};
@@ -980,7 +980,7 @@ fatal_error(Slogan) ->
mode_error(OldMode, NewMode) ->
Msg = io_lib:format("Mode was previously set to '~s'; "
- "can not set it to '~s' now",
+ "cannot set it to '~s' now",
[OldMode, NewMode]),
fatal_error(Msg).
diff --git a/lib/dialyzer/test/options1_SUITE_data/results/compiler b/lib/dialyzer/test/options1_SUITE_data/results/compiler
index cbb5115c91..e1dc038800 100644
--- a/lib/dialyzer/test/options1_SUITE_data/results/compiler
+++ b/lib/dialyzer/test/options1_SUITE_data/results/compiler
@@ -28,7 +28,7 @@ cerl_inline.erl:2750: The pattern <{[], L, D}, Vs> can never match the type <[1.
cerl_inline.erl:2752: The pattern <{[], _L, D}, Vs> can never match the type <[1..255,...],[any()]>
cerl_inline.erl:2754: The pattern <{F, L, D}, Vs> can never match the type <[1..255,...],[any()]>
cerl_inline.erl:2756: The pattern <{F, _L, D}, Vs> can never match the type <[1..255,...],[any()]>
-compile.erl:788: The pattern {'error', Es} can never match the type {'ok',<<_:64,_:_*8>>}
+compile.erl:792: The pattern {'error', Es} can never match the type {'ok',<<_:64,_:_*8>>}
core_lint.erl:473: The pattern <{'c_atom', _, 'all'}, 'binary', _Def, St> can never match the type <_,#c_nil{} | {'c_atom' | 'c_char' | 'c_float' | 'c_int' | 'c_string' | 'c_tuple',_,_} | #c_cons{hd::#c_nil{} | {'c_atom' | 'c_char' | 'c_float' | 'c_int' | 'c_string' | 'c_tuple',_,_} | #c_cons{hd::{_,_} | {_,_,_} | {_,_,_,_},tl::{_,_} | {_,_,_} | {_,_,_,_}},tl::#c_nil{} | {'c_atom' | 'c_char' | 'c_float' | 'c_int' | 'c_string' | 'c_tuple',_,_} | #c_cons{hd::{_,_} | {_,_,_} | {_,_,_,_},tl::{_,_} | {_,_,_} | {_,_,_,_}}},[any()],_>
core_lint.erl:505: The pattern <_Req, 'unknown', St> can never match the type <non_neg_integer(),non_neg_integer(),_>
sys_pre_expand.erl:625: Call to missing or unexported function erlang:hash/2
diff --git a/lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_validator.erl b/lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_validator.erl
index ea92613781..3606b21932 100644
--- a/lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_validator.erl
+++ b/lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_validator.erl
@@ -272,7 +272,7 @@ valfun_1(if_end, Vst) ->
valfun_1({try_case_end,Src}, Vst) ->
assert_term(Src, Vst),
kill_state(Vst);
-%% Instructions that can not cause exceptions
+%% Instructions that cannot cause exceptions
valfun_1({move,Src,Dst}, Vst) ->
Type = get_term_type(Src, Vst),
set_type_reg(Type, Dst, Vst);
diff --git a/lib/dialyzer/test/options1_SUITE_data/src/compiler/compile.erl b/lib/dialyzer/test/options1_SUITE_data/src/compiler/compile.erl
index 7e5ccde2fd..6838cf6734 100644
--- a/lib/dialyzer/test/options1_SUITE_data/src/compiler/compile.erl
+++ b/lib/dialyzer/test/options1_SUITE_data/src/compiler/compile.erl
@@ -228,11 +228,15 @@ os_process_size() ->
case os:type() of
{unix, sunos} ->
Size = os:cmd("ps -o vsz -p " ++ os:getpid() ++ " | tail -1"),
- list_to_integer(lib:nonl(Size));
+ list_to_integer(nonl(Size));
_ ->
0
end.
+nonl([$\n]) -> [];
+nonl([]) -> [];
+nonl([H|T]) -> [H|nonl(T)].
+
run_tc({Name,Fun}, St) ->
Before0 = statistics(runtime),
Val = (catch Fun(St)),
diff --git a/lib/dialyzer/test/overspecs_SUITE_data/dialyzer_options b/lib/dialyzer/test/overspecs_SUITE_data/dialyzer_options
new file mode 100644
index 0000000000..ff4517e59d
--- /dev/null
+++ b/lib/dialyzer/test/overspecs_SUITE_data/dialyzer_options
@@ -0,0 +1 @@
+{dialyzer_options, [{warnings, [overspecs]}]}.
diff --git a/lib/dialyzer/test/overspecs_SUITE_data/results/iodata b/lib/dialyzer/test/overspecs_SUITE_data/results/iodata
new file mode 100644
index 0000000000..d9c70330ec
--- /dev/null
+++ b/lib/dialyzer/test/overspecs_SUITE_data/results/iodata
@@ -0,0 +1,2 @@
+
+iodata.erl:7: The success typing for iodata:encode/2 implies that the function might also return integer() but the specification return is binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | byte(),binary() | [])
diff --git a/lib/dialyzer/test/overspecs_SUITE_data/results/iolist b/lib/dialyzer/test/overspecs_SUITE_data/results/iolist
new file mode 100644
index 0000000000..ca556f017c
--- /dev/null
+++ b/lib/dialyzer/test/overspecs_SUITE_data/results/iolist
@@ -0,0 +1,2 @@
+
+iolist.erl:7: The success typing for iolist:encode/2 implies that the function might also return integer() but the specification return is maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | byte(),binary() | [])
diff --git a/lib/dialyzer/test/overspecs_SUITE_data/src/iodata.erl b/lib/dialyzer/test/overspecs_SUITE_data/src/iodata.erl
new file mode 100644
index 0000000000..caa44f6c91
--- /dev/null
+++ b/lib/dialyzer/test/overspecs_SUITE_data/src/iodata.erl
@@ -0,0 +1,41 @@
+-module(iodata).
+
+%% A small part of beam_asm.
+
+-export([encode/2]).
+
+-spec encode(non_neg_integer(), integer()) -> iodata(). % extra range binary()
+
+encode(Tag, N) when Tag >= 0, N < 0 ->
+ encode1(Tag, negative_to_bytes(N));
+encode(Tag, N) when Tag >= 0, N < 16 ->
+ (N bsl 4) bor Tag; % not in the specification
+encode(Tag, N) when Tag >= 0, N < 16#800 ->
+ [((N bsr 3) band 2#11100000) bor Tag bor 2#00001000, N band 16#ff];
+encode(Tag, N) when Tag >= 0 ->
+ encode1(Tag, to_bytes(N)).
+
+encode1(Tag, Bytes) ->
+ case iolist_size(Bytes) of
+ Num when 2 =< Num, Num =< 8 ->
+ [((Num-2) bsl 5) bor 2#00011000 bor Tag| Bytes];
+ Num when 8 < Num ->
+ [2#11111000 bor Tag, encode(0, Num-9)| Bytes]
+ end.
+
+to_bytes(N) ->
+ Bin = binary:encode_unsigned(N),
+ case Bin of
+ <<0:1,_/bits>> -> Bin;
+ <<1:1,_/bits>> -> [0,Bin]
+ end.
+
+negative_to_bytes(N) when N >= -16#8000 ->
+ <<N:16>>;
+negative_to_bytes(N) ->
+ Bytes = byte_size(binary:encode_unsigned(-N)),
+ Bin = <<N:Bytes/unit:8>>,
+ case Bin of
+ <<0:1,_/bits>> -> [16#ff,Bin];
+ <<1:1,_/bits>> -> Bin
+ end.
diff --git a/lib/dialyzer/test/overspecs_SUITE_data/src/iolist.erl b/lib/dialyzer/test/overspecs_SUITE_data/src/iolist.erl
new file mode 100644
index 0000000000..7cceeda24e
--- /dev/null
+++ b/lib/dialyzer/test/overspecs_SUITE_data/src/iolist.erl
@@ -0,0 +1,41 @@
+-module(iolist).
+
+%% A small part of beam_asm.
+
+-export([encode/2]).
+
+-spec encode(non_neg_integer(), integer()) -> iolist().
+
+encode(Tag, N) when Tag >= 0, N < 0 ->
+ encode1(Tag, negative_to_bytes(N));
+encode(Tag, N) when Tag >= 0, N < 16 ->
+ (N bsl 4) bor Tag; % not in the specification
+encode(Tag, N) when Tag >= 0, N < 16#800 ->
+ [((N bsr 3) band 2#11100000) bor Tag bor 2#00001000, N band 16#ff];
+encode(Tag, N) when Tag >= 0 ->
+ encode1(Tag, to_bytes(N)).
+
+encode1(Tag, Bytes) ->
+ case iolist_size(Bytes) of
+ Num when 2 =< Num, Num =< 8 ->
+ [((Num-2) bsl 5) bor 2#00011000 bor Tag| Bytes];
+ Num when 8 < Num ->
+ [2#11111000 bor Tag, encode(0, Num-9)| Bytes]
+ end.
+
+to_bytes(N) ->
+ Bin = binary:encode_unsigned(N),
+ case Bin of
+ <<0:1,_/bits>> -> Bin;
+ <<1:1,_/bits>> -> [0,Bin]
+ end.
+
+negative_to_bytes(N) when N >= -16#8000 ->
+ <<N:16>>;
+negative_to_bytes(N) ->
+ Bytes = byte_size(binary:encode_unsigned(-N)),
+ Bin = <<N:Bytes/unit:8>>,
+ case Bin of
+ <<0:1,_/bits>> -> [16#ff,Bin];
+ <<1:1,_/bits>> -> Bin
+ end.
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber.erl b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber.erl
index 1d065b3723..88b464a721 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber.erl
@@ -300,7 +300,7 @@ gen_encode_prim(_Erules,D,DoTag,Value) when record(D,type) ->
'ASN1_OPEN_TYPE' ->
emit_encode_func('open_type', Value,DoTag);
XX ->
- exit({'can not encode' ,XX})
+ exit({'cannot encode' ,XX})
end.
@@ -562,7 +562,7 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Length,_Form,OptOrMand) ->
BytesVar,","]),
false;
Other ->
- exit({'can not decode' ,Other})
+ exit({'cannot decode' ,Other})
end,
NewLength = case DoLength of
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber_bin_v2.erl b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber_bin_v2.erl
index 9164ec6551..573bb15c92 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber_bin_v2.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber_bin_v2.erl
@@ -290,7 +290,7 @@ gen_encode_prim(_Erules,D,DoTag,Value) when record(D,type) ->
'ASN1_OPEN_TYPE' ->
emit_encode_func('open_type', Value,DoTag);
XX ->
- exit({'can not encode' ,XX})
+ exit({'cannot encode' ,XX})
end.
@@ -602,7 +602,7 @@ gen_dec_prim(_Erules,Att,BytesVar,DoTag,_TagIn,_Form,_OptOrMand) ->
BytesVar,","]),
add_func({decode_open_type_as_binary,2});
Other ->
- exit({'can not decode' ,Other})
+ exit({'cannot decode' ,Other})
end,
case {DoTag,NewTypeName} of
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_esi.erl b/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_esi.erl
index a48f73274b..52db2d9096 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_esi.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_esi.erl
@@ -285,7 +285,7 @@ eval(Info,"GET",CGIBody,Modules) ->
"~n Modules: ~p",[Modules]),
case auth(CGIBody,Modules) of
true ->
- case lib:eval_str(string:concat(CGIBody,". ")) of
+ case erl_eval:eval_str(string:concat(CGIBody,". ")) of
{error,Reason} ->
?vlog("eval -> error:"
"~n Reason: ~p",[Reason]),
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_lib.erl b/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_lib.erl
index 4008f8d789..9e0cdac2dc 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_lib.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_lib.erl
@@ -779,7 +779,7 @@ error_desc(no_transaction) -> "Operation not allowed outside transactions";
error_desc(combine_error) -> "Table options were ilegally combined";
error_desc(bad_index) -> "Index already exists or was out of bounds";
error_desc(already_exists) -> "Some schema option we try to set is already on";
-error_desc(index_exists)-> "Some ops can not be performed on tabs with index";
+error_desc(index_exists)-> "Some ops cannot be performed on tabs with index";
error_desc(no_exists)-> "Tried to perform op on non-existing (non alive) item";
error_desc(system_limit) -> "Some system_limit was exhausted";
error_desc(mnesia_down) -> "A transaction involving objects at some remote "
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_tm.erl b/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_tm.erl
index af49ceff72..b4e9edb7ce 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_tm.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_tm.erl
@@ -1529,7 +1529,7 @@ commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) ->
?eval_debug_fun({?MODULE, commit_participant, pre}, [{tid, Tid}]),
case catch mnesia_schema:prepare_commit(Tid, C0, {part, Coord}) of
{Modified, C, DumperMode} when record(C, commit) ->
- %% If we can not find any local unclear decision
+ %% If we cannot find any local unclear decision
%% we should presume abort at startup recovery
case lists:member(node(), DiscNs) of
false ->
diff --git a/lib/dialyzer/test/small_SUITE_data/results/maps_sum b/lib/dialyzer/test/small_SUITE_data/results/maps_sum
index b29ac77d88..daa099e490 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/maps_sum
+++ b/lib/dialyzer/test/small_SUITE_data/results/maps_sum
@@ -1,4 +1,4 @@
-maps_sum.erl:15: Invalid type specification for function maps_sum:wrong1/1. The success typing is (maps:iterator() | map()) -> any()
+maps_sum.erl:15: Invalid type specification for function maps_sum:wrong1/1. The success typing is (maps:iterator(_,_) | map()) -> any()
maps_sum.erl:26: Function wrong2/1 has no local return
maps_sum.erl:27: The call lists:foldl(fun((_,_,_) -> any()),0,Data::any()) will never return since it differs in the 1st argument from the success typing arguments: (fun((_,_) -> any()),any(),[any()])
diff --git a/lib/dialyzer/test/small_SUITE_data/results/unused_funs b/lib/dialyzer/test/small_SUITE_data/results/unused_funs
new file mode 100644
index 0000000000..c468457ead
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/unused_funs
@@ -0,0 +1,5 @@
+
+unused_funs.erl:10: The pattern 'error' can never match the type 'other_error'
+unused_funs.erl:15: Function not_used/0 will never be called
+unused_funs.erl:19: Function foo/1 will never be called
+unused_funs.erl:7: Function test/0 has no local return
diff --git a/lib/dialyzer/test/small_SUITE_data/src/unused_funs.erl b/lib/dialyzer/test/small_SUITE_data/src/unused_funs.erl
new file mode 100644
index 0000000000..c24cf3ea81
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/unused_funs.erl
@@ -0,0 +1,21 @@
+%% See also ERL-593.
+
+-module(unused_funs).
+
+-export([test/0]).
+
+test() -> % "has no local return"
+ Var = outer_scope,
+ case other_error of
+ error -> % "can never match"
+ %% No warnings "no local return" and "_ = 1 can never match 0" (!)
+ foo(fun() -> {Var, 1 = 0} end)
+ end.
+
+not_used() -> % "will never be called"
+ %% No warnings "no local return" and "1 can never match 0".
+ foo(fun() -> 1 = 0 end).
+
+foo(Fun) -> % "will never be called"
+ 1 = 0, % No pattern match warning (foo/1 is not traversed at all).
+ Fun().
diff --git a/lib/dialyzer/test/specdiffs_SUITE_data/dialyzer_options b/lib/dialyzer/test/specdiffs_SUITE_data/dialyzer_options
new file mode 100644
index 0000000000..56b36f2ed4
--- /dev/null
+++ b/lib/dialyzer/test/specdiffs_SUITE_data/dialyzer_options
@@ -0,0 +1 @@
+{dialyzer_options, [{warnings, [specdiffs]}]}.
diff --git a/lib/dialyzer/test/specdiffs_SUITE_data/results/iodata b/lib/dialyzer/test/specdiffs_SUITE_data/results/iodata
new file mode 100644
index 0000000000..3fb12fe000
--- /dev/null
+++ b/lib/dialyzer/test/specdiffs_SUITE_data/results/iodata
@@ -0,0 +1,3 @@
+
+iodata.erl:7: The specification for iodata:encode/2 states that the function might also return binary() but the inferred return is nonempty_maybe_improper_list(<<_:8,_:_*8>> | nonempty_maybe_improper_list(<<_:8,_:_*8>> | nonempty_maybe_improper_list(any(),<<_:8,_:_*8>> | []) | byte(),<<_:8,_:_*8>> | []) | integer(),<<_:8,_:_*8>> | []) | integer()
+iodata.erl:7: The success typing for iodata:encode/2 implies that the function might also return integer() but the specification return is binary() | maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | byte(),binary() | [])
diff --git a/lib/dialyzer/test/specdiffs_SUITE_data/results/iolist b/lib/dialyzer/test/specdiffs_SUITE_data/results/iolist
new file mode 100644
index 0000000000..ca556f017c
--- /dev/null
+++ b/lib/dialyzer/test/specdiffs_SUITE_data/results/iolist
@@ -0,0 +1,2 @@
+
+iolist.erl:7: The success typing for iolist:encode/2 implies that the function might also return integer() but the specification return is maybe_improper_list(binary() | maybe_improper_list(any(),binary() | []) | byte(),binary() | [])
diff --git a/lib/dialyzer/test/specdiffs_SUITE_data/src/iodata.erl b/lib/dialyzer/test/specdiffs_SUITE_data/src/iodata.erl
new file mode 100644
index 0000000000..caa44f6c91
--- /dev/null
+++ b/lib/dialyzer/test/specdiffs_SUITE_data/src/iodata.erl
@@ -0,0 +1,41 @@
+-module(iodata).
+
+%% A small part of beam_asm.
+
+-export([encode/2]).
+
+-spec encode(non_neg_integer(), integer()) -> iodata(). % extra range binary()
+
+encode(Tag, N) when Tag >= 0, N < 0 ->
+ encode1(Tag, negative_to_bytes(N));
+encode(Tag, N) when Tag >= 0, N < 16 ->
+ (N bsl 4) bor Tag; % not in the specification
+encode(Tag, N) when Tag >= 0, N < 16#800 ->
+ [((N bsr 3) band 2#11100000) bor Tag bor 2#00001000, N band 16#ff];
+encode(Tag, N) when Tag >= 0 ->
+ encode1(Tag, to_bytes(N)).
+
+encode1(Tag, Bytes) ->
+ case iolist_size(Bytes) of
+ Num when 2 =< Num, Num =< 8 ->
+ [((Num-2) bsl 5) bor 2#00011000 bor Tag| Bytes];
+ Num when 8 < Num ->
+ [2#11111000 bor Tag, encode(0, Num-9)| Bytes]
+ end.
+
+to_bytes(N) ->
+ Bin = binary:encode_unsigned(N),
+ case Bin of
+ <<0:1,_/bits>> -> Bin;
+ <<1:1,_/bits>> -> [0,Bin]
+ end.
+
+negative_to_bytes(N) when N >= -16#8000 ->
+ <<N:16>>;
+negative_to_bytes(N) ->
+ Bytes = byte_size(binary:encode_unsigned(-N)),
+ Bin = <<N:Bytes/unit:8>>,
+ case Bin of
+ <<0:1,_/bits>> -> [16#ff,Bin];
+ <<1:1,_/bits>> -> Bin
+ end.
diff --git a/lib/dialyzer/test/specdiffs_SUITE_data/src/iolist.erl b/lib/dialyzer/test/specdiffs_SUITE_data/src/iolist.erl
new file mode 100644
index 0000000000..7cceeda24e
--- /dev/null
+++ b/lib/dialyzer/test/specdiffs_SUITE_data/src/iolist.erl
@@ -0,0 +1,41 @@
+-module(iolist).
+
+%% A small part of beam_asm.
+
+-export([encode/2]).
+
+-spec encode(non_neg_integer(), integer()) -> iolist().
+
+encode(Tag, N) when Tag >= 0, N < 0 ->
+ encode1(Tag, negative_to_bytes(N));
+encode(Tag, N) when Tag >= 0, N < 16 ->
+ (N bsl 4) bor Tag; % not in the specification
+encode(Tag, N) when Tag >= 0, N < 16#800 ->
+ [((N bsr 3) band 2#11100000) bor Tag bor 2#00001000, N band 16#ff];
+encode(Tag, N) when Tag >= 0 ->
+ encode1(Tag, to_bytes(N)).
+
+encode1(Tag, Bytes) ->
+ case iolist_size(Bytes) of
+ Num when 2 =< Num, Num =< 8 ->
+ [((Num-2) bsl 5) bor 2#00011000 bor Tag| Bytes];
+ Num when 8 < Num ->
+ [2#11111000 bor Tag, encode(0, Num-9)| Bytes]
+ end.
+
+to_bytes(N) ->
+ Bin = binary:encode_unsigned(N),
+ case Bin of
+ <<0:1,_/bits>> -> Bin;
+ <<1:1,_/bits>> -> [0,Bin]
+ end.
+
+negative_to_bytes(N) when N >= -16#8000 ->
+ <<N:16>>;
+negative_to_bytes(N) ->
+ Bytes = byte_size(binary:encode_unsigned(-N)),
+ Bin = <<N:Bytes/unit:8>>,
+ case Bin of
+ <<0:1,_/bits>> -> [16#ff,Bin];
+ <<1:1,_/bits>> -> Bin
+ end.
diff --git a/lib/dialyzer/vsn.mk b/lib/dialyzer/vsn.mk
index fa58adc2db..7240b66fb5 100644
--- a/lib/dialyzer/vsn.mk
+++ b/lib/dialyzer/vsn.mk
@@ -1 +1 @@
-DIALYZER_VSN = 3.2.4
+DIALYZER_VSN = 3.3
diff --git a/lib/diameter/bin/diameterc b/lib/diameter/bin/diameterc
index 3dbd238c19..4d415ece78 100755
--- a/lib/diameter/bin/diameterc
+++ b/lib/diameter/bin/diameterc
@@ -4,7 +4,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -78,8 +78,8 @@ compile(#argv{file = File, options = Opts, output = Out}) ->
error_msg(diameter_make:format_error(Reason), []),
1
catch
- error: Reason ->
- error_msg("ERROR: ~p~n ~p", [Reason, erlang:get_stacktrace()]),
+ error: Reason: Stack ->
+ error_msg("ERROR: ~p~n ~p", [Reason, Stack]),
2
end.
diff --git a/lib/diameter/doc/src/Makefile b/lib/diameter/doc/src/Makefile
index 7a7546fc4d..7672598060 100644
--- a/lib/diameter/doc/src/Makefile
+++ b/lib/diameter/doc/src/Makefile
@@ -77,6 +77,7 @@ clean_man:
clean_html:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
diff --git a/lib/diameter/doc/src/notes.xml b/lib/diameter/doc/src/notes.xml
index f74a4ca2a2..3232c3380a 100644
--- a/lib/diameter/doc/src/notes.xml
+++ b/lib/diameter/doc/src/notes.xml
@@ -11,7 +11,7 @@
<header>
<copyright>
<year>2011</year>
-<year>2017</year>
+<year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -43,6 +43,21 @@ first.</p>
<!-- ===================================================================== -->
+<section><title>diameter 2.1.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix documentation typos.</p>
+ <p>
+ Own Id: OTP-15045</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>diameter 2.1.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/diameter/examples/code/node.erl b/lib/diameter/examples/code/node.erl
index fc5830f8e2..77810bf893 100644
--- a/lib/diameter/examples/code/node.erl
+++ b/lib/diameter/examples/code/node.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile
index 3af856f63e..98636ed6e2 100644
--- a/lib/diameter/src/Makefile
+++ b/lib/diameter/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2017. All Rights Reserved.
+# Copyright Ericsson AB 2010-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -149,7 +149,7 @@ gen/$(DICT_YRL).erl: compiler/$(DICT_YRL).yrl
$(ERLC) -Werror -o $(@D) $<
# Generate the app file.
-$(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk app.sed
+$(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk
$(gen_verbose) \
M=`echo $(notdir $(APP_MODULES)) | tr ' ' ,`; \
C=`echo $(COMPILER_MODULES) | tr ' ' ,`; \
@@ -160,8 +160,7 @@ $(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk app.sed
-e "s;%COMPILER%;$$C;" \
-e "s;%INFO%;$$I;" \
-e "s;%REGISTERED%;$$R;" \
- $< \
- | sed -f app.sed > $@
+ $< > $@
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
$(vsn_verbose) \
diff --git a/lib/diameter/src/app.sed b/lib/diameter/src/app.sed
deleted file mode 100644
index dd3806f5f1..0000000000
--- a/lib/diameter/src/app.sed
+++ /dev/null
@@ -1,41 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# 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.
-# 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%
-
-#
-# Generate runtime_dependencies from applications to avoid having to
-# specify the same application more than once.
-#
-
-/{runtime_dependencies,/b v
-/{[-a-z]*, "[0-9.]*"}/!b
-/{vsn,/b
-
-/%%/!H
-s/{\([^,]*\)[^}]*}/\1/g
-s/%%/%,/
-b
-
-:v
-
-p
-x
-s/\n//
-s/%//g
-s/\n */ /g
-s/{\([^,]*\), "\([^"]*"\)}/"\1-\2/g
diff --git a/lib/diameter/src/base/diameter_codec.erl b/lib/diameter/src/base/diameter_codec.erl
index 2dd2c906a2..493a6ab1e3 100644
--- a/lib/diameter/src/base/diameter_codec.erl
+++ b/lib/diameter/src/base/diameter_codec.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -92,8 +92,8 @@ encode(Mod, Opts, #diameter_packet{} = Pkt) ->
%% count encode errors.
?LOG(encode_error, {Reason, Stack, H}),
exit({?MODULE, encode, T});
- error: Reason ->
- T = {Reason, diameter_lib:get_stacktrace()},
+ error: Reason: Stack ->
+ T = {Reason, diameter_lib:stacktrace(Stack)},
?LOG(encode_error, T),
exit({?MODULE, encode, T})
end;
@@ -134,8 +134,8 @@ enc(_, Opts, #diameter_packet{msg = [#diameter_header{} = Hdr | As]}
Eid:32,
Bin/binary>>}
catch
- error: Reason ->
- exit({Reason, diameter_lib:get_stacktrace(), Hdr})
+ error: Reason: Stack ->
+ exit({Reason, diameter_lib:stacktrace(Stack), Hdr})
end;
enc(Mod, Opts, #diameter_packet{header = Hdr0, msg = Msg} = Pkt) ->
@@ -179,14 +179,14 @@ enc(Mod, Opts, #diameter_packet{header = Hdr0, msg = Msg} = Pkt) ->
Eid:32,
Bin/binary>>}
catch
- error: Reason ->
+ error: Reason: Stack ->
Hdr = Hdr0#diameter_header{cmd_code = Code,
application_id = Aid,
is_request = RB,
is_proxiable = PB,
is_error = EB,
is_retransmitted = TB},
- exit({Reason, diameter_lib:get_stacktrace(), Hdr})
+ exit({Reason, diameter_lib:stacktrace(Stack), Hdr})
end.
%% values/1
diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl
index 90a9282349..36ae4c2276 100644
--- a/lib/diameter/src/base/diameter_config.erl
+++ b/lib/diameter/src/base/diameter_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -633,8 +633,8 @@ opt(service, {K, F})
Nodes ->
is_list(Nodes) orelse {error, Nodes}
catch
- E:R ->
- {error, {E, R, ?STACK}}
+ E:R:Stack ->
+ {error, {E, R, Stack}}
end;
opt(service, {sequence, {H,N}}) ->
@@ -651,8 +651,8 @@ opt(service = S, {sequence = K, F}) ->
V ->
{error, V}
catch
- E:R ->
- {error, {E, R, ?STACK}}
+ E:R:Stack ->
+ {error, {E, R, Stack}}
end;
opt(transport, {transport_module, M}) ->
@@ -932,8 +932,8 @@ cb(M,F) ->
try M:F() of
V -> V
catch
- E: Reason ->
- ?THROW({callback, E, Reason, ?STACK})
+ E: Reason: Stack ->
+ ?THROW({callback, E, Reason, Stack})
end.
%% call/1
diff --git a/lib/diameter/src/base/diameter_gen.erl b/lib/diameter/src/base/diameter_gen.erl
index 93ebe57685..d110a3015e 100644
--- a/lib/diameter/src/base/diameter_gen.erl
+++ b/lib/diameter/src/base/diameter_gen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -76,8 +76,7 @@ encode_avps(Name, Vals, #{module := Mod} = Opts) ->
?LINE,
{Reason, Name, Vals, Mod}),
erlang:error(list_to_tuple(Reason ++ [Name]));
- error: Reason ->
- Stack = erlang:get_stacktrace(),
+ error: Reason: Stack ->
diameter_lib:log({encode, failure},
?MODULE,
?LINE,
@@ -555,8 +554,8 @@ dec(Data, Name, AvpName, Type, Mod, Dict, Fmt, Failed, Opts, Avp) ->
catch
throw: {?MODULE, T} ->
decode_error(Failed, Fmt, T, Avp);
- error: Reason ->
- decode_error(Failed, Reason, Name, Mod, Opts, Avp)
+ error: Reason: Stack ->
+ decode_error(Failed, Reason, Stack, Name, Mod, Opts, Avp)
end.
%% dec_AVP/7
@@ -623,19 +622,19 @@ set(none, Avp, _Name) ->
set(_, Avp, Rec) ->
Avp#diameter_avp{value = Rec}.
-%% decode_error/6
+%% decode_error/7
%%
%% Error when decoding a non-grouped AVP.
-decode_error(true, _, _, _, _, Avp) ->
+decode_error(true, _, _, _, _, _, Avp) ->
Avp;
-decode_error(false, Reason, Name, Mod, Opts, Avp) ->
- Stack = diameter_lib:get_stacktrace(),
+decode_error(false, Reason, Stack, Name, Mod, Opts, Avp) ->
+ Z = diameter_lib:stacktrace(Stack),
diameter_lib:log(decode_error,
?MODULE,
?LINE,
- {Reason, Name, Avp#diameter_avp.name, Mod, Stack}),
+ {Reason, Name, Avp#diameter_avp.name, Mod, Z}),
case Reason of
{'DIAMETER', 5014 = RC, _} ->
%% Length error communicated from diameter_types or a
diff --git a/lib/diameter/src/base/diameter_internal.hrl b/lib/diameter/src/base/diameter_internal.hrl
index a0f4a8567d..4a678643c2 100644
--- a/lib/diameter/src/base/diameter_internal.hrl
+++ b/lib/diameter/src/base/diameter_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,9 +35,6 @@
%% A corresponding error when failure is the best option.
-define(ERROR(T), erlang:error({T, ?MODULE, ?LINE})).
-%% Failure reports always get a stack trace.
--define(STACK, erlang:get_stacktrace()).
-
%% Warning report for unexpected messages in various processes.
-define(UNEXPECTED(F,A),
diameter_lib:warning_report(unexpected, {?MODULE, F, A})).
diff --git a/lib/diameter/src/base/diameter_lib.erl b/lib/diameter/src/base/diameter_lib.erl
index 1c1ea42cb5..edd9d5a4ce 100644
--- a/lib/diameter/src/base/diameter_lib.erl
+++ b/lib/diameter/src/base/diameter_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@
time/1,
eval/1,
eval_name/1,
- get_stacktrace/0,
+ stacktrace/1,
ipaddr/1,
spawn_opts/2,
wait/1,
@@ -42,16 +42,13 @@
log/4]).
%% ---------------------------------------------------------------------------
-%% # get_stacktrace/0
+%% # stacktrace/1
%% ---------------------------------------------------------------------------
%% Return a stacktrace with a leading, potentially large, argument
-%% list replaced by an arity. Trace on stacktrace/0 to see the
+%% list replaced by an arity. Trace on stacktrace/1 to see the
%% original.
-get_stacktrace() ->
- stacktrace(erlang:get_stacktrace()).
-
stacktrace([{M,F,A,L} | T]) when is_list(A) ->
[{M, F, length(A), L} | T];
stacktrace(L) ->
@@ -268,8 +265,8 @@ ipaddr(Addr) ->
try
ip(Addr)
catch
- error: _ ->
- erlang:error({invalid_address, erlang:get_stacktrace()})
+ error: _: Stack ->
+ erlang:error({invalid_address, Stack})
end.
%% Already a tuple: ensure non-negative integers of the right size.
diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl
index cbe66ef27a..77d184cfc7 100644
--- a/lib/diameter/src/base/diameter_service.erl
+++ b/lib/diameter/src/base/diameter_service.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -808,8 +808,8 @@ remotes(F) ->
error_report(invalid_return, share_peers, F),
[]
catch
- E:R ->
- ?LOG(failure, {E, R, F, diameter_lib:get_stacktrace()}),
+ E:R:S ->
+ ?LOG(failure, {E, R, F, diameter_lib:stacktrace(S)}),
error_report(failure, share_peers, F),
[]
end.
@@ -1146,11 +1146,11 @@ peer_cb(App, F, A) ->
mod_state(App#diameter_app.alias, ModS),
true
catch
- E:R ->
+ E:R:S ->
%% Don't include arguments since a #diameter_caps{} strings
%% from the peer, which could be anything (especially, large).
[Mod|X] = App#diameter_app.module,
- ?LOG(failure, {E, R, Mod, F, diameter_lib:get_stacktrace()}),
+ ?LOG(failure, {E, R, Mod, F, diameter_lib:stacktrace(S)}),
error_report(failure, F, {Mod, F, A ++ X}),
false
end.
@@ -1376,9 +1376,9 @@ cm([#diameter_app{alias = Alias} = App], Req, From, Svc) ->
?LOG(invalid_return, {ModX, handle_call, Args, T}),
invalid
catch
- E: Reason ->
+ E: Reason: S ->
ModX = App#diameter_app.module,
- Stack = diameter_lib:get_stacktrace(),
+ Stack = diameter_lib:stacktrace(S),
?LOG(failure, {E, Reason, ModX, handle_call, Stack}),
failure
end;
@@ -1585,10 +1585,10 @@ pick_peer(Local,
?LOG(invalid_return, {ModX, pick_peer, T}),
false
catch
- E: Reason when M ->
+ E: Reason: Stack when M ->
ModX = App#diameter_app.module,
- Stack = diameter_lib:get_stacktrace(),
- ?LOG(failure, {E, Reason, ModX, pick_peer, Stack}),
+ Z = diameter_lib:stacktrace(Stack),
+ ?LOG(failure, {E, Reason, ModX, pick_peer, Z}),
false
end.
diff --git a/lib/diameter/src/compiler/diameter_exprecs.erl b/lib/diameter/src/compiler/diameter_exprecs.erl
index 143dede037..ded07f2353 100644
--- a/lib/diameter/src/compiler/diameter_exprecs.erl
+++ b/lib/diameter/src/compiler/diameter_exprecs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/diameter/src/compiler/diameter_make.erl b/lib/diameter/src/compiler/diameter_make.erl
index eae40dbafd..03cfc03edc 100644
--- a/lib/diameter/src/compiler/diameter_make.erl
+++ b/lib/diameter/src/compiler/diameter_make.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -271,6 +271,6 @@ make(File, Opts, Dict, Mode) ->
try
diameter_codegen:from_dict(File, Dict, Opts, Mode)
catch
- error: Reason ->
- erlang:error({Reason, Mode, erlang:get_stacktrace()})
+ error: Reason: Stack ->
+ erlang:error({Reason, Mode, Stack})
end.
diff --git a/lib/diameter/src/diameter.app.src b/lib/diameter/src/diameter.app.src
index 9a6e47006b..18202f033e 100644
--- a/lib/diameter/src/diameter.app.src
+++ b/lib/diameter/src/diameter.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -28,14 +28,21 @@
]},
{registered, [%REGISTERED%]},
{applications, [
- {stdlib, "2.4"}, {kernel, "3.2"}%, {erts, "6.4"}
- %% {syntax-tools, "1.6,18"}
- %% {runtime-tools, "1.8.16"}
- %, {ssl, "6.0"}
+ stdlib,
+ kernel
+ %, ssl
+ %, syntax-tools
+ %, runtime-tools
]},
{env, []},
{mod, {diameter_app, []}},
{runtime_dependencies, [
+ "erts-10.0",
+ "stdlib-2.4",
+ "kernel-3.2",
+ "ssl-9.0"
+ %, "syntax-tools-1.6.18"
+ %, "runtime-tools-1.8.16"
]}
%%
%% Note that ssl is only required if configured on TCP transports,
diff --git a/lib/diameter/src/transport/diameter_tcp.erl b/lib/diameter/src/transport/diameter_tcp.erl
index a8639baa11..da059fa7d6 100644
--- a/lib/diameter/src/transport/diameter_tcp.erl
+++ b/lib/diameter/src/transport/diameter_tcp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -716,7 +716,7 @@ tls_handshake(_, false, S) ->
tls(connect, Sock, Opts) ->
ssl:connect(Sock, Opts);
tls(accept, Sock, Opts) ->
- ssl:ssl_accept(Sock, Opts).
+ ssl:handshake(Sock, Opts). %% assume no handshake option
%% recv/2
%%
@@ -839,7 +839,7 @@ start_fragment_timer(#transport{timeout = Tmo} = S) ->
accept(ssl, LSock) ->
case ssl:transport_accept(LSock) of
{ok, Sock} ->
- {ssl:ssl_accept(Sock), Sock};
+ ssl:handshake(Sock);
{error, _} = No ->
No
end;
diff --git a/lib/diameter/test/diameter_app_SUITE.erl b/lib/diameter/test/diameter_app_SUITE.erl
index 71256020f5..ef4a28d3f4 100644
--- a/lib/diameter/test/diameter_app_SUITE.erl
+++ b/lib/diameter/test/diameter_app_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -208,9 +208,9 @@ xref(Config) ->
CTmods = CTmods -- Mods,
%% Ensure that runtime modules only call other runtime modules, or
- %% applications declared as in runtime_dependencies in the app
- %% file. Note that the declared application versions are ignored
- %% since we only know what we can see now.
+ %% applications declared in runtime_dependencies in the app file.
+ %% The declared application versions are ignored since we only
+ %% know what we see now.
[] = lists:filter(fun(M) -> not lists:member(app(M), Deps) end,
RTdeps -- Mods).
@@ -261,8 +261,12 @@ app(Mod) ->
case code:which(Mod) of
preloaded ->
"erts";
+ Reason when is_atom(Reason) ->
+ error({Reason, Mod});
Path ->
- unversion(lists:nth(3, lists:reverse(filename:split(Path))))
+ %% match to identify an unexpectedly short path
+ {_, _, [_,_,_|_] = Split} = {Mod, Path, filename:split(Path)},
+ unversion(lists:nth(3, lists:reverse(Split)))
end.
add_application(XRef, App) ->
diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl
index c224f9a27e..434aef01dd 100644
--- a/lib/diameter/test/diameter_traffic_SUITE.erl
+++ b/lib/diameter/test/diameter_traffic_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1924,8 +1924,8 @@ compile_and_load() ->
{module, nas4005} = code:load_binary(nas4005, "nas4005", Bin),
true
catch
- E:R ->
- {E, R, erlang:get_stacktrace()}
+ E:R:Stack ->
+ {E, R, Stack}
end.
here() ->
diff --git a/lib/diameter/test/diameter_watchdog_SUITE.erl b/lib/diameter/test/diameter_watchdog_SUITE.erl
index 39c4f051a5..f3f168e671 100644
--- a/lib/diameter/test/diameter_watchdog_SUITE.erl
+++ b/lib/diameter/test/diameter_watchdog_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -638,10 +638,9 @@ run1([F|A]) ->
apply(?MODULE, F, A),
ok
catch
- E:R ->
- S = erlang:get_stacktrace(),
- ?WARN("~p", [{A, E, R, S}]),
- S
+ E:R:Stack ->
+ ?WARN("~p", [{A, E, R, Stack}]),
+ Stack
end.
%% jitter/2
diff --git a/lib/edoc/doc/src/Makefile b/lib/edoc/doc/src/Makefile
index 71de42795a..aba94a6802 100644
--- a/lib/edoc/doc/src/Makefile
+++ b/lib/edoc/doc/src/Makefile
@@ -114,6 +114,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(XML_REF3_FILES) $(XML_CHAPTER_FILES) *.html
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
diff --git a/lib/edoc/doc/src/notes.xml b/lib/edoc/doc/src/notes.xml
index 240789e876..2ef941b06d 100644
--- a/lib/edoc/doc/src/notes.xml
+++ b/lib/edoc/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2007</year><year>2017</year>
+ <year>2007</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,33 @@
<p>This document describes the changes made to the EDoc
application.</p>
+<section><title>Edoc 0.9.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Types and function specifications including the
+ <c>map()</c> type are pretty-printed correctly. </p>
+ <p>
+ Own Id: OTP-15117</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Update to use the new string api instead of the old.</p>
+ <p>
+ Own Id: OTP-15036</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Edoc 0.9.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/edoc/src/edoc_layout.erl b/lib/edoc/src/edoc_layout.erl
index baa147410b..47ff7b21fc 100644
--- a/lib/edoc/src/edoc_layout.erl
+++ b/lib/edoc/src/edoc_layout.erl
@@ -1193,6 +1193,8 @@ ot_name(Es, T) ->
{atom,0,list_to_atom(Atom)},T]};
"tuple" when T =:= [] ->
{type,0,tuple,any};
+ "map" when T =:= [] ->
+ {type,0,map,any};
Atom ->
{type,0,list_to_atom(Atom),T}
end.
diff --git a/lib/edoc/vsn.mk b/lib/edoc/vsn.mk
index 2f6d469536..bea9277e1f 100644
--- a/lib/edoc/vsn.mk
+++ b/lib/edoc/vsn.mk
@@ -1 +1 @@
-EDOC_VSN = 0.9.2
+EDOC_VSN = 0.9.3
diff --git a/lib/eldap/doc/src/Makefile b/lib/eldap/doc/src/Makefile
index aff1da4a9a..bf1eca267a 100644
--- a/lib/eldap/doc/src/Makefile
+++ b/lib/eldap/doc/src/Makefile
@@ -89,6 +89,7 @@ debug opt valgrind:
clean clean_docs clean_tex:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(MAN6DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
diff --git a/lib/eldap/doc/src/notes.xml b/lib/eldap/doc/src/notes.xml
index 8b066671ee..ef7dda510c 100644
--- a/lib/eldap/doc/src/notes.xml
+++ b/lib/eldap/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2012</year><year>2016</year>
+ <year>2012</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,21 @@
</header>
<p>This document describes the changes made to the Eldap application.</p>
+<section><title>Eldap 1.2.4</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Update to use the new string api instead of the old.</p>
+ <p>
+ Own Id: OTP-15036</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Eldap 1.2.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/eldap/test/eldap_basic_SUITE.erl b/lib/eldap/test/eldap_basic_SUITE.erl
index 4bfb0dd291..b871eda19c 100644
--- a/lib/eldap/test/eldap_basic_SUITE.erl
+++ b/lib/eldap/test/eldap_basic_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/eldap/vsn.mk b/lib/eldap/vsn.mk
index 1636b6bb6d..f2b3cd47f2 100644
--- a/lib/eldap/vsn.mk
+++ b/lib/eldap/vsn.mk
@@ -1 +1 @@
-ELDAP_VSN = 1.2.3
+ELDAP_VSN = 1.2.4
diff --git a/lib/erl_docgen/doc/src/Makefile b/lib/erl_docgen/doc/src/Makefile
index a9110e4635..d6d2550425 100644
--- a/lib/erl_docgen/doc/src/Makefile
+++ b/lib/erl_docgen/doc/src/Makefile
@@ -106,6 +106,7 @@ html: gifs examples $(HTML_REF_MAN_FILE)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN6DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/erl_docgen/doc/src/notes.xml b/lib/erl_docgen/doc/src/notes.xml
index 2652b4b0c8..7a09b62351 100644
--- a/lib/erl_docgen/doc/src/notes.xml
+++ b/lib/erl_docgen/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,7 +31,43 @@
</header>
<p>This document describes the changes made to the <em>erl_docgen</em> application.</p>
- <section><title>Erl_Docgen 0.7.2</title>
+ <section><title>Erl_Docgen 0.8</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add a hoverable element to the titles in the html
+ documentation with a link to github where the
+ documentation can be edited.</p>
+ <p>
+ Make the anchors in the html User's Guide and system
+ documentation use the title of the sections instead of a
+ generated id.</p>
+ <p>
+ Own Id: OTP-14979</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Docgen 0.7.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Update makefile so db_funcs.xsl is a part of the
+ installed application. </p>
+ <p>
+ Own Id: OTP-15091</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Docgen 0.7.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/erl_docgen/priv/bin/codeline_preprocessing.escript b/lib/erl_docgen/priv/bin/codeline_preprocessing.escript
index 67966b79e6..ce9303f86e 100755
--- a/lib/erl_docgen/priv/bin/codeline_preprocessing.escript
+++ b/lib/erl_docgen/priv/bin/codeline_preprocessing.escript
@@ -2,7 +2,7 @@
%% -*- erlang -*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/erl_docgen/priv/bin/github_link.escript b/lib/erl_docgen/priv/bin/github_link.escript
index 1b36fca202..e0f5a2f471 100755
--- a/lib/erl_docgen/priv/bin/github_link.escript
+++ b/lib/erl_docgen/priv/bin/github_link.escript
@@ -2,7 +2,7 @@
%% -*- erlang -*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/erl_docgen/priv/bin/xml_from_edoc.escript b/lib/erl_docgen/priv/bin/xml_from_edoc.escript
index b0e3764fae..38e4f2d923 100755
--- a/lib/erl_docgen/priv/bin/xml_from_edoc.escript
+++ b/lib/erl_docgen/priv/bin/xml_from_edoc.escript
@@ -2,7 +2,7 @@
%% -*- erlang -*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/erl_docgen/priv/xsl/Makefile b/lib/erl_docgen/priv/xsl/Makefile
index d0dd227169..d381bd4cf7 100644
--- a/lib/erl_docgen/priv/xsl/Makefile
+++ b/lib/erl_docgen/priv/xsl/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009-2016. All Rights Reserved.
+# Copyright Ericsson AB 2009-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -44,7 +44,8 @@ XSL_FILES = \
db_html.xsl \
db_html_params.xsl \
db_man.xsl \
- db_eix.xsl
+ db_eix.xsl \
+ db_funcs.xsl
# ----------------------------------------------------
diff --git a/lib/erl_docgen/priv/xsl/db_man.xsl b/lib/erl_docgen/priv/xsl/db_man.xsl
index a5ad7ed5ae..27b2bd4066 100644
--- a/lib/erl_docgen/priv/xsl/db_man.xsl
+++ b/lib/erl_docgen/priv/xsl/db_man.xsl
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
- # Copyright Ericsson AB 2009-2016. All Rights Reserved.
+ # Copyright Ericsson AB 2009-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/erl_docgen/src/docgen_edoc_xml_cb.erl b/lib/erl_docgen/src/docgen_edoc_xml_cb.erl
index b065c18cda..d562cfddcc 100644
--- a/lib/erl_docgen/src/docgen_edoc_xml_cb.erl
+++ b/lib/erl_docgen/src/docgen_edoc_xml_cb.erl
@@ -182,7 +182,7 @@ chapter_title(#xmlElement{content=Es}) -> % name = h3 | h4
%% otp_xmlify(Es1) -> Es2
%% Es1 = Es2 = [#xmlElement{} | #xmlText{}]
%% Fix things that are allowed in XHTML but not in chapter/erlref DTDs.
-%% 1) lists (<ul>, <ol>, <dl>) and code snippets (<pre>) can not occur
+%% 1) lists (<ul>, <ol>, <dl>) and code snippets (<pre>) cannot occur
%% within a <p>, such a <p> must be splitted into a sequence of <p>,
%% <ul>, <ol>, <dl> and <pre>.
%% 2) <a> must only have either a href attribute (corresponds to a
diff --git a/lib/erl_docgen/src/docgen_otp_specs.erl b/lib/erl_docgen/src/docgen_otp_specs.erl
index 9f2b401f93..311ec1471a 100644
--- a/lib/erl_docgen/src/docgen_otp_specs.erl
+++ b/lib/erl_docgen/src/docgen_otp_specs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -658,6 +658,8 @@ ot_name(Es, T) ->
{atom,0,list_to_atom(Atom)},T]};
"tuple" when T =:= [] ->
{type,0,tuple,any};
+ "map" when T =:= [] ->
+ {type,0,map,any};
Atom ->
{type,0,list_to_atom(Atom),T}
end.
diff --git a/lib/erl_docgen/vsn.mk b/lib/erl_docgen/vsn.mk
index 95b2329ac5..0b24604daa 100644
--- a/lib/erl_docgen/vsn.mk
+++ b/lib/erl_docgen/vsn.mk
@@ -1 +1 @@
-ERL_DOCGEN_VSN = 0.7.2
+ERL_DOCGEN_VSN = 0.8
diff --git a/lib/erl_interface/configure.in b/lib/erl_interface/configure.in
index 696ebf5ca0..a155ceef7e 100644
--- a/lib/erl_interface/configure.in
+++ b/lib/erl_interface/configure.in
@@ -1,7 +1,7 @@
# -*- Autoconf -*-
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2000-2016. All Rights Reserved.
+# Copyright Ericsson AB 2000-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/erl_interface/doc/src/Makefile b/lib/erl_interface/doc/src/Makefile
index 8ef7e9648c..173bd2e83b 100644
--- a/lib/erl_interface/doc/src/Makefile
+++ b/lib/erl_interface/doc/src/Makefile
@@ -100,6 +100,7 @@ debug opt:
clean clean_docs clean_tex:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN1DIR)/*
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
diff --git a/lib/erl_interface/doc/src/notes.xml b/lib/erl_interface/doc/src/notes.xml
index f165dde259..1438317d8d 100644
--- a/lib/erl_interface/doc/src/notes.xml
+++ b/lib/erl_interface/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,62 @@
</header>
<p>This document describes the changes made to the Erl_interface application.</p>
+<section><title>Erl_Interface 3.10.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix bug where calling erl_init on certain platforms could
+ result in a buffer overflow bug.</p>
+ <p>
+ Own Id: OTP-15033</p>
+ </item>
+ <item>
+ <p>
+ Fixed <c>erl_call -m</c> to not deallocate module source
+ binary before it has been read.</p>
+ <p>
+ Own Id: OTP-15105 Aux Id: ERL-629 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> The program <c>erl_call</c> calls
+ <c>erl_eval:eval_str/1</c> when it used to call
+ <c>lib:eval_str/1</c>. This means that <c>erl_call</c>
+ will fail when trying interact with an Erlang node
+ running Erlang/OTP 20 or earlier. </p>
+ <p>
+ Own Id: OTP-15114 Aux Id: OTP-15072, ERL-634 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Interface 3.10.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Make <c>ei_connect</c> and friends also accept state
+ <c>ok_simultaneous</c> during handshake, which means the
+ other node has initiated a connection setup that will be
+ cancelled in favor of this connection.</p>
+ <p>
+ Own Id: OTP-15161 Aux Id: ERIERL-191 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erl_Interface 3.10.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/erl_interface/src/INSTALL b/lib/erl_interface/src/INSTALL
index b42a17ac46..bf3ca8b6a5 100644
--- a/lib/erl_interface/src/INSTALL
+++ b/lib/erl_interface/src/INSTALL
@@ -122,10 +122,10 @@ you can use the `configure' options `--x-includes=DIR' and
Specifying the System Type
==========================
- There may be some features `configure' can not figure out
+ There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of host the package
will run on. Usually `configure' can figure that out, but if it prints
-a message saying it can not guess the host type, give it the
+a message saying it cannot guess the host type, give it the
`--host=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name with three fields:
CPU-COMPANY-SYSTEM
diff --git a/lib/erl_interface/src/Makefile b/lib/erl_interface/src/Makefile
index 135522397b..800557fbfe 100644
--- a/lib/erl_interface/src/Makefile
+++ b/lib/erl_interface/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2016. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/erl_interface/src/Makefile.in b/lib/erl_interface/src/Makefile.in
index 69b5b6003d..614e7325a9 100644
--- a/lib/erl_interface/src/Makefile.in
+++ b/lib/erl_interface/src/Makefile.in
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c
index 5c01223e3d..9df4fa3b6c 100644
--- a/lib/erl_interface/src/connect/ei_connect.c
+++ b/lib/erl_interface/src/connect/ei_connect.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2000-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2000-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -138,6 +138,11 @@ static int recv_name(int fd,
unsigned *version,
unsigned *flags, ErlConnect *namebuf, unsigned ms);
+static struct hostent*
+dyn_gethostbyname_r(const char *name, struct hostent *hostp, char **buffer_p,
+ int buflen, int *h_errnop);
+
+
/***************************************************************************
*
@@ -480,10 +485,14 @@ int ei_connect_xinit(ei_cnode* ec, const char *thishostname,
int ei_connect_init(ei_cnode* ec, const char* this_node_name,
const char *cookie, short creation)
{
- struct hostent *hp;
char thishostname[EI_MAXHOSTNAMELEN+1];
char thisnodename[MAXNODELEN+1];
char thisalivename[EI_MAXALIVELEN+1];
+ struct hostent host, *hp;
+ char buffer[1024];
+ char *buf = buffer;
+ int ei_h_errno;
+ int res;
#ifdef __WIN32__
if (!initWinSock()) {
@@ -517,10 +526,13 @@ int ei_connect_init(ei_cnode* ec, const char* this_node_name,
strcpy(thisalivename, this_node_name);
}
- if ((hp = ei_gethostbyname(thishostname)) == 0) {
+ hp = dyn_gethostbyname_r(thishostname,&host,&buf,sizeof(buffer),&ei_h_errno);
+ if (hp == NULL) {
/* Looking up IP given hostname fails. We must be on a standalone
host so let's use loopback for communication instead. */
- if ((hp = ei_gethostbyname("localhost")) == 0) {
+ hp = dyn_gethostbyname_r("localhost", &host, &buf, sizeof(buffer),
+ &ei_h_errno);
+ if (hp == NULL) {
#ifdef __WIN32__
char reason[1024];
@@ -549,8 +561,11 @@ int ei_connect_init(ei_cnode* ec, const char* this_node_name,
sprintf(thisnodename, "%s@%s", this_node_name, hp->h_name);
}
}
- return ei_connect_xinit(ec, thishostname, thisalivename, thisnodename,
- (struct in_addr *)*hp->h_addr_list, cookie, creation);
+ res = ei_connect_xinit(ec, thishostname, thisalivename, thisnodename,
+ (struct in_addr *)*hp->h_addr_list, cookie, creation);
+ if (buf != buffer)
+ free(buf);
+ return res;
}
@@ -595,6 +610,13 @@ struct hostent *dyn_gethostbyname_r(const char *name,
int buflen,
int *h_errnop)
{
+#ifdef __WIN32__
+ /*
+ * Apparently ei_gethostbyname_r not implemented for Windows (?)
+ * Fall back on ei_gethostbyname like before.
+ */
+ return ei_gethostbyname(name);
+#else
char* buf = *buffer_p;
struct hostent *hp;
@@ -629,6 +651,7 @@ struct hostent *dyn_gethostbyname_r(const char *name,
}
}
return hp;
+#endif
}
/*
@@ -999,7 +1022,7 @@ int ei_do_receive_msg(int fd, int staticbuffer_p,
erl_errno = EMSGSIZE;
return ERL_ERROR;
}
- x->index = x->buffsz;
+ x->index = msglen;
switch (msg->msgtype) { /* FIXME does not handle trace tokens and monitors */
case ERL_SEND:
case ERL_REG_SEND:
@@ -1357,11 +1380,14 @@ static int recv_status(int fd, unsigned ms)
"<- RECV_STATUS socket read failed (%d)", rlen);
goto error;
}
- if (rlen == 3 && buf[0] == 's' && buf[1] == 'o' &&
- buf[2] == 'k') {
+
+ EI_TRACE_CONN2("recv_status",
+ "<- RECV_STATUS (%.*s)", (rlen>20 ? 20 : rlen), buf);
+
+ if (rlen >= 3 && buf[0] == 's' && buf[1] == 'o' && buf[2] == 'k') {
+ /* Expecting "sok" or "sok_simultaneous" */
if (!is_static)
free(buf);
- EI_TRACE_CONN0("recv_status","<- RECV_STATUS (ok)");
return 0;
}
error:
diff --git a/lib/erl_interface/src/connect/ei_resolve.c b/lib/erl_interface/src/connect/ei_resolve.c
index 2757735d39..022a43d255 100644
--- a/lib/erl_interface/src/connect/ei_resolve.c
+++ b/lib/erl_interface/src/connect/ei_resolve.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1997-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/lib/erl_interface/src/decode/decode_atom.c b/lib/erl_interface/src/decode/decode_atom.c
index 87cd75b1be..2bf8ab0552 100644
--- a/lib/erl_interface/src/decode/decode_atom.c
+++ b/lib/erl_interface/src/decode/decode_atom.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1998-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1998-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/lib/erl_interface/src/legacy/erl_marshal.c b/lib/erl_interface/src/legacy/erl_marshal.c
index 6435754823..c18067b9bc 100644
--- a/lib/erl_interface/src/legacy/erl_marshal.c
+++ b/lib/erl_interface/src/legacy/erl_marshal.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/lib/erl_interface/src/misc/ei_pthreads.c b/lib/erl_interface/src/misc/ei_pthreads.c
index 25608edeec..8c7e86555d 100644
--- a/lib/erl_interface/src/misc/ei_pthreads.c
+++ b/lib/erl_interface/src/misc/ei_pthreads.c
@@ -78,7 +78,7 @@ static void tls_init_once(void)
errno_tls_index = TlsAlloc();
if (errno_tls_index == TLS_OUT_OF_INDEXES) {
fprintf(stderr,
- "FATAL ERROR: can not allocate TLS index for "
+ "FATAL ERROR: cannot allocate TLS index for "
"erl_errno (error code = %d)!\n",GetLastError());
exit(1);
}
@@ -206,6 +206,7 @@ volatile int *__erl_errno_place(void)
use_fallback = 1;
return &fallback_errno;
}
+ *erl_errno_p = 0;
if (pthread_setspecific(erl_errno_key, erl_errno_p) != 0 ||
(erl_errno_p = pthread_getspecific(erl_errno_key)) == NULL) {
diff --git a/lib/erl_interface/src/prog/erl_call.c b/lib/erl_interface/src/prog/erl_call.c
index 7577a07a3e..52ad6885e8 100644
--- a/lib/erl_interface/src/prog/erl_call.c
+++ b/lib/erl_interface/src/prog/erl_call.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -517,6 +517,15 @@ int erl_call(int argc, char **argv)
}
}
+
+ /*
+ * If we loaded any module source code, we can free the buffer
+ * now. This buffer was allocated in read_stdin().
+ */
+ if (module != NULL) {
+ free(module);
+ }
+
/*
* Eval the Erlang functions read from stdin/
*/
@@ -545,7 +554,7 @@ int erl_call(int argc, char **argv)
/* erl_format("[~w]", erl_mk_binary(evalbuf,len))) */
- if (ei_rpc(&ec, fd, "lib", "eval_str", p, i, &reply) < 0) {
+ if (ei_rpc(&ec, fd, "erl_eval", "eval_str", p, i, &reply) < 0) {
fprintf(stderr,"erl_call: evaluating input failed: %s\n",
evalbuf);
free(p);
@@ -795,8 +804,6 @@ static int get_module(char **mbuf, char **mname)
*mname = (char *) ei_chk_calloc(i+1, sizeof(char));
memcpy(*mname, start, i);
}
- if (*mbuf)
- free(*mbuf); /* Allocated in read_stdin() */
return len;
diff --git a/lib/erl_interface/test/ei_accept_SUITE.erl b/lib/erl_interface/test/ei_accept_SUITE.erl
index 6676e73e21..78a433d21b 100644
--- a/lib/erl_interface/test/ei_accept_SUITE.erl
+++ b/lib/erl_interface/test/ei_accept_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("ei_accept_SUITE_data/ei_accept_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
ei_accept/1, ei_threaded_accept/1,
monitor_ei_process/1]).
@@ -38,8 +39,11 @@ all() ->
[ei_accept, ei_threaded_accept,
monitor_ei_process].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
ei_accept(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
Myname = hd(tl(string:tokens(atom_to_list(node()), "@"))),
@@ -91,7 +95,7 @@ ei_threaded_accept(Config) when is_list(Config) ->
%% Test erlang:monitor toward erl_interface "processes"
monitor_ei_process(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
Myname = hd(tl(string:tokens(atom_to_list(node()), "@"))),
@@ -99,7 +103,6 @@ monitor_ei_process(Config) when is_list(Config) ->
EINode = list_to_atom("c42@"++Myname),
io:format("EINode ~p ~n", [EINode]),
- Self = self(),
Port = 6543,
{ok, ListenFd} = ei_publish(P, Port),
MRef1 = erlang:monitor(process, {any, EINode}),
diff --git a/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c b/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c
index 2b62d7c3a4..50df848b69 100644
--- a/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c
+++ b/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -75,11 +75,7 @@ TESTCASE(interpret)
ei_term term;
ei_x_new(&x);
- for (;;) {
- if (get_bin_term(&x, &term)) {
- report(1);
- return;
- } else {
+ while (get_bin_term(&x, &term) == 0) {
char* buf = x.buff, func[MAXATOMLEN];
int index = x.index, arity;
if (term.ei_type != ERL_SMALL_TUPLE_EXT || term.arity != 2)
@@ -100,8 +96,9 @@ TESTCASE(interpret)
message("\"%d\" \n", func);
fail("bad command");
}
- }
- }
+ }
+ report(1);
+ ei_x_free(&x);
}
static void cmd_ei_connect_init(char* buf, int len)
diff --git a/lib/erl_interface/test/ei_connect_SUITE.erl b/lib/erl_interface/test/ei_connect_SUITE.erl
index 66498deadc..24cd384295 100644
--- a/lib/erl_interface/test/ei_connect_SUITE.erl
+++ b/lib/erl_interface/test/ei_connect_SUITE.erl
@@ -25,6 +25,7 @@
-include("ei_connect_SUITE_data/ei_connect_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
ei_send/1,
ei_reg_send/1,
ei_format_pid/1,
@@ -44,8 +45,11 @@ all() ->
[ei_send, ei_reg_send, ei_rpc, ei_format_pid, ei_send_funs,
ei_threaded_send, ei_set_get_tracelevel].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
ei_send(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = ei_connect(P, node()),
@@ -58,7 +62,7 @@ ei_send(Config) when is_list(Config) ->
ei_format_pid(Config) when is_list(Config) ->
S = self(),
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = ei_connect(P, node()),
@@ -70,7 +74,7 @@ ei_format_pid(Config) when is_list(Config) ->
ok.
ei_send_funs(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = ei_connect(P, node()),
@@ -88,7 +92,7 @@ ei_send_funs(Config) when is_list(Config) ->
ok.
ei_reg_send(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = ei_connect(P, node()),
@@ -137,7 +141,7 @@ start_einode(Einode, N, Host) ->
ok.
ei_rpc(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = ei_connect(P, node()),
@@ -150,7 +154,7 @@ ei_rpc(Config) when is_list(Config) ->
ok.
ei_set_get_tracelevel(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
5 = ei_set_get_tracelevel(P, 5),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = ei_connect(P, node()),
diff --git a/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c b/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c
index 6a3796dd24..fbd86cdb50 100644
--- a/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c
+++ b/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c
@@ -74,11 +74,7 @@ TESTCASE(interpret)
ei_term term;
ei_x_new(&x);
- for (;;) {
- if (get_bin_term(&x, &term)) {
- report(1);
- return;
- } else {
+ while (get_bin_term(&x, &term) == 0) {
char* buf = x.buff, func[MAXATOMLEN];
int index = x.index, arity;
if (term.ei_type != ERL_SMALL_TUPLE_EXT || term.arity != 2)
@@ -99,8 +95,10 @@ TESTCASE(interpret)
message("\"%d\" \n", func);
fail("bad command");
}
- }
- }
+ }
+ report(1);
+ ei_x_free(&x);
+ return;
}
diff --git a/lib/erl_interface/test/ei_decode_SUITE.erl b/lib/erl_interface/test/ei_decode_SUITE.erl
index 74fb9b8916..499f10611e 100644
--- a/lib/erl_interface/test/ei_decode_SUITE.erl
+++ b/lib/erl_interface/test/ei_decode_SUITE.erl
@@ -25,6 +25,7 @@
-include("ei_decode_SUITE_data/ei_decode_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
test_ei_decode_long/1,
test_ei_decode_ulong/1,
test_ei_decode_longlong/1,
@@ -42,6 +43,9 @@ all() ->
test_ei_decode_char, test_ei_decode_nonoptimal,
test_ei_decode_misc, test_ei_decode_utf8_atom].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%% ---------------------------------------------------------------------------
% NOTE: for historical reasons we don't pach as tight as we can,
@@ -51,7 +55,7 @@ all() ->
%% ######################################################################## %%
test_ei_decode_long(Config) when is_list(Config) ->
- P = runner:start(?test_ei_decode_long),
+ P = runner:start(Config, ?test_ei_decode_long),
send_integers(P),
runner:recv_eot(P),
ok.
@@ -60,7 +64,7 @@ test_ei_decode_long(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_decode_ulong(Config) when is_list(Config) ->
- P = runner:start(?test_ei_decode_ulong),
+ P = runner:start(Config, ?test_ei_decode_ulong),
send_integers(P),
runner:recv_eot(P),
ok.
@@ -77,7 +81,7 @@ test_ei_decode_longlong(Config) when is_list(Config) ->
vxworks ->
{skip,"Skipped on VxWorks"};
_ ->
- P = runner:start(?test_ei_decode_longlong),
+ P = runner:start(Config, ?test_ei_decode_longlong),
send_integers2(P),
runner:recv_eot(P),
ok
@@ -91,7 +95,7 @@ test_ei_decode_ulonglong(Config) when is_list(Config) ->
vxworks ->
{skip,"Skipped on VxWorks"};
_ ->
- P = runner:start(?test_ei_decode_ulonglong),
+ P = runner:start(Config, ?test_ei_decode_ulonglong),
send_integers2(P),
runner:recv_eot(P),
ok
@@ -104,7 +108,7 @@ test_ei_decode_ulonglong(Config) when is_list(Config) ->
%% FIXME maybe the API should change to use "unsigned char" to be clear?!
test_ei_decode_char(Config) when is_list(Config) ->
- P = runner:start(?test_ei_decode_char),
+ P = runner:start(Config, ?test_ei_decode_char),
send_term_as_binary(P,0),
send_term_as_binary(P,16#7f),
@@ -119,7 +123,7 @@ test_ei_decode_char(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_decode_nonoptimal(Config) when is_list(Config) ->
- P = runner:start(?test_ei_decode_nonoptimal),
+ P = runner:start(Config, ?test_ei_decode_nonoptimal),
send_non_optimal_pos(P), % decode_char
send_non_optimal(P), % decode_long
@@ -168,7 +172,7 @@ send_non_optimal_neg(P) ->
%% ######################################################################## %%
test_ei_decode_misc(Config) when is_list(Config) ->
- P = runner:start(?test_ei_decode_misc),
+ P = runner:start(Config, ?test_ei_decode_misc),
send_term_as_binary(P,0.0),
send_term_as_binary(P,-1.0),
@@ -199,7 +203,7 @@ test_ei_decode_misc(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_decode_utf8_atom(Config) ->
- P = runner:start(?test_ei_decode_utf8_atom),
+ P = runner:start(Config, ?test_ei_decode_utf8_atom),
send_latin1_atom_as_binary(P,"å"),
send_latin1_atom_as_binary(P,"ä"),
diff --git a/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c b/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c
index b7a2c4bb8b..5a9be1e9a2 100644
--- a/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c
+++ b/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c
@@ -105,6 +105,7 @@ int ei_decode_my_string(const char *buf, int *index, char *to,
fail1("size of encoded data (%d) is incorrect", size1); \
return; \
} \
+ free_packet(buf); \
} \
#define EI_DECODE_2_FAIL(FUNC,SIZE,TYPE,VAL) \
@@ -148,6 +149,7 @@ int ei_decode_my_string(const char *buf, int *index, char *to,
fail("size of encoded data should be 0"); \
return; \
} \
+ free_packet(buf); \
} \
#define dump(arr, num) { \
@@ -205,6 +207,7 @@ int ei_decode_my_string(const char *buf, int *index, char *to,
fail("size of encoded data is incorrect"); \
return; \
} \
+ free_packet(buf); \
} \
#define EI_DECODE_STRING(FUNC,SIZE,VAL) \
@@ -248,6 +251,7 @@ int ei_decode_my_string(const char *buf, int *index, char *to,
fail("size of encoded data should be 0"); \
return; \
} \
+ free_packet(buf); \
} \
//#define EI_DECODE_UTF8_STRING(FUNC,SIZE,VAL)
@@ -310,6 +314,7 @@ int ei_decode_my_string(const char *buf, int *index, char *to,
fail("size of encoded data is incorrect"); \
return; \
} \
+ free_packet(buf); \
} \
/* ******************************************************************** */
diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE.erl b/lib/erl_interface/test/ei_decode_encode_SUITE.erl
index 160720b413..6476e92be9 100644
--- a/lib/erl_interface/test/ei_decode_encode_SUITE.erl
+++ b/lib/erl_interface/test/ei_decode_encode_SUITE.erl
@@ -25,6 +25,7 @@
-include("ei_decode_encode_SUITE_data/ei_decode_encode_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
test_ei_decode_encode/1]).
suite() ->
@@ -33,6 +34,9 @@ suite() ->
all() ->
[test_ei_decode_encode].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%% ---------------------------------------------------------------------------
% NOTE: these types have no meaning on the C side so we pass them
@@ -42,7 +46,7 @@ all() ->
%% ######################################################################## %%
test_ei_decode_encode(Config) when is_list(Config) ->
- P = runner:start(?test_ei_decode_encode),
+ P = runner:start(Config, ?test_ei_decode_encode),
Fun = fun (X) -> {X,true} end,
Pid = self(),
diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
index 467f789fdb..6285b5e199 100644
--- a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
+++ b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
@@ -466,6 +466,7 @@ void decode_encode_big(struct Type* t)
send_buffer(arg.buff, arg.index);
ei_x_free(&arg);
ei_free_big(p);
+ free_packet(buf);
}
diff --git a/lib/erl_interface/test/ei_encode_SUITE.erl b/lib/erl_interface/test/ei_encode_SUITE.erl
index 8857b092f3..8c3b0e193b 100644
--- a/lib/erl_interface/test/ei_encode_SUITE.erl
+++ b/lib/erl_interface/test/ei_encode_SUITE.erl
@@ -25,6 +25,7 @@
-include("ei_encode_SUITE_data/ei_encode_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
test_ei_encode_long/1,
test_ei_encode_ulong/1,
test_ei_encode_longlong/1,
@@ -45,6 +46,9 @@ all() ->
test_ei_encode_fails, test_ei_encode_utf8_atom,
test_ei_encode_utf8_atom_len].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%% ---------------------------------------------------------------------------
@@ -55,7 +59,7 @@ all() ->
%% ######################################################################## %%
test_ei_encode_long(Config) when is_list(Config) ->
- P = runner:start(?test_ei_encode_long),
+ P = runner:start(Config, ?test_ei_encode_long),
{<<97,0>> ,0} = get_buf_and_term(P),
{<<97,255>> ,255} = get_buf_and_term(P),
@@ -77,7 +81,7 @@ test_ei_encode_long(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_encode_ulong(Config) when is_list(Config) ->
- P = runner:start(?test_ei_encode_ulong),
+ P = runner:start(Config, ?test_ei_encode_ulong),
{<<97,0>> ,0} = get_buf_and_term(P),
{<<97,255>> ,255} = get_buf_and_term(P),
@@ -101,7 +105,7 @@ test_ei_encode_longlong(Config) when is_list(Config) ->
vxworks ->
{skip,"Skipped on VxWorks"};
_ ->
- P = runner:start(?test_ei_encode_longlong),
+ P = runner:start(Config, ?test_ei_encode_longlong),
{<<97,0>> ,0} = get_buf_and_term(P),
{<<97,255>> ,255} = get_buf_and_term(P),
@@ -132,7 +136,7 @@ test_ei_encode_ulonglong(Config) when is_list(Config) ->
vxworks ->
{skip,"Skipped on VxWorks"};
_ ->
- P = runner:start(?test_ei_encode_ulonglong),
+ P = runner:start(Config, ?test_ei_encode_ulonglong),
{<<97,0>> ,0} = get_buf_and_term(P),
{<<97,255>> ,255} = get_buf_and_term(P),
@@ -158,7 +162,7 @@ test_ei_encode_ulonglong(Config) when is_list(Config) ->
%% FIXME maybe the API should change to use "unsigned char" to be clear?!
test_ei_encode_char(Config) when is_list(Config) ->
- P = runner:start(?test_ei_encode_char),
+ P = runner:start(Config, ?test_ei_encode_char),
{<<97, 0>>,0} = get_buf_and_term(P),
{<<97,127>>,16#7f} = get_buf_and_term(P),
@@ -171,7 +175,7 @@ test_ei_encode_char(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_encode_misc(Config) when is_list(Config) ->
- P = runner:start(?test_ei_encode_misc),
+ P = runner:start(Config, ?test_ei_encode_misc),
<<131>> = get_binaries(P),
@@ -217,7 +221,7 @@ test_ei_encode_misc(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_encode_fails(Config) when is_list(Config) ->
- P = runner:start(?test_ei_encode_fails),
+ P = runner:start(Config, ?test_ei_encode_fails),
XAtom = list_to_atom(lists:duplicate(255, $x)),
YAtom = list_to_atom(lists:duplicate(255, $y)),
@@ -236,7 +240,7 @@ test_ei_encode_fails(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_encode_utf8_atom(Config) ->
- P = runner:start(?test_ei_encode_utf8_atom),
+ P = runner:start(Config, ?test_ei_encode_utf8_atom),
{<<119,2,195,133>>,'Å'} = get_buf_and_term(P),
{<<119,2,195,133>>,'Å'} = get_buf_and_term(P),
@@ -251,7 +255,7 @@ test_ei_encode_utf8_atom(Config) ->
%% ######################################################################## %%
test_ei_encode_utf8_atom_len(Config) ->
- P = runner:start(?test_ei_encode_utf8_atom_len),
+ P = runner:start(Config, ?test_ei_encode_utf8_atom_len),
{<<119,2,195,133>>,'Å'} = get_buf_and_term(P),
{<<119,4,195,133,195,132>>,'ÅÄ'} = get_buf_and_term(P),
diff --git a/lib/erl_interface/test/ei_format_SUITE.erl b/lib/erl_interface/test/ei_format_SUITE.erl
index 07ee479b1f..b11a6ff164 100644
--- a/lib/erl_interface/test/ei_format_SUITE.erl
+++ b/lib/erl_interface/test/ei_format_SUITE.erl
@@ -26,6 +26,7 @@
-export([format_wo_ver/1,
all/0, suite/0,
+ init_per_testcase/2,
atoms/1,
tuples/1,
lists/1]).
@@ -41,10 +42,13 @@ suite() ->
all() ->
[format_wo_ver, atoms, tuples, lists].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%% Tests formatting various atoms.
atoms(Config) when is_list(Config) ->
- P = runner:start(?atoms),
+ P = runner:start(Config, ?atoms),
{term, ''} = get_term(P),
{term, 'a'} = get_term(P),
@@ -84,7 +88,7 @@ atoms(Config) when is_list(Config) ->
%% Tests formatting various tuples
tuples(Config) when is_list(Config) ->
- P = runner:start(?tuples),
+ P = runner:start(Config, ?tuples),
{term, {}} = get_term(P),
{term, {a}} = get_term(P),
@@ -105,7 +109,7 @@ tuples(Config) when is_list(Config) ->
%% Tests formatting various lists
lists(Config) when is_list(Config) ->
- P = runner:start(?lists),
+ P = runner:start(Config, ?lists),
{term, []} = get_term(P),
{term, [a]} = get_term(P),
@@ -146,7 +150,7 @@ lists(Config) when is_list(Config) ->
format_wo_ver(Config) when is_list(Config) ->
- P = runner:start(?format_wo_ver),
+ P = runner:start(Config, ?format_wo_ver),
{term, [-1, 2, $c, {a, "b"}, {c, 10}]} = get_term(P),
diff --git a/lib/erl_interface/test/ei_print_SUITE.erl b/lib/erl_interface/test/ei_print_SUITE.erl
index 6d5c341eae..cad2686018 100644
--- a/lib/erl_interface/test/ei_print_SUITE.erl
+++ b/lib/erl_interface/test/ei_print_SUITE.erl
@@ -25,6 +25,7 @@
-include("ei_print_SUITE_data/ei_print_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
atoms/1, tuples/1, lists/1, strings/1]).
-import(runner, [get_term/1]).
@@ -38,10 +39,13 @@ suite() ->
all() ->
[atoms, tuples, lists, strings].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%% Tests formatting various atoms.
atoms(Config) when is_list(Config) ->
- P = runner:start(?atoms),
+ P = runner:start(Config, ?atoms),
{term, "''"} = get_term(P),
{term, "a"} = get_term(P),
@@ -79,7 +83,7 @@ atoms(Config) when is_list(Config) ->
%% Tests formatting various tuples
tuples(Config) when is_list(Config) ->
- P = runner:start(?tuples),
+ P = runner:start(Config, ?tuples),
{term, "{}"} = get_term(P),
{term, "{a}"} = get_term(P),
@@ -100,7 +104,7 @@ tuples(Config) when is_list(Config) ->
%% Tests formatting various lists
lists(Config) when is_list(Config) ->
- P = runner:start(?lists),
+ P = runner:start(Config, ?lists),
{term, "[]"} = get_term(P),
{term, "[a]"} = get_term(P),
@@ -125,7 +129,7 @@ lists(Config) when is_list(Config) ->
ok.
strings(Config) when is_list(Config) ->
- P = runner:start(?strings),
+ P = runner:start(Config, ?strings),
{term, "\"\\n\""} = get_term(P),
{term, "\"\\r\\n\""} = get_term(P),
diff --git a/lib/erl_interface/test/ei_tmo_SUITE.erl b/lib/erl_interface/test/ei_tmo_SUITE.erl
index 003fe20594..1e76a99e1e 100644
--- a/lib/erl_interface/test/ei_tmo_SUITE.erl
+++ b/lib/erl_interface/test/ei_tmo_SUITE.erl
@@ -39,14 +39,16 @@ all() ->
[framework_check, ei_accept_tmo, ei_connect_tmo,
ei_send_tmo, ei_recv_tmo].
-init_per_testcase(_Case, Config) ->
+init_per_testcase(Case, Config) ->
+ Config1 = runner:init_per_testcase(?MODULE, Case, Config),
+
% test if platform is vxworks_simso
{_,Host} = split(node()),
Bool = case atom_to_list(Host) of
[$v,$x,$s,$i,$m | _] -> true;
_ -> false
end,
- [{vxsim,Bool}|Config].
+ [{vxsim,Bool} | Config1].
end_per_testcase(_Case, _Config) ->
ok.
@@ -55,7 +57,7 @@ end_per_testcase(_Case, _Config) ->
framework_check(Config) when is_list(Config) ->
%%dbg:tracer(),
%%dbg:p(self()),
- P = runner:start(?framework_check),
+ P = runner:start(Config, ?framework_check),
runner:send_term(P,{hello,world}),
{term, {hello,world}} = runner:get_term(P),
runner:recv_eot(P),
@@ -71,7 +73,7 @@ ei_recv_tmo(Config) when is_list(Config) ->
do_one_recv(Config,CNode) ->
{_,Host} = split(node()),
- P1 = runner:start(?recv_tmo),
+ P1 = runner:start(Config, ?recv_tmo),
runner:send_term(P1,{CNode,
erlang:get_cookie(),
node()}),
@@ -84,7 +86,7 @@ do_one_recv(Config,CNode) ->
runner:recv_eot(P1).
do_one_recv_failure(Config,CNode) ->
- P1 = runner:start(?recv_tmo),
+ P1 = runner:start(Config, ?recv_tmo),
runner:send_term(P1,{CNode,
erlang:get_cookie(),
node()}),
@@ -110,7 +112,7 @@ ei_send_tmo(Config) when is_list(Config) ->
do_one_send(Config,From,CNode) ->
{_,Host} = split(node()),
- P1 = runner:start(?send_tmo),
+ P1 = runner:start(Config, ?send_tmo),
runner:send_term(P1,{CNode,
erlang:get_cookie(),
node()}),
@@ -139,7 +141,7 @@ do_one_send_failure(Config,From,FakeName,CName,VxSim) ->
exit(Else)
end,
EpmdSocket = register(OurName, LSocket, 1, 5),
- P3 = runner:start(?send_tmo),
+ P3 = runner:start(Config, ?send_tmo),
Cookie = kaksmula_som_ingen_bryr_sig_om,
runner:send_term(P3,{CName,
Cookie,
@@ -202,7 +204,7 @@ ei_connect_tmo(Config) when is_list(Config) ->
%dbg:p(self()),
VxSim = proplists:get_value(vxsim, Config),
DummyNode = make_and_check_dummy(),
- P = runner:start(?connect_tmo),
+ P = runner:start(Config, ?connect_tmo),
runner:send_term(P,{c_nod_connect_tmo_1,
kaksmula_som_ingen_bryr_sig_om,
DummyNode}),
@@ -219,7 +221,7 @@ ei_connect_tmo(Config) when is_list(Config) ->
end
end,
runner:recv_eot(P),
- P2 = runner:start(?connect_tmo),
+ P2 = runner:start(Config, ?connect_tmo),
runner:send_term(P2,{c_nod_connect_tmo_2,
erlang:get_cookie(),
node()}),
@@ -237,7 +239,7 @@ ei_connect_tmo(Config) when is_list(Config) ->
exit(Else)
end,
EpmdSocket = register(OurName, LSocket, 1, 5),
- P3 = runner:start(?connect_tmo),
+ P3 = runner:start(Config, ?connect_tmo),
Cookie = kaksmula_som_ingen_bryr_sig_om,
runner:send_term(P3,{c_nod_connect_tmo_3,
Cookie,
@@ -266,12 +268,12 @@ ei_connect_tmo(Config) when is_list(Config) ->
ei_accept_tmo(Config) when is_list(Config) ->
%%dbg:tracer(),
%%dbg:p(self()),
- P = runner:start(?accept_tmo),
+ P = runner:start(Config, ?accept_tmo),
runner:send_term(P,{c_nod_som_ingen_kontaktar_1,
kaksmula_som_ingen_bryr_sig_om}),
{term,{-1,ETimedout,ETimedout}} = runner:get_term(P, 10000),
runner:recv_eot(P),
- P2 = runner:start(?accept_tmo),
+ P2 = runner:start(Config, ?accept_tmo),
runner:send_term(P2,{c_nod_som_vi_kontaktar_1,
erlang:get_cookie()}),
receive after 1000 -> ok end,
@@ -280,7 +282,7 @@ ei_accept_tmo(Config) when is_list(Config) ->
{term, X} = runner:get_term(P2, 10000),
runner:recv_eot(P2),
true = is_integer(X),
- P3 = runner:start(?accept_tmo),
+ P3 = runner:start(Config, ?accept_tmo),
runner:send_term(P3,{c_nod_som_vi_kontaktar_2,
erlang:get_cookie()}),
receive after 1000 -> ok end,
diff --git a/lib/erl_interface/test/ei_tmo_SUITE_data/ei_tmo_test.c b/lib/erl_interface/test/ei_tmo_SUITE_data/ei_tmo_test.c
index 8e0f2807a4..39846e4a58 100644
--- a/lib/erl_interface/test/ei_tmo_SUITE_data/ei_tmo_test.c
+++ b/lib/erl_interface/test/ei_tmo_SUITE_data/ei_tmo_test.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2003-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2003-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/lib/erl_interface/test/erl_connect_SUITE.erl b/lib/erl_interface/test/erl_connect_SUITE.erl
index cd73f07b8f..ad4e34c548 100644
--- a/lib/erl_interface/test/erl_connect_SUITE.erl
+++ b/lib/erl_interface/test/erl_connect_SUITE.erl
@@ -25,6 +25,7 @@
-include("erl_connect_SUITE_data/erl_connect_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
erl_send/1, erl_reg_send/1,
erl_send_cookie_file/1]).
@@ -38,8 +39,11 @@ all() ->
[erl_send, erl_reg_send, erl_send_cookie_file].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
erl_send(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
1 = erl_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = erl_connect(P, node()),
@@ -56,7 +60,7 @@ erl_send_cookie_file(Config) when is_list(Config) ->
vxworks ->
{skip,"Skipped on VxWorks"};
_ ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
1 = erl_connect_init(P, 42, '', 0),
{ok,Fd} = erl_connect(P, node()),
@@ -70,7 +74,7 @@ erl_send_cookie_file(Config) when is_list(Config) ->
end.
erl_reg_send(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
1 = erl_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = erl_connect(P, node()),
diff --git a/lib/erl_interface/test/erl_eterm_SUITE.erl b/lib/erl_interface/test/erl_eterm_SUITE.erl
index 3d1e33081b..84b58fed54 100644
--- a/lib/erl_interface/test/erl_eterm_SUITE.erl
+++ b/lib/erl_interface/test/erl_eterm_SUITE.erl
@@ -35,6 +35,7 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-export([all/0, suite/0,
+ init_per_testcase/2,
build_terms/1, round_trip_conversion/1,
decode_terms/1, decode_float/1,
t_erl_mk_int/1, t_erl_mk_list/1,
@@ -94,6 +95,9 @@ all() ->
high_chaparal, broken_data, cnode_1].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%
%%% 1. B a s i c t e s t s
@@ -104,7 +108,7 @@ all() ->
%% a list and verifies that the result is as expected.
build_terms(Config) when is_list(Config) ->
- P = runner:start(?build_terms),
+ P = runner:start(Config, ?build_terms),
{term, Term} = get_term(P),
io:format("Received: ~p", [Term]),
[ARefLN, ARef, APortLN, APort, APidLN, APid,
@@ -136,7 +140,7 @@ build_terms(Config) when is_list(Config) ->
%% This test is run entirely in C code.
round_trip_conversion(Config) when is_list(Config) ->
- runner:test(?round_trip_conversion),
+ runner:test(Config, ?round_trip_conversion),
ok.
%% This test sends a list of all data types to the C code function,
@@ -156,7 +160,7 @@ decode_terms(Config) when is_list(Config) ->
{element1, 42, 767}, "A string",
1, -1, 0, 3.0, ABinary, 'I am an atom'],
- P = runner:start(?decode_terms),
+ P = runner:start(Config, ?decode_terms),
runner:send_term(P, Terms),
runner:recv_eot(P),
@@ -165,7 +169,7 @@ decode_terms(Config) when is_list(Config) ->
%% Decodes the floating point number 3.1415.
decode_float(Config) when is_list(Config) ->
- P = runner:start(?decode_float),
+ P = runner:start(Config, ?decode_float),
runner:send_term(P, 3.1415),
runner:recv_eot(P),
ok.
@@ -173,7 +177,7 @@ decode_float(Config) when is_list(Config) ->
%% Tests the erl_free_compound() function.
t_erl_free_compound(Config) when is_list(Config) ->
- runner:test(?t_erl_free_compound),
+ runner:test(Config, ?t_erl_free_compound),
ok.
@@ -186,7 +190,7 @@ t_erl_free_compound(Config) when is_list(Config) ->
%% This tests the erl_mk_list() function.
t_erl_mk_list(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_list),
+ P = runner:start(Config, ?t_erl_mk_list),
{term, []} = get_term(P),
{term, [abc]} = get_term(P),
@@ -200,7 +204,7 @@ t_erl_mk_list(Config) when is_list(Config) ->
%% This tests the erl_mk_int() function.
t_erl_mk_int(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_int),
+ P = runner:start(Config, ?t_erl_mk_int),
{term, 0} = get_term(P),
{term, 127} = get_term(P),
@@ -255,14 +259,14 @@ t_erl_mk_int(Config) when is_list(Config) ->
%% Basic test of erl_copy_term().
basic_copy(Config) when is_list(Config) ->
- runner:test(?basic_copy),
+ runner:test(Config, ?basic_copy),
ok.
%% This tests the erl_mk_tuple() function.
t_erl_mk_tuple(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_tuple),
+ P = runner:start(Config, ?t_erl_mk_tuple),
{term, {madonna, 21, 'mad donna', 12}} = get_term(P),
{term, {'Madonna',21,{children,{"Isabella",2}},
@@ -275,7 +279,7 @@ t_erl_mk_tuple(Config) when is_list(Config) ->
%% This tests the erl_mk_atom() function.
t_erl_mk_atom(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_atom),
+ P = runner:start(Config, ?t_erl_mk_atom),
{term, madonna} = (get_term(P)),
{term, 'Madonna'} = (get_term(P)),
@@ -295,7 +299,7 @@ t_erl_mk_atom(Config) when is_list(Config) ->
%% This tests the erl_mk_binary() function.
t_erl_mk_binary(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_binary),
+ P = runner:start(Config, ?t_erl_mk_binary),
{term, Bin} = (get_term(P)),
"{madonna,21,'mad donna',1234.567.890, !#$%&/()=?+-@, \" \\}" = binary_to_list(Bin),
@@ -307,7 +311,7 @@ t_erl_mk_binary(Config) when is_list(Config) ->
%% This tests the erl_mk_empty_list() function.
t_erl_mk_empty_list(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_empty_list),
+ P = runner:start(Config, ?t_erl_mk_empty_list),
{term, []} = get_term(P),
@@ -322,7 +326,7 @@ t_erl_mk_float(Config) when is_list(Config) ->
vxworks ->
{skipped, "Floating point numbers never compare equal on PPC"};
_ ->
- P = runner:start(?t_erl_mk_float),
+ P = runner:start(Config, ?t_erl_mk_float),
{term, {3.1415, 1.999999, 2.000000, 2.000001,
2.000002, 12345.67890}} = get_term(P),
runner:recv_eot(P),
@@ -333,7 +337,7 @@ t_erl_mk_float(Config) when is_list(Config) ->
%% This tests the erl_mk_pid() function.
t_erl_mk_pid(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_pid),
+ P = runner:start(Config, ?t_erl_mk_pid),
{term, A_pid} = (get_term(P)),
{pid, kalle@localhost, 3, 2} = nc2vinfo(A_pid),
@@ -342,7 +346,7 @@ t_erl_mk_pid(Config) when is_list(Config) ->
ok.
t_erl_mk_xpid(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_xpid),
+ P = runner:start(Config, ?t_erl_mk_xpid),
{term, A_pid} = (get_term(P)),
{pid, kalle@localhost, 32767, 8191} = nc2vinfo(A_pid),
@@ -354,7 +358,7 @@ t_erl_mk_xpid(Config) when is_list(Config) ->
%% This tests the erl_mk_port() function.
t_erl_mk_port(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_port),
+ P = runner:start(Config, ?t_erl_mk_port),
{term, A_port} = (get_term(P)),
{port, kalle@localhost, 4} = nc2vinfo(A_port),
@@ -363,7 +367,7 @@ t_erl_mk_port(Config) when is_list(Config) ->
ok.
t_erl_mk_xport(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_xport),
+ P = runner:start(Config, ?t_erl_mk_xport),
{term, A_port} = (get_term(P)),
{port, kalle@localhost, 268435455} = nc2vinfo(A_port),
@@ -375,7 +379,7 @@ t_erl_mk_xport(Config) when is_list(Config) ->
%% This tests the erl_mk_ref() function.
t_erl_mk_ref(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_ref),
+ P = runner:start(Config, ?t_erl_mk_ref),
{term, A_ref} = (get_term(P)),
{ref, kalle@localhost, _Length, [6]} = nc2vinfo(A_ref),
@@ -384,7 +388,7 @@ t_erl_mk_ref(Config) when is_list(Config) ->
ok.
t_erl_mk_long_ref(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_long_ref),
+ P = runner:start(Config, ?t_erl_mk_long_ref),
{term, A_ref} = (get_term(P)),
{ref, kalle@localhost, _Length, [4294967295,4294967295,262143]}
@@ -397,7 +401,7 @@ t_erl_mk_long_ref(Config) when is_list(Config) ->
%% This tests the erl_mk_string() function.
t_erl_mk_string(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_string),
+ P = runner:start(Config, ?t_erl_mk_string),
{term, "madonna"} = (get_term(P)),
{term, "Madonna"} = (get_term(P)),
@@ -417,7 +421,7 @@ t_erl_mk_string(Config) when is_list(Config) ->
%% This tests the erl_mk_estring() function.
t_erl_mk_estring(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_estring),
+ P = runner:start(Config, ?t_erl_mk_estring),
{term, "madonna"} = (get_term(P)),
{term, "Madonna"} = (get_term(P)),
@@ -437,7 +441,7 @@ t_erl_mk_estring(Config) when is_list(Config) ->
%% This tests the erl_mk_uint() function.
t_erl_mk_uint(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_uint),
+ P = runner:start(Config, ?t_erl_mk_uint),
{term, 54321} = (get_term(P)),
{term, 2147483647} = (get_term(P)),
@@ -453,7 +457,7 @@ t_erl_mk_uint(Config) when is_list(Config) ->
%% This tests the erl_mk_var() function.
t_erl_mk_var(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_var),
+ P = runner:start(Config, ?t_erl_mk_var),
{term, 1} = (get_term(P)),
{term, 0} = (get_term(P)),
@@ -470,7 +474,7 @@ t_erl_mk_var(Config) when is_list(Config) ->
%% This tests the erl_cons() function.
t_erl_cons(Config) when is_list(Config) ->
- P = runner:start(?t_erl_cons),
+ P = runner:start(Config, ?t_erl_cons),
{term, [madonna, 21]} = get_term(P),
@@ -490,7 +494,7 @@ t_erl_cons(Config) when is_list(Config) ->
%% Tests the erl_length() function.
t_erl_length(Config) when is_list(Config) ->
- P = runner:start(?t_erl_length),
+ P = runner:start(Config, ?t_erl_length),
0 = erl_length(P, []),
1 = erl_length(P, [a]),
@@ -513,7 +517,7 @@ erl_length(Port, List) ->
%% Tests the erl_hd() function.
t_erl_hd(Config) when is_list(Config) ->
- P = runner:start(?t_erl_hd),
+ P = runner:start(Config, ?t_erl_hd),
'NULL' = erl_hd(P, 42),
'NULL' = erl_hd(P, abc),
@@ -537,7 +541,7 @@ erl_hd(Port, List) ->
%% Tests the erl_tail() function.
t_erl_tl(Config) when is_list(Config) ->
- P = runner:start(?t_erl_tl),
+ P = runner:start(Config, ?t_erl_tl),
'NULL' = erl_tl(P, 42),
'NULL' = erl_tl(P, abc),
@@ -561,20 +565,20 @@ erl_tl(Port, List) ->
%% Tests the type checking macros (done in the C program).
type_checks(Config) when is_list(Config) ->
- runner:test(?type_checks),
+ runner:test(Config, ?type_checks),
ok.
%% Tests the extractor macros (done in the C program).
extractor_macros(Config) when is_list(Config) ->
- runner:test(?extractor_macros),
+ runner:test(Config, ?extractor_macros),
ok.
%% This tests the erl_size() function.
t_erl_size(Config) when is_list(Config) ->
- P = runner:start(?t_erl_size),
+ P = runner:start(Config, ?t_erl_size),
{term, 0} = (get_term(P)),
{term, 4} = (get_term(P)),
@@ -589,7 +593,7 @@ t_erl_size(Config) when is_list(Config) ->
%% This tests the erl_var_content() function.
t_erl_var_content(Config) when is_list(Config) ->
- P = runner:start(?t_erl_var_content),
+ P = runner:start(Config, ?t_erl_var_content),
{term, 17} = (get_term(P)),
{term, "http://www.madonna.com"} = (get_term(P)),
@@ -604,7 +608,7 @@ t_erl_var_content(Config) when is_list(Config) ->
%% This tests the erl_element() function.
t_erl_element(Config) when is_list(Config) ->
- P = runner:start(?t_erl_element),
+ P = runner:start(Config, ?t_erl_element),
{term, madonna} = get_term(P),
{term, 21} = get_term(P),
@@ -630,7 +634,7 @@ t_erl_element(Config) when is_list(Config) ->
%% Tests the erl_iolist_length() function.
t_erl_iolist_length(Config) when is_list(Config) ->
- P = runner:start(?t_erl_iolist_length),
+ P = runner:start(Config, ?t_erl_iolist_length),
%% Flat lists.
@@ -697,7 +701,7 @@ erl_iolist_length(Port, List) ->
%% Tests the erl_iolist_to_binary() function.
t_erl_iolist_to_binary(Config) when is_list(Config) ->
- P = runner:start(?t_erl_iolist_to_binary),
+ P = runner:start(Config, ?t_erl_iolist_to_binary),
%% Flat lists.
@@ -768,7 +772,7 @@ iolist_to_list(Port, Term) ->
%% Tests the erl_iolist_to_string() function.
t_erl_iolist_to_string(Config) when is_list(Config) ->
- P = runner:start(?t_erl_iolist_to_string),
+ P = runner:start(Config, ?t_erl_iolist_to_string),
%% Flat lists.
@@ -947,14 +951,14 @@ collect_line1([C|Rest], Result) ->
%% Test case submitted by Per Lundgren, ERV.
high_chaparal(Config) when is_list(Config) ->
- P = runner:start(?high_chaparal),
+ P = runner:start(Config, ?high_chaparal),
{term, [hello, world]} = get_term(P),
runner:recv_eot(P),
ok.
%% OTP-7448
broken_data(Config) when is_list(Config) ->
- P = runner:start(?broken_data),
+ P = runner:start(Config, ?broken_data),
runner:recv_eot(P),
ok.
diff --git a/lib/erl_interface/test/erl_ext_SUITE.erl b/lib/erl_interface/test/erl_ext_SUITE.erl
index afaba1fd93..806339b122 100644
--- a/lib/erl_interface/test/erl_ext_SUITE.erl
+++ b/lib/erl_interface/test/erl_ext_SUITE.erl
@@ -25,6 +25,7 @@
-include("erl_ext_SUITE_data/ext_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
compare_tuple/1,
compare_list/1,
compare_string/1,
@@ -40,28 +41,30 @@ all() ->
[compare_tuple, compare_list, compare_string,
compare_list_string, compare_nc_ext].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
compare_tuple(Config) when is_list(Config) ->
- P = runner:start(?compare_tuple),
+ P = runner:start(Config, ?compare_tuple),
runner:recv_eot(P),
ok.
compare_list(Config) when is_list(Config) ->
- P = runner:start(?compare_list),
+ P = runner:start(Config, ?compare_list),
runner:recv_eot(P),
ok.
compare_string(Config) when is_list(Config) ->
- P = runner:start(?compare_string),
+ P = runner:start(Config, ?compare_string),
runner:recv_eot(P),
ok.
compare_list_string(Config) when is_list(Config) ->
- P = runner:start(?compare_list_string),
+ P = runner:start(Config, ?compare_list_string),
runner:recv_eot(P),
ok.
compare_nc_ext(Config) when is_list(Config) ->
- P = runner:start(?compare_nc_ext),
+ P = runner:start(Config, ?compare_nc_ext),
runner:recv_eot(P),
ok.
diff --git a/lib/erl_interface/test/erl_format_SUITE.erl b/lib/erl_interface/test/erl_format_SUITE.erl
index c1a7d8377e..d984dcb08e 100644
--- a/lib/erl_interface/test/erl_format_SUITE.erl
+++ b/lib/erl_interface/test/erl_format_SUITE.erl
@@ -25,6 +25,7 @@
-include("erl_format_SUITE_data/format_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
atoms/1, tuples/1, lists/1]).
-import(runner, [get_term/1]).
@@ -38,10 +39,13 @@ suite() ->
all() ->
[atoms, tuples, lists].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%% Tests formatting various atoms.
atoms(Config) when is_list(Config) ->
- P = runner:start(?atoms),
+ P = runner:start(Config, ?atoms),
{term, ''} = get_term(P),
{term, 'a'} = get_term(P),
@@ -79,7 +83,7 @@ atoms(Config) when is_list(Config) ->
%% Tests formatting various tuples
tuples(Config) when is_list(Config) ->
- P = runner:start(?tuples),
+ P = runner:start(Config, ?tuples),
{term, {}} = get_term(P),
{term, {a}} = get_term(P),
@@ -100,7 +104,7 @@ tuples(Config) when is_list(Config) ->
%% Tests formatting various lists
lists(Config) when is_list(Config) ->
- P = runner:start(?lists),
+ P = runner:start(Config, ?lists),
{term, []} = get_term(P),
{term, [a]} = get_term(P),
diff --git a/lib/erl_interface/test/erl_global_SUITE.erl b/lib/erl_interface/test/erl_global_SUITE.erl
index ecc6753c7f..560afd58ba 100644
--- a/lib/erl_interface/test/erl_global_SUITE.erl
+++ b/lib/erl_interface/test/erl_global_SUITE.erl
@@ -25,6 +25,7 @@
-include("erl_global_SUITE_data/erl_global_test_cases.hrl").
-export([all/0,suite/0,
+ init_per_testcase/2,
erl_global_registration/1,
erl_global_whereis/1, erl_global_names/1]).
@@ -39,9 +40,11 @@ suite() ->
[{ct_hooks,[ts_install_cth]},
{timetrap, {seconds, 30}}].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
erl_global_registration(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
{ok, Fd} = erl_connect(P, node(), 42, erlang:get_cookie(), 0),
ok = erl_global_register(P, Fd, ?GLOBAL_NAME),
@@ -53,7 +56,7 @@ erl_global_registration(Config) when is_list(Config) ->
ok.
erl_global_whereis(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
{ok, Fd} = erl_connect(P, node(), 42, erlang:get_cookie(), 0),
Self = self(),
@@ -66,7 +69,7 @@ erl_global_whereis(Config) when is_list(Config) ->
ok.
erl_global_names(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
{ok, Fd} = erl_connect(P, node(), 42, erlang:get_cookie(), 0),
Self = self(),
diff --git a/lib/erl_interface/test/erl_match_SUITE.erl b/lib/erl_interface/test/erl_match_SUITE.erl
index 5566714092..f1f6892ae0 100644
--- a/lib/erl_interface/test/erl_match_SUITE.erl
+++ b/lib/erl_interface/test/erl_match_SUITE.erl
@@ -25,6 +25,7 @@
-include("erl_match_SUITE_data/match_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
atoms/1, lists/1, tuples/1, references/1, pids/1, ports/1,
bind/1, integers/1, floats/1, binaries/1, strings/1]).
@@ -40,6 +41,8 @@ all() ->
[atoms, lists, tuples, references, pids, ports, bind,
integers, floats, binaries, strings].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
atoms(Config) when is_list(Config) ->
P = start_matcher(Config),
@@ -239,7 +242,7 @@ bind(Config) when is_list(Config) ->
ok.
start_bind(Config) ->
- runner:start(?erl_match_bind).
+ runner:start(Config, ?erl_match_bind).
bind_ok(Port, Bind, Term) ->
true = erl_bind(Port, Bind, Term).
@@ -258,7 +261,7 @@ erl_bind(Port, Pattern, Term) ->
start_matcher(Config) ->
- runner:start(?erl_match_server).
+ runner:start(Config, ?erl_match_server).
eq(Port, Pattern, Term) ->
true = erl_match(Port, Pattern, Term).
diff --git a/lib/erl_interface/test/port_call_SUITE.erl b/lib/erl_interface/test/port_call_SUITE.erl
index fb10bd895f..d31b2372ab 100644
--- a/lib/erl_interface/test/port_call_SUITE.erl
+++ b/lib/erl_interface/test/port_call_SUITE.erl
@@ -32,7 +32,9 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--export([all/0, suite/0, basic/1]).
+-export([all/0, suite/0,
+ init_per_testcase/2,
+ basic/1]).
% Private exports
-include_lib("common_test/include/ct.hrl").
@@ -44,6 +46,8 @@ suite() ->
all() ->
[basic].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
basic(Config) when is_list(Config) ->
case os:type() of
diff --git a/lib/erl_interface/test/runner.erl b/lib/erl_interface/test/runner.erl
index cbdeb3c8a9..484890006e 100644
--- a/lib/erl_interface/test/runner.erl
+++ b/lib/erl_interface/test/runner.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,8 +21,9 @@
%%
-module(runner).
--export([test/1, test/2,
- start/1, send_term/2, finish/1, send_eot/1, recv_eot/1,
+-export([test/2, test/3,
+ init_per_testcase/3,
+ start/2, send_term/2, finish/1, send_eot/1, recv_eot/1,
get_term/1, get_term/2]).
-define(default_timeout, 5000).
@@ -32,11 +33,11 @@
%% This function is useful for test cases written in C which requires
%% no further input, and only returns a result by calling report().
-test(Tc) ->
- test(Tc, ?default_timeout).
+test(Config, Tc) ->
+ test(Config, Tc, ?default_timeout).
-test(Tc, Timeout) ->
- Port = start(Tc),
+test(Config, Tc, Timeout) ->
+ Port = start(Config, Tc),
case get_term(Port, Timeout) of
eot ->
@@ -54,12 +55,51 @@ test(Tc, Timeout) ->
%%
%% Returns: {ok, Port}
-start({Prog, Tc}) when is_list(Prog), is_integer(Tc) ->
- Port = open_port({spawn, Prog}, [{packet, 4}, exit_status]),
+start(Config, {Prog, Tc}) when is_list(Prog), is_integer(Tc) ->
+ Port = open_port({spawn, prog_cmd(Config, Prog)},
+ [{packet, 4}, exit_status]),
Command = [Tc div 256, Tc rem 256],
Port ! {self(), {command, Command}},
Port.
+prog_cmd(Config, Prog) ->
+ case proplists:get_value(valgrind_cmd_fun, Config) of
+ undefined ->
+ Prog;
+ Fun when is_function(Fun) ->
+ Fun(Prog)
+ end.
+
+init_per_testcase(Suite, Case, Config) ->
+ case os:getenv("VALGRIND_LOG_DIR") of
+ false ->
+ Config;
+ LogDir ->
+ Valgrind = case os:find_executable("valgrind") of
+ false ->
+ ct:fail("VALGRIND_LOG_DIR set, "
+ "but no valgrind executable found");
+ VG -> VG
+ end,
+
+ LogFileOpt = case os:getenv("VALGRIND_LOG_XML") of
+ false ->
+ " --log-file=";
+ "yes" ->
+ " --xml=yes --xml-file="
+ end,
+ Fun = fun(Prog) ->
+ LogFile = io_lib:format("erl_interface-~w.~w-~s.log.%p",
+ [Suite, Case, filename:basename(Prog)]),
+ Valgrind
+ ++ LogFileOpt ++ filename:join(LogDir,LogFile)
+ ++ " " ++ os:getenv("VALGRIND_MISC_FLAGS","")
+ ++ " " ++ Prog
+ end,
+ [{valgrind_cmd_fun, Fun} | Config]
+ end.
+
+
%% Finishes a test case by send an 'eot' message to the C program
%% and waiting for an 'eot'.
%%
diff --git a/lib/erl_interface/vsn.mk b/lib/erl_interface/vsn.mk
index 8b6e91757d..586b23c5b3 100644
--- a/lib/erl_interface/vsn.mk
+++ b/lib/erl_interface/vsn.mk
@@ -1,2 +1,2 @@
-EI_VSN = 3.10.2
+EI_VSN = 3.10.3
ERL_INTERFACE_VSN = $(EI_VSN)
diff --git a/lib/et/doc/src/Makefile b/lib/et/doc/src/Makefile
index 162d36e274..93e2f8eeee 100644
--- a/lib/et/doc/src/Makefile
+++ b/lib/et/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2016. All Rights Reserved.
+# Copyright Ericsson AB 2002-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -85,6 +85,7 @@ clean clean_docs:
fi \
done
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/et/doc/src/et_collector.xml b/lib/et/doc/src/et_collector.xml
index 6a85b81ec2..ba24c121e0 100644
--- a/lib/et/doc/src/et_collector.xml
+++ b/lib/et/doc/src/et_collector.xml
@@ -46,7 +46,8 @@
<v>option() = {parent_pid, pid()} | {event_order, event_order()} | {dict_insert, {filter, collector}, collector_fun()} | {dict_insert, {filter, event_filter_name()}, event_filter_fun()} | {dict_insert, {subscriber, pid()}, dict_val()} | {dict_insert, dict_key(), dict_val()} | {dict_delete, dict_key()} | {trace_client, trace_client()} | {trace_global, boolean()} | {trace_pattern, trace_pattern()} | {trace_port, integer()} | {trace_max_queue, integer()}</v>
<v>event_order() = trace_ts | event_ts</v>
<v>trace_pattern() = {report_module(), extended_dbg_match_spec()} | undefined</v>
- <v>report_module() = atom() | undefined &lt;v>extended_dbg_match_spec()() = detail_level() | dbg_match_spec()</v>
+ <v>report_module() = atom() | undefined</v>
+ <v>extended_dbg_match_spec() = detail_level() | dbg_match_spec()</v>
<v>detail_level() = min | max | integer(X) when X =&lt; 0, X >= 100</v>
<v>trace_client() = {event_file, file_name()} | {dbg_trace_type(), dbg_trace_parameters()}</v>
<v>file_name() = string()</v>
@@ -221,7 +222,7 @@
<v>CollectorPid = pid()</v>
<v>RawPattern = {report_module(), extended_dbg_match_spec()}</v>
<v>report_module() = atom() | undefined</v>
- <v>extended_dbg_match_spec()() = detail_level() | dbg_match_spec()</v>
+ <v>extended_dbg_match_spec() = detail_level() | dbg_match_spec()</v>
<v>RawPattern = detail_level()</v>
<v>detail_level() = min | max | integer(X) when X =&lt; 0, X >= 100</v>
<v>TracePattern = {report_module(), dbg_match_spec_match_spec()}</v>
@@ -348,7 +349,8 @@
<v>done() = 0</v>
<v>forward() = infinity | integer(X) where X > 0</v>
<v>backward() = '-infinity' | integer(X) where X &lt; 0</v>
- <v>Fun = fun(Event, Acc) -> NewAcc &lt;v>Acc = NewAcc = term()</v>
+ <v>Fun = fun(Event, Acc) -> NewAcc</v>
+ <v>Acc = NewAcc = term()</v>
</type>
<desc>
<p>Iterate over the currently stored events.</p>
diff --git a/lib/et/doc/src/et_selector.xml b/lib/et/doc/src/et_selector.xml
index 441a4dd278..b819bbf0c6 100644
--- a/lib/et/doc/src/et_selector.xml
+++ b/lib/et/doc/src/et_selector.xml
@@ -90,7 +90,9 @@
<fsummary>Transforms trace data and makes an event record out of it</fsummary>
<type>
- <v>Mod = module_name() | undefined &lt;v>module_name() = atom() &lt;v>ValidTraceData = erlang_trace_data() | record(event)</v>
+ <v>Mod = module_name() | undefined</v>
+ <v>module_name() = atom()</v>
+ <v>ValidTraceData = erlang_trace_data() | record(event)</v>
<v>erlang_trace_data() = {trace, Pid, Label, Info} | {trace, Pid, Label, Info, Extra} | {trace_ts, Pid, Label, Info, ReportedTS} | {trace_ts, Pid, Label, Info, Extra, ReportedTS} | {seq_trace, Label, Info} | {seq_trace, Label, Info, ReportedTS} | {drop, NumberOfDroppedItems}</v>
</type>
diff --git a/lib/et/doc/src/files.mk b/lib/et/doc/src/files.mk
index 7437da7ce3..c9041caa81 100644
--- a/lib/et/doc/src/files.mk
+++ b/lib/et/doc/src/files.mk
@@ -1,7 +1,7 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2016. All Rights Reserved.
+# Copyright Ericsson AB 2002-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/et/doc/src/notes.xml b/lib/et/doc/src/notes.xml
index f0995b7c19..e7cec937b3 100644
--- a/lib/et/doc/src/notes.xml
+++ b/lib/et/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2002</year><year>2016</year>
+ <year>2002</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -37,6 +37,21 @@
one section in this document. The title of each section is the
version number of <c>Event Tracer (ET)</c>.</p>
+<section><title>ET 1.6.2</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Calls to <c>erlang:get_stacktrace()</c> are removed.
+ </p>
+ <p>
+ Own Id: OTP-14861</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>ET 1.6.1</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/et/src/et.app.src b/lib/et/src/et.app.src
index f4e32f734d..8cea1ba842 100644
--- a/lib/et/src/et.app.src
+++ b/lib/et/src/et.app.src
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/et/src/et_collector.erl b/lib/et/src/et_collector.erl
index ffe244324c..b432df8c62 100644
--- a/lib/et/src/et_collector.erl
+++ b/lib/et/src/et_collector.erl
@@ -509,7 +509,7 @@ get_global_pid() ->
%% CollectorPid = pid()
%% RawPattern = {report_module(), extended_dbg_match_spec()}
%% report_module() = atom() | undefined
-%% extended_dbg_match_spec()() = detail_level() | dbg_match_spec()
+%% extended_dbg_match_spec() = detail_level() | dbg_match_spec()
%% RawPattern = detail_level()
%% detail_level() = min | max | integer(X) when X =< 0, X >= 100
%% TracePattern = {report_module(), dbg_match_spec_match_spec()}
diff --git a/lib/et/src/et_wx_contents_viewer.erl b/lib/et/src/et_wx_contents_viewer.erl
index 7ca41da3e8..580c921139 100644
--- a/lib/et/src/et_wx_contents_viewer.erl
+++ b/lib/et/src/et_wx_contents_viewer.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/et/test/et_test_lib.erl b/lib/et/test/et_test_lib.erl
index fc469f646a..4addcd7ca8 100644
--- a/lib/et/test/et_test_lib.erl
+++ b/lib/et/test/et_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/et/test/ett.erl b/lib/et/test/ett.erl
index 2b276eab1a..dd274ec317 100644
--- a/lib/et/test/ett.erl
+++ b/lib/et/test/ett.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/et/vsn.mk b/lib/et/vsn.mk
index aab63a402e..08ded8b6f1 100644
--- a/lib/et/vsn.mk
+++ b/lib/et/vsn.mk
@@ -1 +1 @@
-ET_VSN = 1.6.1
+ET_VSN = 1.6.2
diff --git a/lib/eunit/doc/src/Makefile b/lib/eunit/doc/src/Makefile
index e91d947592..117542cb37 100644
--- a/lib/eunit/doc/src/Makefile
+++ b/lib/eunit/doc/src/Makefile
@@ -146,6 +146,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(XML_REF3_FILES) $(XML_CHAPTER_FILES) *.html
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
diff --git a/lib/eunit/doc/src/notes.xml b/lib/eunit/doc/src/notes.xml
index b38cb2e70e..0d2d61d553 100644
--- a/lib/eunit/doc/src/notes.xml
+++ b/lib/eunit/doc/src/notes.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2017</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -33,6 +33,21 @@
</header>
<p>This document describes the changes made to the EUnit application.</p>
+<section><title>Eunit 2.3.6</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Calls to <c>erlang:get_stacktrace()</c> are removed.
+ </p>
+ <p>
+ Own Id: OTP-14861</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Eunit 2.3.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/eunit/vsn.mk b/lib/eunit/vsn.mk
index 2ed9eaac16..054e21f6ad 100644
--- a/lib/eunit/vsn.mk
+++ b/lib/eunit/vsn.mk
@@ -1 +1 @@
-EUNIT_VSN = 2.3.5
+EUNIT_VSN = 2.3.6
diff --git a/lib/ftp/Makefile b/lib/ftp/Makefile
index 555f8b0dea..e0c9de42e4 100644
--- a/lib/ftp/Makefile
+++ b/lib/ftp/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2016. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/ftp/doc/src/Makefile b/lib/ftp/doc/src/Makefile
index e96a9c032f..20fbbc73a9 100644
--- a/lib/ftp/doc/src/Makefile
+++ b/lib/ftp/doc/src/Makefile
@@ -103,6 +103,7 @@ pdf: $(TOP_PDF_FILE)
html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs: clean_html clean_man clean_pdf
+ rm -rf $(XMLDIR)
rm -f errs core *~
man: $(MAN3_FILES)
diff --git a/lib/ftp/doc/src/ftp.xml b/lib/ftp/doc/src/ftp.xml
index 18770ebcb4..34e3ff84b0 100644
--- a/lib/ftp/doc/src/ftp.xml
+++ b/lib/ftp/doc/src/ftp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -314,7 +314,7 @@
<fsummary>Transfers a binary into a remote file.</fsummary>
<type>
<v>Pid = pid()</v>
- <v>Bin = binary()()</v>
+ <v>Bin = binary()</v>
<v>RemoteFile = string()</v>
<v>Reason = restriction_reason()| shortage_reason() | common_reason()</v>
</type>
@@ -546,11 +546,12 @@
<v>start_option() = {verbose, verbose()} | {debug, debug()}</v>
<v>verbose() = boolean() (default is false)</v>
<v>debug() = disable | debug | trace (default is disable)</v>
- <v>open_option() = {ipfamily, ipfamily()} | {port, port()} | {mode, mode()} | {tls, tls_options()} | {timeout, timeout()} | {dtimeout, dtimeout()} | {progress, progress()}</v>
+ <v>open_option() = {ipfamily, ipfamily()} | {port, port()} | {mode, mode()} | {tls, tls_options()} | {timeout, timeout()} | {dtimeout, dtimeout()} | {progress, progress() | {sock_ctrl, sock_opts()} | {sock_data_act, sock_opts()} | {sock_data_pass, sock_opts()} }</v>
<v>ipfamily() = inet | inet6 | inet6fb4 (default is inet)</v>
<v>port() = integer() > 0 (default is 21)</v>
<v>mode() = active | passive (default is passive)</v>
<v>tls_options() = [<seealso marker="ssl:ssl#type-ssloption">ssl:ssloption()</seealso>]</v>
+ <v>sock_opts() = [<seealso marker="kernel:gen_tcp#type-option">gen_tcp:option()</seealso> except for ipv6_v6only, active, packet, mode, packet_size and header</v>
<v>timeout() = integer() > 0 (default is 60000 milliseconds)</v>
<v>dtimeout() = integer() > 0 | infinity (default is infinity)</v>
<v>pogress() = ignore | {module(), function(), initial_data()} (default is ignore)</v>
@@ -573,6 +574,11 @@
is used for securing both the control connection and the data sessions.
</p>
+ <p>The options <c>sock_ctrl</c>, <c>sock_data_act</c> and <c>sock_data_pass</c> passes options down to
+ the underlying transport layer (tcp). The default value for <c>sock_ctrl</c> is <c>[]</c>. Both
+ <c>sock_data_act</c> and <c>sock_data_pass</c> uses the value of <c>sock_ctrl</c> as default value.
+ </p>
+
<p>A session opened in this way is closed using function
<seealso marker="#close">close</seealso>.</p>
@@ -730,7 +736,7 @@
<fsummary>Transfers a binary into a remote file.</fsummary>
<type>
<v>Pid = pid()</v>
- <v>Bin = binary()()</v>
+ <v>Bin = binary()</v>
<v>RemoteFile = string()</v>
<v>Reason = restriction_reason() | common_reason() | shortage_reason()</v>
</type>
diff --git a/lib/ftp/src/Makefile b/lib/ftp/src/Makefile
index 6a6df6bde4..93e3c4a8e5 100644
--- a/lib/ftp/src/Makefile
+++ b/lib/ftp/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2017. All Rights Reserved.
+# Copyright Ericsson AB 1999-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/ftp/src/ftp.erl b/lib/ftp/src/ftp.erl
index 8790bfec13..40f6b53fa3 100644
--- a/lib/ftp/src/ftp.erl
+++ b/lib/ftp/src/ftp.erl
@@ -101,6 +101,9 @@
%% data needed further on.
caller = undefined, % term()
ipfamily, % inet | inet6 | inet6fb4
+ sockopts_ctrl = [],
+ sockopts_data_passive = [],
+ sockopts_data_active = [],
progress = ignore, % ignore | pid()
dtimeout = ?DATA_ACCEPT_TIMEOUT, % non_neg_integer() | infinity
tls_upgrading_data_connection = false,
@@ -135,9 +138,10 @@ start_standalone(Options) ->
try
{ok, StartOptions} = start_options(Options),
{ok, OpenOptions} = open_options(Options),
+ {ok, SocketOptions} = socket_options(Options),
case start_link(StartOptions, []) of
{ok, Pid} ->
- call(Pid, {open, ip_comm, OpenOptions}, plain);
+ call(Pid, {open, ip_comm, OpenOptions, SocketOptions}, plain);
Error1 ->
Error1
end
@@ -149,10 +153,11 @@ start_standalone(Options) ->
start_service(Options) ->
try
{ok, StartOptions} = start_options(Options),
- {ok, OpenOptions} = open_options(Options),
+ {ok, OpenOptions} = open_options(Options),
+ {ok, SocketOptions} = socket_options(Options),
case ftp_sup:start_child([[[{client, self()} | StartOptions], []]]) of
{ok, Pid} ->
- call(Pid, {open, ip_comm, OpenOptions}, plain);
+ call(Pid, {open, ip_comm, OpenOptions, SocketOptions}, plain);
Error1 ->
Error1
end
@@ -200,9 +205,10 @@ open({option_list, Options}) when is_list(Options) ->
try
{ok, StartOptions} = start_options(Options),
{ok, OpenOptions} = open_options(Options),
+ {ok, SockOpts} = socket_options(Options),
case ftp_sup:start_child([[[{client, self()} | StartOptions], []]]) of
{ok, Pid} ->
- call(Pid, {open, ip_comm, OpenOptions}, plain);
+ call(Pid, {open, ip_comm, OpenOptions, SockOpts}, plain);
Error1 ->
Error1
end
@@ -227,9 +233,10 @@ open(Host, Opts) when is_list(Opts) ->
try
{ok, StartOptions} = start_options(Opts),
{ok, OpenOptions} = open_options([{host, Host}|Opts]),
+ {ok, SocketOptions} = socket_options(Opts),
case start_link(StartOptions, []) of
{ok, Pid} ->
- do_open(Pid, OpenOptions, tls_options(Opts));
+ do_open(Pid, OpenOptions, SocketOptions, tls_options(Opts));
Error1 ->
Error1
end
@@ -238,8 +245,8 @@ open(Host, Opts) when is_list(Opts) ->
Error2
end.
-do_open(Pid, OpenOptions, TLSOpts) ->
- case call(Pid, {open, ip_comm, OpenOptions}, plain) of
+do_open(Pid, OpenOptions, SocketOptions, TLSOpts) ->
+ case call(Pid, {open, ip_comm, OpenOptions, SocketOptions}, plain) of
{ok, Pid} ->
maybe_tls_upgrade(Pid, TLSOpts);
Error ->
@@ -1026,7 +1033,7 @@ handle_call({_,latest_ctrl_response}, _, #state{latest_ctrl_response=Resp} = Sta
handle_call({Pid, _}, _, #state{owner = Owner} = State) when Owner =/= Pid ->
{reply, {error, not_connection_owner}, State};
-handle_call({_, {open, ip_comm, Opts}}, From, State) ->
+handle_call({_, {open, ip_comm, Opts, {CtrlOpts, DataPassOpts, DataActOpts}}}, From, State) ->
case key_search(host, Opts, undefined) of
undefined ->
{stop, normal, {error, ehost}, State};
@@ -1043,6 +1050,9 @@ handle_call({_, {open, ip_comm, Opts}}, From, State) ->
mode = Mode,
progress = progress(Progress),
ipfamily = IpFamily,
+ sockopts_ctrl = CtrlOpts,
+ sockopts_data_passive = DataPassOpts,
+ sockopts_data_active = DataActOpts,
dtimeout = DTimeout,
ftp_extension = FtpExt},
@@ -1055,28 +1065,6 @@ handle_call({_, {open, ip_comm, Opts}}, From, State) ->
end
end;
-handle_call({_, {open, ip_comm, Host, Opts}}, From, State) ->
- Mode = key_search(mode, Opts, ?DEFAULT_MODE),
- Port = key_search(port, Opts, ?FTP_PORT),
- Timeout = key_search(timeout, Opts, ?CONNECTION_TIMEOUT),
- DTimeout = key_search(dtimeout, Opts, ?DATA_ACCEPT_TIMEOUT),
- Progress = key_search(progress, Opts, ignore),
- FtpExt = key_search(ftp_extension, Opts, ?FTP_EXT_DEFAULT),
-
- State2 = State#state{client = From,
- mode = Mode,
- progress = progress(Progress),
- dtimeout = DTimeout,
- ftp_extension = FtpExt},
-
- case setup_ctrl_connection(Host, Port, Timeout, State2) of
- {ok, State3, WaitTimeout} ->
- {noreply, State3, WaitTimeout};
- {error, _Reason} ->
- gen_server:reply(From, {error, ehost}),
- {stop, normal, State2#state{client = undefined}}
- end;
-
handle_call({_, {open, tls_upgrade, TLSOptions}}, From, State) ->
_ = send_ctrl_message(State, mk_cmd("AUTH TLS", [])),
activate_ctrl_connection(State),
@@ -1659,11 +1647,12 @@ handle_ctrl_result({pos_compl, Lines},
client = From,
caller = {setup_data_connection, Caller},
csock = CSock,
+ sockopts_data_passive = SockOpts,
timeout = Timeout}
= State) ->
[_, PortStr | _] = lists:reverse(string:tokens(Lines, "|")),
{ok, {IP, _}} = peername(CSock),
- case connect(IP, list_to_integer(PortStr), Timeout, State) of
+ case connect(IP, list_to_integer(PortStr), SockOpts, Timeout, State) of
{ok, _, Socket} ->
handle_caller(State#state{caller = Caller, dsock = {tcp, Socket}});
{error, _Reason} = Error ->
@@ -1676,7 +1665,8 @@ handle_ctrl_result({pos_compl, Lines},
ipfamily = inet,
client = From,
caller = {setup_data_connection, Caller},
- timeout = Timeout,
+ timeout = Timeout,
+ sockopts_data_passive = SockOpts,
ftp_extension = false} = State) ->
{_, [?LEFT_PAREN | Rest]} =
@@ -1690,7 +1680,7 @@ handle_ctrl_result({pos_compl, Lines},
Port = (P1 * 256) + P2,
?DBG('<--data tcp connect to ~p:~p, Caller=~p~n',[IP,Port,Caller]),
- case connect(IP, Port, Timeout, State) of
+ case connect(IP, Port, SockOpts, Timeout, State) of
{ok, _, Socket} ->
handle_caller(State#state{caller = Caller, dsock = {tcp,Socket}});
{error, _Reason} = Error ->
@@ -1705,13 +1695,14 @@ handle_ctrl_result({pos_compl, Lines},
caller = {setup_data_connection, Caller},
csock = CSock,
timeout = Timeout,
+ sockopts_data_passive = SockOpts,
ftp_extension = true} = State) ->
[_, PortStr | _] = lists:reverse(string:tokens(Lines, "|")),
{ok, {IP, _}} = peername(CSock),
?DBG('<--data tcp connect to ~p:~p, Caller=~p~n',[IP,PortStr,Caller]),
- case connect(IP, list_to_integer(PortStr), Timeout, State) of
+ case connect(IP, list_to_integer(PortStr), SockOpts, Timeout, State) of
{ok, _, Socket} ->
handle_caller(State#state{caller = Caller, dsock = {tcp, Socket}});
{error, _Reason} = Error ->
@@ -2075,9 +2066,9 @@ handle_caller(#state{caller = {transfer_data, {Cmd, Bin, RemoteFile}}} =
%% Connect to FTP server at Host (default is TCP port 21)
%% in order to establish a control connection.
-setup_ctrl_connection(Host, Port, Timeout, State) ->
+setup_ctrl_connection(Host, Port, Timeout, #state{sockopts_ctrl = SockOpts} = State) ->
MsTime = erlang:monotonic_time(),
- case connect(Host, Port, Timeout, State) of
+ case connect(Host, Port, SockOpts, Timeout, State) of
{ok, IpFam, CSock} ->
NewState = State#state{csock = {tcp, CSock}, ipfamily = IpFam},
activate_ctrl_connection(NewState),
@@ -2095,12 +2086,15 @@ setup_ctrl_connection(Host, Port, Timeout, State) ->
setup_data_connection(#state{mode = active,
caller = Caller,
csock = CSock,
+ sockopts_data_active = SockOpts,
ftp_extension = FtpExt} = State) ->
case (catch sockname(CSock)) of
- {ok, {{_, _, _, _, _, _, _, _} = IP, _}} ->
+ {ok, {{_, _, _, _, _, _, _, _} = IP0, _}} ->
+ IP = proplists:get_value(ip, SockOpts, IP0),
{ok, LSock} =
gen_tcp:listen(0, [{ip, IP}, {active, false},
- inet6, binary, {packet, 0}]),
+ inet6, binary, {packet, 0} |
+ lists:keydelete(ip,1,SockOpts)]),
{ok, {_, Port}} = sockname({tcp,LSock}),
IpAddress = inet_parse:ntoa(IP),
Cmd = mk_cmd("EPRT |2|~s|~p|", [IpAddress, Port]),
@@ -2108,9 +2102,11 @@ setup_data_connection(#state{mode = active,
activate_ctrl_connection(State),
{noreply, State#state{caller = {setup_data_connection,
{LSock, Caller}}}};
- {ok, {{_,_,_,_} = IP, _}} ->
+ {ok, {{_,_,_,_} = IP0, _}} ->
+ IP = proplists:get_value(ip, SockOpts, IP0),
{ok, LSock} = gen_tcp:listen(0, [{ip, IP}, {active, false},
- binary, {packet, 0}]),
+ binary, {packet, 0} |
+ lists:keydelete(ip,1,SockOpts)]),
{ok, Port} = inet:port(LSock),
_ = case FtpExt of
false ->
@@ -2149,41 +2145,41 @@ setup_data_connection(#state{mode = passive, ipfamily = inet,
activate_ctrl_connection(State),
{noreply, State#state{caller = {setup_data_connection, Caller}}}.
-connect(Host, Port, Timeout, #state{ipfamily = inet = IpFam}) ->
- connect2(Host, Port, IpFam, Timeout);
+connect(Host, Port, SockOpts, Timeout, #state{ipfamily = inet = IpFam}) ->
+ connect2(Host, Port, IpFam, SockOpts, Timeout);
-connect(Host, Port, Timeout, #state{ipfamily = inet6 = IpFam}) ->
- connect2(Host, Port, IpFam, Timeout);
+connect(Host, Port, SockOpts, Timeout, #state{ipfamily = inet6 = IpFam}) ->
+ connect2(Host, Port, IpFam, SockOpts, Timeout);
-connect(Host, Port, Timeout, #state{ipfamily = inet6fb4}) ->
+connect(Host, Port, SockOpts, Timeout, #state{ipfamily = inet6fb4}) ->
case inet:getaddr(Host, inet6) of
{ok, {0, 0, 0, 0, 0, 16#ffff, _, _} = IPv6} ->
case inet:getaddr(Host, inet) of
{ok, IPv4} ->
IpFam = inet,
- connect2(IPv4, Port, IpFam, Timeout);
+ connect2(IPv4, Port, IpFam, SockOpts, Timeout);
_ ->
IpFam = inet6,
- connect2(IPv6, Port, IpFam, Timeout)
+ connect2(IPv6, Port, IpFam, SockOpts, Timeout)
end;
{ok, IPv6} ->
IpFam = inet6,
- connect2(IPv6, Port, IpFam, Timeout);
+ connect2(IPv6, Port, IpFam, SockOpts, Timeout);
_ ->
case inet:getaddr(Host, inet) of
{ok, IPv4} ->
IpFam = inet,
- connect2(IPv4, Port, IpFam, Timeout);
+ connect2(IPv4, Port, IpFam, SockOpts, Timeout);
Error ->
Error
end
end.
-connect2(Host, Port, IpFam, Timeout) ->
- Opts = [IpFam, binary, {packet, 0}, {active, false}],
+connect2(Host, Port, IpFam, SockOpts, Timeout) ->
+ Opts = [IpFam, binary, {packet, 0}, {active, false} | SockOpts],
case gen_tcp:connect(Host, Port, Opts, Timeout) of
{ok, Sock} ->
{ok, IpFam, Sock};
@@ -2553,6 +2549,32 @@ open_options(Options) ->
{ftp_extension, ValidateFtpExtension, false, ?FTP_EXT_DEFAULT}],
validate_options(Options, ValidOptions, []).
+socket_options(Options) ->
+ CtrlOpts = proplists:get_value(sock_ctrl, Options, []),
+ DataActOpts = proplists:get_value(sock_data_act, Options, CtrlOpts),
+ DataPassOpts = proplists:get_value(sock_data_pass, Options, CtrlOpts),
+ case [O || O <- lists:usort(CtrlOpts++DataPassOpts++DataActOpts),
+ not valid_socket_option(O)] of
+ [] ->
+ {ok, {CtrlOpts, DataPassOpts, DataActOpts}};
+ Invalid ->
+ throw({error,{sock_opts,Invalid}})
+ end.
+
+
+valid_socket_option(inet ) -> false;
+valid_socket_option(inet6 ) -> false;
+valid_socket_option({ipv6_v6only, _}) -> false;
+valid_socket_option({active,_} ) -> false;
+valid_socket_option({packet,_} ) -> false;
+valid_socket_option({mode,_} ) -> false;
+valid_socket_option(binary ) -> false;
+valid_socket_option(list ) -> false;
+valid_socket_option({header,_} ) -> false;
+valid_socket_option({packet_size,_} ) -> false;
+valid_socket_option(_) -> true.
+
+
tls_options(Options) ->
%% Options will be validated by ssl application
proplists:get_value(tls, Options, undefined).
diff --git a/lib/ftp/src/ftp_progress.erl b/lib/ftp/src/ftp_progress.erl
index a6263e5cd7..64c612519d 100644
--- a/lib/ftp/src/ftp_progress.erl
+++ b/lib/ftp/src/ftp_progress.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ftp/src/ftp_response.erl b/lib/ftp/src/ftp_response.erl
index d54d97dc91..8d00153ba8 100644
--- a/lib/ftp/src/ftp_response.erl
+++ b/lib/ftp/src/ftp_response.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ftp/test/erl_make_certs.erl b/lib/ftp/test/erl_make_certs.erl
index 2db95825bc..e10ecf01f9 100644
--- a/lib/ftp/test/erl_make_certs.erl
+++ b/lib/ftp/test/erl_make_certs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ftp/test/ftp_SUITE.erl b/lib/ftp/test/ftp_SUITE.erl
index 92d2c36a86..7c87d5cbdb 100644
--- a/lib/ftp/test/ftp_SUITE.erl
+++ b/lib/ftp/test/ftp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ftp/test/ftp_format_SUITE.erl b/lib/ftp/test/ftp_format_SUITE.erl
index 95d594a44b..e1d0de2390 100644
--- a/lib/ftp/test/ftp_format_SUITE.erl
+++ b/lib/ftp/test/ftp_format_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ftp/test/ftp_property_test_SUITE.erl b/lib/ftp/test/ftp_property_test_SUITE.erl
index 46ed6959a8..cd43613b9e 100644
--- a/lib/ftp/test/ftp_property_test_SUITE.erl
+++ b/lib/ftp/test/ftp_property_test_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ftp/test/property_test/ftp_simple_client_server.erl b/lib/ftp/test/property_test/ftp_simple_client_server.erl
index 1bc54128f6..d304478b47 100644
--- a/lib/ftp/test/property_test/ftp_simple_client_server.erl
+++ b/lib/ftp/test/property_test/ftp_simple_client_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/hipe/cerl/Makefile b/lib/hipe/cerl/Makefile
index b6116c4276..f653dce36f 100644
--- a/lib/hipe/cerl/Makefile
+++ b/lib/hipe/cerl/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2016. All Rights Reserved.
+# Copyright Ericsson AB 2003-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/hipe/doc/src/Makefile b/lib/hipe/doc/src/Makefile
index 1c774d3357..bd6a7b2f74 100644
--- a/lib/hipe/doc/src/Makefile
+++ b/lib/hipe/doc/src/Makefile
@@ -94,6 +94,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/hipe/doc/src/hipe_app.xml b/lib/hipe/doc/src/hipe_app.xml
index fc42ecd97d..99759a2f2c 100644
--- a/lib/hipe/doc/src/hipe_app.xml
+++ b/lib/hipe/doc/src/hipe_app.xml
@@ -4,7 +4,7 @@
<appref>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -35,6 +35,14 @@
<app>HiPE</app>
<appsummary>The HiPE Application</appsummary>
<description>
+ <note>
+ <p>
+ HiPE and execution of HiPE compiled code only have limited support by
+ the OTP team at Ericsson. The OTP team only does limited maintenance
+ of HiPE and does not actively develop HiPE. HiPE is mainly supported
+ by the HiPE team at Uppsala University.
+ </p>
+ </note>
<p>
The normal way to native-compile an Erlang module using HiPE is to include the atom native
in the Erlang compiler options, as in:</p>
@@ -70,12 +78,12 @@
</item>
<tag>NIFs</tag>
- <item><p>Modules compiled with HiPE can not call <seealso marker="erts:erlang#load_nif-2">
+ <item><p>Modules compiled with HiPE cannot call <seealso marker="erts:erlang#load_nif-2">
<c>erlang:load_nif/2</c></seealso> to load NIFs.</p>
</item>
<tag>-on_load</tag>
- <item><p>Modules compiled with HiPE can not use
+ <item><p>Modules compiled with HiPE cannot use
<seealso marker="doc/reference_manual:code_loading#on_load"><c>-on_load()</c></seealso>
directives.</p>
</item>
@@ -108,7 +116,7 @@
queue when the reference was created will be bypassed, as they
cannot possibly contain the reference. HiPE currently has an
optimization similar this, but it is not guaranteed to
- bypass all messages. In the worst case scenario it, cannot
+ bypass all messages. In the worst case scenario, it cannot
bypass any messages at all.
</p>
<p>
@@ -117,21 +125,55 @@
</p>
</item>
+ <tag>Garbage collection after BIFs</tag>
+ <item>
+ <p>
+ The condition for determining whether a garbage collection
+ is needed or not has changed in later releases. HiPE has not
+ been updated regarding this which may cause premature garbage
+ collections after BIF calls.
+ </p>
+ </item>
+
</taglist>
</section>
<section>
<title>Stability Issues</title>
<taglist>
- <tag>Not yielding in <c>receive</c> statements</tag>
+ <tag>Not checking reduction count on function returns</tag>
<item>
- <p>HiPE will not yield in <c>receive</c> statements where
- appropriate. If a process have lots of signals in its signal
- queue and execute a HiPE compiled <c>receive</c> statement,
- the scheduler thread performing the execution may be stuck
- in the <c>receive</c> statement for a very long time. This
- can in turn cause various severe issues such as for example
- prevent the runtime system from being able to release
- memory.
+ <p>
+ BEAM checks the reduction count and schedules out the executing
+ process if needed both when calling a function and when returning
+ from a function call that was not called using a tail call.
+ HiPE only checks the reduction count when calling a function.
+ </p>
+ <p>
+ The runtime system might need to schedule out a process
+ in order to reclaim memory. If the process isn't scheduled
+ out soon after the process has entered this state, memory
+ consumption will quickly grow. Maintaining this state is also
+ quite expensive performance wise.
+ </p>
+ <p>
+ Processes executing code that performs large recursions and
+ produce data after returning from recursive calls may have to
+ be scheduled out when returning from a function call. Since
+ HiPE does not check reductions on returns, processes executing
+ such HiPE compiled code may cause huge peeks in memory
+ consumption as well as severe performance degradation.
+ </p>
+ </item>
+
+ <tag>Not bumping appropriate amount of reductions in <c>receive</c> statements</tag>
+ <item>
+ <p>
+ The process signaling improvements made in ERTS version
+ 10.0 moved potentially significant amounts of work into the
+ receive statement from other places. In order to account for
+ this work, the reduction count should be bumped on the
+ executing process. Reductions are not bumped when entering
+ the <c>receive</c> statement from HiPE compiled code.
</p>
</item>
</taglist>
diff --git a/lib/hipe/doc/src/notes.xml b/lib/hipe/doc/src/notes.xml
index c190a89260..f47868296a 100644
--- a/lib/hipe/doc/src/notes.xml
+++ b/lib/hipe/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2006</year><year>2017</year>
+ <year>2006</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,51 @@
</header>
<p>This document describes the changes made to HiPE.</p>
+<section><title>Hipe 3.18</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Optimize <c>receive</c> statements that are only waiting
+ for messages containing a reference created before the
+ receive. All messages that existed in the queue when the
+ reference was created will be bypassed, as they cannot
+ possibly contain the reference. This optimization has
+ existed for vanilla BEAM since OTP R14.</p>
+ <p>
+ Own Id: OTP-14785 Aux Id: PR-1632 </p>
+ </item>
+ <item>
+ <p>
+ Add validation pass to hipe compiler to detect internal
+ errors causing primop calls that may trigger an unsafe GC
+ at run-time. The pass can be disabled with option
+ <c>no_verify_gcsafe</c>.</p>
+ <p>
+ Own Id: OTP-14900 Aux Id: PR-1685, PR-1621 </p>
+ </item>
+ <item>
+ <p>
+ Make hipe compiled code work on x86_64 (amd64) with OS
+ security feature PIE, where executable code can be loaded
+ into a random location. Old behavior, if hipe was
+ enabled, was to disable PIE build options for the VM.</p>
+ <p>
+ Own Id: OTP-14903</p>
+ </item>
+ <item>
+ <p>
+ Inline more type test BIFs; <c>is_number</c>,
+ <c>is_bitstring</c>, <c>is_map</c>.</p>
+ <p>
+ Own Id: OTP-14941 Aux Id: PR-1718 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Hipe 3.17.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/hipe/icode/hipe_icode_range.erl b/lib/hipe/icode/hipe_icode_range.erl
index 34b18acccd..098a7a8d8c 100644
--- a/lib/hipe/icode/hipe_icode_range.erl
+++ b/lib/hipe/icode/hipe_icode_range.erl
@@ -1633,7 +1633,7 @@ inf_bsl(_, pos_inf) -> neg_inf;
inf_bsl(Number, neg_inf) when is_integer(Number), Number >= 0 -> 0;
inf_bsl(_Number, neg_inf) -> -1;
inf_bsl(Number1, Number2) when is_integer(Number1), is_integer(Number2) ->
- %% We can not shift left with a number which is not a fixnum. We
+ %% We cannot shift left with a number which is not a fixnum. We
%% don't have enough memory.
Bits = ?BITS,
if Number2 > (Bits bsl 1) -> inf_bsl(Number1, pos_inf);
diff --git a/lib/hipe/main/hipe.app.src b/lib/hipe/main/hipe.app.src
index 7350e873aa..4684ab49ea 100644
--- a/lib/hipe/main/hipe.app.src
+++ b/lib/hipe/main/hipe.app.src
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl
index 97814fe217..ac2e6c1e3b 100644
--- a/lib/hipe/main/hipe.erl
+++ b/lib/hipe/main/hipe.erl
@@ -852,8 +852,8 @@ finalize_fun_sequential({MFA, Icode}, Opts, Servers) ->
print_crash_message(What, Error, StackTrace) ->
StackFun = fun(_,_,_) -> false end,
FormatFun = fun (Term, _) -> io_lib:format("~p", [Term]) end,
- StackTrace = lib:format_stacktrace(1, StackTrace,
- StackFun, FormatFun),
+ StackTraceS = erl_error:format_stacktrace(1, StackTrace,
+ StackFun, FormatFun),
WhatS = case What of
{M,F,A} -> io_lib:format("~w:~w/~w", [M,F,A]);
Mod -> io_lib:format("~w", [Mod])
@@ -862,7 +862,7 @@ print_crash_message(What, Error, StackTrace) ->
"while compiling ~s~n"
"crash reason: ~p~n"
"~s~n",
- [WhatS, Error, StackTrace]).
+ [WhatS, Error, StackTraceS]).
pp_server_start(Opts) ->
set_architecture(Opts),
diff --git a/lib/hipe/rtl/hipe_icode2rtl.erl b/lib/hipe/rtl/hipe_icode2rtl.erl
index 6da8a76d34..1ab41f4deb 100644
--- a/lib/hipe/rtl/hipe_icode2rtl.erl
+++ b/lib/hipe/rtl/hipe_icode2rtl.erl
@@ -215,7 +215,7 @@ gen_enter(I, VarMap, ConstTab) ->
{Code1, ConstTab2} =
case hipe_icode:enter_type(I) of
primop ->
- IsGuard = false, % enter can not happen in a guard
+ IsGuard = false, % enter cannot happen in a guard
hipe_rtl_primops:gen_enter_primop({Fun, Args}, IsGuard, ConstTab1);
Type ->
Call = gen_enter_1(Fun, Args, Type),
diff --git a/lib/hipe/rtl/hipe_rtl_arith.inc b/lib/hipe/rtl/hipe_rtl_arith.inc
index c05b7aa160..575f10b542 100644
--- a/lib/hipe/rtl/hipe_rtl_arith.inc
+++ b/lib/hipe/rtl/hipe_rtl_arith.inc
@@ -118,8 +118,8 @@ eval_alu(Op, Arg1, Arg2) ->
%% Björn & Bjarni:
%% We need to be able to do evaluations based only on the bits, since
-%% there are cases where we can evaluate a subset of the bits, but can
-%% not do a full eval-alub call (eg. a + 0 gives no carry)
+%% there are cases where we can evaluate a subset of the bits, but
+%% cannot do a full eval-alub call (eg. a + 0 gives no carry)
%%
-spec eval_cond_bits(hipe_rtl:alub_cond(), boolean(),
boolean(), boolean(), boolean()) -> boolean().
diff --git a/lib/hipe/rtl/hipe_rtl_lcm.erl b/lib/hipe/rtl/hipe_rtl_lcm.erl
index af39c9a0a4..2c8cc80e56 100644
--- a/lib/hipe/rtl/hipe_rtl_lcm.erl
+++ b/lib/hipe/rtl/hipe_rtl_lcm.erl
@@ -267,14 +267,17 @@ try_insert_expr_last(CFG0, Label, Instr) ->
%% with the new code inserted second to last (assuming the last expression
%% is a branch operation).
insert_expr_last_work(_Instr, [#call{}]) ->
- %% Call instructions clobber all expressions; we musn't insert the expression
- %% before it
+ %% Call instructions clobber all expressions; we must not insert the
+ %% expression before it
not_safe;
insert_expr_last_work(Instr, [Code1]) ->
%% We insert the code next to last.
[Instr, Code1];
insert_expr_last_work(Instr, [Code|Codes]) ->
- [Code|insert_expr_last_work(Instr, Codes)].
+ case insert_expr_last_work(Instr, Codes) of
+ not_safe -> not_safe;
+ NewCodes -> [Code|NewCodes]
+ end.
%%=============================================================================
%% Inserts expression first in the block for the given label.
diff --git a/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl b/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl
index cad43e2df5..72373e536d 100644
--- a/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl
+++ b/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl
@@ -31,11 +31,11 @@
%%
%% Some things to note:
%%
-%% 1. All precoloured registers are assumed to contain bottom. We can not
+%% 1. All precoloured registers are assumed to contain bottom. We cannot
%% do anything with them since they are not in SSA-form. This might be
%% possible to resolve in some way, but we decided to not go there.
%%
-%% 2. const_labels are assumed to be bottom, we can not find the address
+%% 2. const_labels are assumed to be bottom, we cannot find the address
%% in any nice way (that I know of, maybe someone can help ?). I
%% suppose they don't get a value until linking (or some step that
%% resembles it). They are only affecting bignums and floats (at least
@@ -579,7 +579,7 @@ visit_multimove(Inst, Env) ->
%% Procedure : visit_call/2
%% Purpose : execute a call-instruction. All calls return bottom. We make
%% this assumption since the icode-leel have taken care of BIF's
-%% and we belive that we are left with the things that can not be
+%% and we belive that we are left with the things that cannot be
%% done att compile time.
%% Arguments : Inst - The instruction
%% Env - The environment
diff --git a/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl b/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl
index e71045bfe2..fc87abb54e 100644
--- a/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl
+++ b/lib/hipe/test/basic_SUITE_data/basic_issues_hipe.erl
@@ -8,8 +8,9 @@
-export([test/0]).
-%% functions that need to be exported so that they are retained.
--export([auth/4]).
+%% functions that need to be exported so that they are retained and/or
+%% not specialized away by the compiler.
+-export([auth/4, wxSizer_replace/2, parent_class/1]).
test() ->
ok = test_dominance_trees(),
@@ -18,6 +19,7 @@ test() ->
ok = test_bif_fails(),
ok = test_find_catches(),
ok = test_heap_allocate_trim(),
+ ok = wxSizer_replace(),
ok.
%%--------------------------------------------------------------------
@@ -151,3 +153,25 @@ get_next_retry(Error, Count) ->
end.
pair(A, B) -> {A, B}.
+
+%%--------------------------------------------------------------------
+%% Date: June 11, 2018
+%%
+%% Stripped down test case (from `wxSizer') that crashed the lazy code
+%% motion pass of the HiPE compiler in a pre-release of Erlang/OTP 21.
+%% A similar crash existed in `ssl_correction'.
+%%--------------------------------------------------------------------
+
+wxSizer_replace() ->
+ wxSizer_replace(?MODULE, ?MODULE).
+
+-define(CLASS(Type, Class), ((Type) =:= Class) orelse (Type):parent_class(Class)).
+
+wxSizer_replace(OldwinT, NewwinT) -> % this function was the culprit
+ ?CLASS(OldwinT, ?MODULE),
+ ?CLASS(NewwinT, ?MODULE),
+ ok.
+
+parent_class(wxWindow) -> true;
+parent_class(wxEvtHandler) -> true;
+parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
diff --git a/lib/hipe/vsn.mk b/lib/hipe/vsn.mk
index 0c517f9a7a..b081cb0c26 100644
--- a/lib/hipe/vsn.mk
+++ b/lib/hipe/vsn.mk
@@ -1 +1 @@
-HIPE_VSN = 3.17.1
+HIPE_VSN = 3.18
diff --git a/lib/inets/doc/src/Makefile b/lib/inets/doc/src/Makefile
index 90c1258d4a..cbc0e384d8 100644
--- a/lib/inets/doc/src/Makefile
+++ b/lib/inets/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2015. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -115,6 +115,7 @@ pdf: $(TOP_PDF_FILE)
html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs: clean_html clean_man clean_pdf
+ rm -rf $(XMLDIR)
rm -f errs core *~
man: $(MAN3_FILES)
diff --git a/lib/inets/doc/src/http_client.xml b/lib/inets/doc/src/http_client.xml
index 15e383ec77..c31a47f4f4 100644
--- a/lib/inets/doc/src/http_client.xml
+++ b/lib/inets/doc/src/http_client.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/inets/doc/src/http_uri.xml b/lib/inets/doc/src/http_uri.xml
index f57214a7ce..2dec5acbf9 100644
--- a/lib/inets/doc/src/http_uri.xml
+++ b/lib/inets/doc/src/http_uri.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2012</year><year>2017</year>
+ <year>2012</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml
index 521ad6a015..a2871f3b95 100644
--- a/lib/inets/doc/src/httpc.xml
+++ b/lib/inets/doc/src/httpc.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml
index edf8731a82..e5adb4eb20 100644
--- a/lib/inets/doc/src/httpd.xml
+++ b/lib/inets/doc/src/httpd.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -173,7 +173,7 @@
<item>
<p>For <c>ip_comm</c> configuration options, see
<seealso marker="kernel:gen_tcp#listen-2">gen_tcp:listen/2</seealso>, some options
- that are used internally by httpd can not be set.</p>
+ that are used internally by httpd cannot be set.</p>
<p>For <c>SSL</c> configuration options, see
<seealso marker="ssl:ssl#listen-2">ssl:listen/2</seealso>.</p>
<p>Default is <c>ip_comm</c>.</p>
diff --git a/lib/inets/doc/src/inets.xml b/lib/inets/doc/src/inets.xml
index eb4e51584f..9b0ffaad5e 100644
--- a/lib/inets/doc/src/inets.xml
+++ b/lib/inets/doc/src/inets.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2007</year><year>2016</year>
+ <year>2007</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/inets/doc/src/mod_esi.xml b/lib/inets/doc/src/mod_esi.xml
index d024c8afa8..ede7dc8f7d 100644
--- a/lib/inets/doc/src/mod_esi.xml
+++ b/lib/inets/doc/src/mod_esi.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/inets/doc/src/mod_security.xml b/lib/inets/doc/src/mod_security.xml
index ec8d6ec42c..d65d2ff998 100644
--- a/lib/inets/doc/src/mod_security.xml
+++ b/lib/inets/doc/src/mod_security.xml
@@ -135,7 +135,8 @@
<type>
<v>What = atom()</v>
<v>Port = integer()</v>
- <v>Address = {A,B,C,D} | string() &lt;v>Dir = string()</v>
+ <v>Address = {A,B,C,D} | string()</v>
+ <v>Dir = string()</v>
<v>Data = [Info]</v>
<v>Info = {Name, Value}</v>
</type>
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 10dd26322c..88a4335f60 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2002</year><year>2017</year>
+ <year>2002</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -33,7 +33,135 @@
<file>notes.xml</file>
</header>
- <section><title>Inets 6.5.1</title>
+ <section><title>Inets 7.0</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed HTTP content injection bug in httpc (ERL-456).</p>
+ <p>
+ Own Id: OTP-14726</p>
+ </item>
+ <item>
+ <p>
+ Fixed support for URI-references in HTTP 'Location'
+ header (ERL-333).</p>
+ <p>
+ Own Id: OTP-14729</p>
+ </item>
+ <item>
+ <p>
+ Fix broken 'Content-Type' handling in httpc (ERL-536).</p>
+ <p>
+ Own Id: OTP-15006</p>
+ </item>
+ <item>
+ <p>
+ Fix handling of relative paths in the script_alias
+ property of httpd (ERL-574).</p>
+ <p>
+ Own Id: OTP-15021</p>
+ </item>
+ <item>
+ <p>
+ Fix httpd:reload_config/2 with path() as the first
+ argument (ERL-578).</p>
+ <p>
+ Own Id: OTP-15025</p>
+ </item>
+ <item>
+ <p>
+ Improved gracefulness.</p>
+ <p>
+ Own Id: OTP-15042</p>
+ </item>
+ </list>
+ </section>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Split inets and create separate ftp and tftp apps.</p>
+ <p>
+ Own Id: OTP-14113</p>
+ </item>
+ </list>
+ </section>
+
+ </section>
+
+ <section><title>Inets 6.5.2.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Change status code for no mod found to handle request to
+ 501</p>
+ <p>
+ Own Id: OTP-15215</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 6.5.2.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Enhance error handling, that is mod_get will return 403
+ if a path is a directory and not a file.</p>
+ <p>
+ Own Id: OTP-15192</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+ <section><title>Inets 6.5.2.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Options added for setting low-level properties on the
+ underlying TCP connections. The options are:
+ <c>sock_ctrl</c>, <c>sock_data_act</c> and
+ <c>sock_data_pass</c>. See the manual for details.</p>
+ <p>
+ Own Id: OTP-15120 Aux Id: ERIERL-192 </p>
+ </item>
+ </list>
+ </section>
+
+ </section>
+
+<section><title>Inets 6.5.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ inets: httpd - Gracefully handle bad headers</p>
+ <p>
+ The option max_headers operated on the individual header
+ length instead of the total length of all headers. Also
+ headers with empty keys are now discarded.</p>
+ <p>
+ Own Id: OTP-15092</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 6.5.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
@@ -1070,7 +1198,7 @@
Add option {ftp_extension, boolean} to enable use of
extended commands EPSV and EPRT, as specified in RFC
2428, for IPv4 instead of using the legacy commands. Ipv6
- can not be supported without the extended commands.</p>
+ cannot be supported without the extended commands.</p>
<p>
Own Id: OTP-12255</p>
</item>
diff --git a/lib/inets/doc/src/notes_history.xml b/lib/inets/doc/src/notes_history.xml
index c12899e614..1523827db9 100644
--- a/lib/inets/doc/src/notes_history.xml
+++ b/lib/inets/doc/src/notes_history.xml
@@ -1149,8 +1149,8 @@
<list type="bulleted">
<item>
<p>When further testing the functionality of https requests
- that goes through a proxy. We realised that alas this can
- not currently be supported as it requires features from
+ that goes through a proxy. We realised that alas this
+ cannot currently be supported as it requires features from
the ssl implementation that is not currently available.
So for now an error message will be returned when trying
to use this functionality.</p>
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index a73503a5ce..24a205ced9 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/http_client/httpc_cookie.erl b/lib/inets/src/http_client/httpc_cookie.erl
index cbf428ab3e..2e647a1438 100644
--- a/lib/inets/src/http_client/httpc_cookie.erl
+++ b/lib/inets/src/http_client/httpc_cookie.erl
@@ -271,7 +271,7 @@ lookup_cookies(CookieDb, Host, Path) ->
lookup_domain_cookies(_CookieDb, [], AccCookies) ->
lists:flatten(AccCookies);
-%% Top domains can not have cookies
+%% Top domains cannot have cookies
lookup_domain_cookies(_CookieDb, [_], AccCookies) ->
lists:flatten(AccCookies);
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index c9763507d1..5e05b8170a 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/http_client/httpc_internal.hrl b/lib/inets/src/http_client/httpc_internal.hrl
index c5fe439722..a14d8aa71b 100644
--- a/lib/inets/src/http_client/httpc_internal.hrl
+++ b/lib/inets/src/http_client/httpc_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl
index c3404dbb37..0333442bf2 100644
--- a/lib/inets/src/http_client/httpc_manager.erl
+++ b/lib/inets/src/http_client/httpc_manager.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/http_client/httpc_request.erl b/lib/inets/src/http_client/httpc_request.erl
index 641b6559de..9b81bd7a80 100644
--- a/lib/inets/src/http_client/httpc_request.erl
+++ b/lib/inets/src/http_client/httpc_request.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/http_client/httpc_response.erl b/lib/inets/src/http_client/httpc_response.erl
index 92dc9b0e02..bb6b76da89 100644
--- a/lib/inets/src/http_client/httpc_response.erl
+++ b/lib/inets/src/http_client/httpc_response.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -398,7 +398,7 @@ redirect(Response = {_, Headers, _}, Request) ->
THost = http_util:maybe_add_brackets(maps:get(host, URIMap), Brackets),
TPort = maps:get(port, URIMap),
TPath = maps:get(path, URIMap),
- TQuery = maps:get(query, URIMap, ""),
+ TQuery = add_question_mark(maps:get(query, URIMap, "")),
NewURI = uri_string:normalize(
uri_string:recompose(URIMap)),
HostPort = http_request:normalize_host(TScheme, THost, TPort),
@@ -417,29 +417,38 @@ redirect(Response = {_, Headers, _}, Request) ->
end
end.
+add_question_mark(<<>>) ->
+ <<>>;
+add_question_mark([]) ->
+ [];
+add_question_mark(Comp) when is_binary(Comp) ->
+ <<$?, Comp/binary>>;
+add_question_mark(Comp) when is_list(Comp) ->
+ [$?|Comp].
%% RFC3986 - 5.2.2. Transform References
resolve_uri(Scheme, Host, Port, Path, Query, URI) ->
resolve_uri(Scheme, Host, Port, Path, Query, URI, #{}).
%%
resolve_uri(Scheme, Host, Port, Path, Query, URI, Map0) ->
- case maps:is_key(scheme, URI) of
- true ->
- Port = get_port(URI),
+ case maps:get(scheme, URI, undefined) of
+ undefined ->
+ Port0 = get_port(Scheme, URI),
+ Map = Map0#{scheme => Scheme,
+ port => Port0},
+ resolve_authority(Host, Port, Path, Query, URI, Map);
+ URIScheme ->
+ Port0 = get_port(URIScheme, URI),
maybe_add_query(
- Map0#{scheme => maps:get(scheme, URI),
- host => maps:get(host, URI),
- port => Port,
- path => maps:get(path, URI)},
- URI);
- false ->
- Map = Map0#{scheme => Scheme},
- resolve_authority(Host, Port, Path, Query, URI, Map)
+ Map0#{scheme => URIScheme,
+ host => maps:get(host, URI),
+ port => Port0,
+ path => maps:get(path, URI)},
+ URI)
end.
-get_port(URI) ->
- Scheme = maps:get(scheme, URI),
+get_port(Scheme, URI) ->
case maps:get(port, URI, undefined) of
undefined ->
get_default_port(Scheme);
@@ -457,15 +466,13 @@ get_default_port("https") ->
resolve_authority(Host, Port, Path, Query, RelURI, Map) ->
case maps:is_key(host, RelURI) of
true ->
- Port = get_port(RelURI),
maybe_add_query(
Map#{host => maps:get(host, RelURI),
- port => Port,
path => maps:get(path, RelURI)},
RelURI);
false ->
Map1 = Map#{host => Host,
- port => Port},
+ port => Port},
resolve_path(Path, Query, RelURI, Map1)
end.
diff --git a/lib/inets/src/http_lib/http_request.erl b/lib/inets/src/http_lib/http_request.erl
index f68b233e10..2b1a0bd40f 100644
--- a/lib/inets/src/http_lib/http_request.erl
+++ b/lib/inets/src/http_lib/http_request.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,10 +27,12 @@
key_value(KeyValueStr) ->
case lists:splitwith(fun($:) -> false; (_) -> true end, KeyValueStr) of
- {Key, [$: | Value]} ->
+ {Key, [$: | Value]} when Key =/= [] ->
{http_util:to_lower(string:strip(Key)), string:strip(Value)};
{_, []} ->
- undefined
+ undefined;
+ _ ->
+ undefined
end.
%%-------------------------------------------------------------------------
%% headers(HeaderList, #http_request_h{}) -> #http_request_h{}
diff --git a/lib/inets/src/http_lib/http_uri.erl b/lib/inets/src/http_lib/http_uri.erl
index bc588fd390..6805b0293d 100644
--- a/lib/inets/src/http_lib/http_uri.erl
+++ b/lib/inets/src/http_lib/http_uri.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/http_server/httpd.erl b/lib/inets/src/http_server/httpd.erl
index 1eaa1c930a..f4b53ce129 100644
--- a/lib/inets/src/http_server/httpd.erl
+++ b/lib/inets/src/http_server/httpd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/http_server/httpd_esi.erl b/lib/inets/src/http_server/httpd_esi.erl
index f5493f6fad..3b66b86348 100644
--- a/lib/inets/src/http_server/httpd_esi.erl
+++ b/lib/inets/src/http_server/httpd_esi.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/http_server/httpd_example.erl b/lib/inets/src/http_server/httpd_example.erl
index 47a8c48d01..52f5fa03a9 100644
--- a/lib/inets/src/http_server/httpd_example.erl
+++ b/lib/inets/src/http_server/httpd_example.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/http_server/httpd_file.erl b/lib/inets/src/http_server/httpd_file.erl
index 4d419172d0..fb71834e95 100644
--- a/lib/inets/src/http_server/httpd_file.erl
+++ b/lib/inets/src/http_server/httpd_file.erl
@@ -33,6 +33,9 @@ handle_error(enoent, Op, ModData, Path) ->
handle_error(enotdir, Op, ModData, Path) ->
handle_error(404, Op, ModData, Path,
": A component of the file name is not a directory");
+handle_error(eisdir, Op, ModData, Path) ->
+ handle_error(403, Op, ModData, Path,
+ ":Ilegal operation expected a file not a directory");
handle_error(emfile, Op, _ModData, Path) ->
handle_error(500, Op, none, Path, ": Too many open files");
handle_error({enfile,_}, Op, _ModData, Path) ->
diff --git a/lib/inets/src/http_server/httpd_request.erl b/lib/inets/src/http_server/httpd_request.erl
index 007d272323..9d7538a13d 100644
--- a/lib/inets/src/http_server/httpd_request.erl
+++ b/lib/inets/src/http_server/httpd_request.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -259,17 +259,17 @@ parse_headers(<<?LF, Octet, Rest/binary>>, Header, Headers, Current, Max,
%% If ?CR is is missing RFC2616 section-19.3
parse_headers(<<?CR,?LF, Octet, Rest/binary>>, Header, Headers, Current, Max,
Options, Result);
-parse_headers(<<?CR,?LF, Octet, Rest/binary>>, Header, Headers, _, Max,
+parse_headers(<<?CR,?LF, Octet, Rest/binary>>, Header, Headers, Current, Max,
Options, Result) ->
case http_request:key_value(lists:reverse(Header)) of
undefined -> %% Skip headers with missing :
parse_headers(Rest, [Octet], Headers,
- 0, Max, Options, Result);
+ Current, Max, Options, Result);
NewHeader ->
case check_header(NewHeader, Options) of
ok ->
parse_headers(Rest, [Octet], [NewHeader | Headers],
- 0, Max, Options, Result);
+ Current, Max, Options, Result);
{error, Reason} ->
HttpVersion = lists:nth(3, lists:reverse(Result)),
{error, Reason, HttpVersion}
diff --git a/lib/inets/src/http_server/httpd_response.erl b/lib/inets/src/http_server/httpd_response.erl
index 57ce162922..bb946664f9 100644
--- a/lib/inets/src/http_server/httpd_response.erl
+++ b/lib/inets/src/http_server/httpd_response.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -61,8 +61,12 @@ generate_and_send_response(#mod{config_db = ConfigDB} = ModData) ->
{StatusCode, Response} -> %% Old way
send_response_old(ModData, StatusCode, Response),
ok;
- undefined ->
- send_status(ModData, 500, none),
+ undefined ->
+ %% Happens when no mod_*
+ %% handles the request
+ send_status(ModData, 501, {ModData#mod.method,
+ ModData#mod.request_uri,
+ ModData#mod.http_version}),
ok
end
end
diff --git a/lib/inets/src/http_server/httpd_script_env.erl b/lib/inets/src/http_server/httpd_script_env.erl
index d7c92c59ef..055edca211 100644
--- a/lib/inets/src/http_server/httpd_script_env.erl
+++ b/lib/inets/src/http_server/httpd_script_env.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/http_server/mod_alias.erl b/lib/inets/src/http_server/mod_alias.erl
index 8f0b92710e..68a3de0229 100644
--- a/lib/inets/src/http_server/mod_alias.erl
+++ b/lib/inets/src/http_server/mod_alias.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/http_server/mod_disk_log.erl b/lib/inets/src/http_server/mod_disk_log.erl
index 2023546f01..190cf91416 100644
--- a/lib/inets/src/http_server/mod_disk_log.erl
+++ b/lib/inets/src/http_server/mod_disk_log.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/http_server/mod_esi.erl b/lib/inets/src/http_server/mod_esi.erl
index 3206d957d9..21aafa7f7b 100644
--- a/lib/inets/src/http_server/mod_esi.erl
+++ b/lib/inets/src/http_server/mod_esi.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -561,7 +561,7 @@ eval(#mod{method = Method} = ModData, ESIBody, Modules)
end.
generate_webpage(ESIBody) ->
- (catch lib:eval_str(string:concat(ESIBody,". "))).
+ (catch erl_eval:eval_str(string:concat(ESIBody,". "))).
is_authorized(_ESIBody, [all]) ->
true;
diff --git a/lib/inets/src/http_server/mod_log.erl b/lib/inets/src/http_server/mod_log.erl
index ec570504be..0323918578 100644
--- a/lib/inets/src/http_server/mod_log.erl
+++ b/lib/inets/src/http_server/mod_log.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/inets_app/Makefile b/lib/inets/src/inets_app/Makefile
index fad2fefe2f..ec1ae70305 100644
--- a/lib/inets/src/inets_app/Makefile
+++ b/lib/inets/src/inets_app/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2005-2016. All Rights Reserved.
+# Copyright Ericsson AB 2005-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/inets_app/inets.app.src b/lib/inets/src/inets_app/inets.app.src
index 5b34018def..e5780b2a4c 100644
--- a/lib/inets/src/inets_app/inets.app.src
+++ b/lib/inets/src/inets_app/inets.app.src
@@ -1,7 +1,7 @@
%% This is an -*- erlang -*- file.
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index a86413147c..0dcf66265e 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -1,7 +1,7 @@
%% -*- erlang -*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/inets_app/inets.erl b/lib/inets/src/inets_app/inets.erl
index 450adf1a02..ab2bc5b784 100644
--- a/lib/inets/src/inets_app/inets.erl
+++ b/lib/inets/src/inets_app/inets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/inets_app/inets_internal.hrl b/lib/inets/src/inets_app/inets_internal.hrl
index e0f59bba5f..38b7e68638 100644
--- a/lib/inets/src/inets_app/inets_internal.hrl
+++ b/lib/inets/src/inets_app/inets_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/src/inets_app/inets_sup.erl b/lib/inets/src/inets_app/inets_sup.erl
index 22c928f9f9..0d3c7475fc 100644
--- a/lib/inets/src/inets_app/inets_sup.erl
+++ b/lib/inets/src/inets_app/inets_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/test/Makefile b/lib/inets/test/Makefile
index 0e33b72095..6ab9771a8f 100644
--- a/lib/inets/test/Makefile
+++ b/lib/inets/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/inets/test/http_format_SUITE.erl b/lib/inets/test/http_format_SUITE.erl
index 647eff4f7c..0a5aed67d5 100644
--- a/lib/inets/test/http_format_SUITE.erl
+++ b/lib/inets/test/http_format_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -435,7 +435,7 @@ http_request(Config) when is_list(Config) ->
[<<>>, Length1], HttpBody1)).
%%-------------------------------------------------------------------------
validate_request_line() ->
- [{doc, "Test httpd_request:validate/3. Makes sure you can not get past"
+ [{doc, "Test httpd_request:validate/3. Makes sure you cannot get past"
" the server_root and that the request is recognized by the server"
" and protcol version."}].
validate_request_line(Config) when is_list(Config) ->
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 84d07bc97f..6e048a4d56 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -59,7 +59,8 @@ all() ->
{group, http_unix_socket},
{group, https},
{group, sim_https},
- {group, misc}
+ {group, misc},
+ {group, sim_mixed} % HTTP and HTTPS sim servers
].
groups() ->
@@ -74,7 +75,8 @@ groups() ->
{http_unix_socket, [], simulated_unix_socket()},
{https, [], real_requests()},
{sim_https, [], only_simulated()},
- {misc, [], misc()}
+ {misc, [], misc()},
+ {sim_mixed, [], sim_mixed()}
].
real_requests()->
@@ -170,6 +172,12 @@ misc() ->
wait_for_whole_response
].
+sim_mixed() ->
+ [
+ redirect_http_to_https,
+ redirect_relative_different_port
+ ].
+
%%--------------------------------------------------------------------
init_per_suite(Config) ->
@@ -195,7 +203,8 @@ init_per_group(misc = Group, Config) ->
Config;
-init_per_group(Group, Config0) when Group =:= sim_https; Group =:= https->
+init_per_group(Group, Config0) when Group =:= sim_https; Group =:= https;
+ Group =:= sim_mixed ->
catch crypto:stop(),
try crypto:start() of
ok ->
@@ -238,6 +247,13 @@ end_per_group(http_unix_socket,_Config) ->
end_per_group(_, _Config) ->
ok.
+do_init_per_group(Group=sim_mixed, Config0) ->
+ % The mixed group uses two server ports (http and https), so we use
+ % different config names here.
+ Config1 = init_ssl(Config0),
+ Config2 = proplists:delete(http_port, proplists:delete(https_port, Config1)),
+ {HttpPort, HttpsPort} = server_start(Group, server_config(sim_https, Config2)),
+ [{http_port, HttpPort} | [{https_port, HttpsPort} | Config2]];
do_init_per_group(Group, Config0) ->
Config1 =
case Group of
@@ -734,6 +750,48 @@ redirect_loop(Config) when is_list(Config) ->
= httpc:request(get, {URL, []}, [], []).
%%-------------------------------------------------------------------------
+redirect_http_to_https() ->
+ [{doc, "Test that a 30X redirect from one scheme to another is handled "
+ "correctly."}].
+redirect_http_to_https(Config) when is_list(Config) ->
+ URL301 = mixed_url(http, "/301_custom_url.html", Config),
+ TargetUrl = mixed_url(https, "/dummy.html", Config),
+ Headers = [{"x-test-301-url", TargetUrl}],
+
+ {ok, {{_,200,_}, [_ | _], [_|_]}}
+ = httpc:request(get, {URL301, Headers}, [], []),
+
+ {ok, {{_,200,_}, [_ | _], []}}
+ = httpc:request(head, {URL301, Headers}, [], []),
+
+ {ok, {{_,200,_}, [_ | _], [_|_]}}
+ = httpc:request(post, {URL301, Headers, "text/plain", "foobar"},
+ [], []).
+%%-------------------------------------------------------------------------
+redirect_relative_different_port() ->
+ [{doc, "Test that a 30X redirect with a relative target, but different "
+ "port, is handled correctly."}].
+redirect_relative_different_port(Config) when is_list(Config) ->
+ URL301 = mixed_url(http, "/301_custom_url.html", Config),
+
+ % We need an extra server of the same protocol here, so spawn a new
+ % HTTP-protocol one
+ Port = server_start(sim_http, []),
+ {ok, Host} = inet:gethostname(),
+ % Prefix the URI with '/' instead of a scheme
+ TargetUrl = "//" ++ Host ++ ":" ++ integer_to_list(Port) ++ "/dummy.html",
+ Headers = [{"x-test-301-url", TargetUrl}],
+
+ {ok, {{_,200,_}, [_ | _], [_|_]}}
+ = httpc:request(get, {URL301, Headers}, [], []),
+
+ {ok, {{_,200,_}, [_ | _], []}}
+ = httpc:request(head, {URL301, Headers}, [], []),
+
+ {ok, {{_,200,_}, [_ | _], [_|_]}}
+ = httpc:request(post, {URL301, Headers, "text/plain", "foobar"},
+ [], []).
+%%-------------------------------------------------------------------------
cookie() ->
[{doc, "Test cookies."}].
cookie(Config) when is_list(Config) ->
@@ -1559,6 +1617,21 @@ url(sim_http, UserInfo, End, Config) ->
url(sim_https, UserInfo, End, Config) ->
url(https, UserInfo, End, Config).
+% Only for use in the `mixed` test group, where both http and https
+% URLs are possible.
+mixed_url(http, End, Config) ->
+ mixed_url(http_port, End, Config);
+mixed_url(https, End, Config) ->
+ mixed_url(https_port, End, Config);
+mixed_url(PortType, End, Config) ->
+ Port = proplists:get_value(PortType, Config),
+ {ok, Host} = inet:gethostname(),
+ Start = case PortType of
+ http_port -> ?URL_START;
+ https_port -> ?TLS_URL_START
+ end,
+ Start ++ Host ++ ":" ++ integer_to_list(Port) ++ End.
+
group_name(Config) ->
GroupProp = proplists:get_value(tc_group_properties, Config),
proplists:get_value(name, GroupProp).
@@ -1587,6 +1660,9 @@ server_start(http_ipv6, HttpdConfig) ->
Serv = inets:services_info(),
{value, {_, _, Info}} = lists:keysearch(Pid, 2, Serv),
proplists:get_value(port, Info);
+server_start(sim_mixed, Config) ->
+ % For the mixed http/https case, we start two servers and return both ports.
+ {server_start(sim_http, []), server_start(sim_https, Config)};
server_start(_, HttpdConfig) ->
{ok, Pid} = inets:start(httpd, HttpdConfig),
Serv = inets:services_info(),
@@ -1645,6 +1721,8 @@ start_apps(https) ->
inets_test_lib:start_apps([crypto, public_key, ssl]);
start_apps(sim_https) ->
inets_test_lib:start_apps([crypto, public_key, ssl]);
+start_apps(sim_mixed) ->
+ inets_test_lib:start_apps([crypto, public_key, ssl]);
start_apps(_) ->
ok.
@@ -2089,6 +2167,20 @@ handle_uri(_,"/301_rel_uri.html",_,_,_,_) ->
"Content-Length:" ++ integer_to_list(length(Body))
++ "\r\n\r\n" ++ Body;
+handle_uri("HEAD","/301_custom_url.html",_,Headers,_,_) ->
+ NewUri = proplists:get_value("x-test-301-url", Headers),
+ "HTTP/1.1 301 Moved Permanently\r\n" ++
+ "Location:" ++ NewUri ++ "\r\n" ++
+ "Content-Length:0\r\n\r\n";
+
+handle_uri(_,"/301_custom_url.html",_,Headers,_,_) ->
+ NewUri = proplists:get_value("x-test-301-url", Headers),
+ Body = "<HTML><BODY><a href=" ++ NewUri ++
+ ">New place</a></BODY></HTML>",
+ "HTTP/1.1 301 Moved Permanently\r\n" ++
+ "Location:" ++ NewUri ++ "\r\n" ++
+ "Content-Length:" ++ integer_to_list(length(Body))
+ ++ "\r\n\r\n" ++ Body;
handle_uri("HEAD","/302.html",Port,_,Socket,_) ->
NewUri = url_start(Socket) ++
diff --git a/lib/inets/test/httpc_proxy_SUITE.erl b/lib/inets/test/httpc_proxy_SUITE.erl
index 198b245399..3ee7981660 100644
--- a/lib/inets/test/httpc_proxy_SUITE.erl
+++ b/lib/inets/test/httpc_proxy_SUITE.erl
@@ -534,7 +534,7 @@ init_local_proxy(Config) ->
ct:fail({local_proxy_start_failed,Error})
end;
_ ->
- {skip,"Platform can not run local proxy start script"}
+ {skip,"Platform cannot run local proxy start script"}
end.
init_local_proxy_string(String, Config) ->
diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl
index 251547dcb0..c5751e79a6 100644
--- a/lib/inets/test/httpd_SUITE.erl
+++ b/lib/inets/test/httpd_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -76,6 +76,8 @@ all() ->
{group, http_logging},
{group, http_post},
{group, http_rel_path_script_alias},
+ {group, http_not_sup},
+ {group, https_not_sup},
mime_types_format
].
@@ -103,6 +105,8 @@ groups() ->
{http_reload, [], [{group, reload}]},
{https_reload, [], [{group, reload}]},
{http_post, [], [{group, post}]},
+ {http_not_sup, [], [{group, not_sup}]},
+ {https_not_sup, [], [{group, not_sup}]},
{http_mime_types, [], [alias_1_1, alias_1_0, alias_0_9]},
{limit, [], [max_clients_1_1, max_clients_1_0, max_clients_0_9]},
{custom, [], [customize, add_default]},
@@ -134,7 +138,8 @@ groups() ->
esi_put, esi_post] ++ http_head() ++ http_get() ++ load()},
{http_1_0, [], [host, cgi, trace] ++ http_head() ++ http_get() ++ load()},
{http_0_9, [], http_head() ++ http_get() ++ load()},
- {http_rel_path_script_alias, [], [cgi]}
+ {http_rel_path_script_alias, [], [cgi]},
+ {not_sup, [], [put_not_sup]}
].
basic_groups ()->
@@ -207,7 +212,8 @@ init_per_group(Group, Config0) when Group == https_basic;
Group == https_auth_api_dets;
Group == https_auth_api_mnesia;
Group == https_security;
- Group == https_reload
+ Group == https_reload;
+ Group == https_not_sup
->
catch crypto:stop(),
try crypto:start() of
@@ -226,6 +232,7 @@ init_per_group(Group, Config0) when Group == http_basic;
Group == http_auth_api_mnesia;
Group == http_security;
Group == http_reload;
+ Group == http_not_sup;
Group == http_post;
Group == http_mime_types
->
@@ -275,6 +282,8 @@ init_per_group(http_logging, Config) ->
init_per_group(http_rel_path_script_alias = Group, Config) ->
ok = start_apps(Group),
init_httpd(Group, [{type, ip_comm},{http_version, "HTTP/1.1"}| Config]);
+init_per_group(not_sup, Config) ->
+ [{http_version, "HTTP/1.1"} | Config];
init_per_group(_, Config) ->
Config.
@@ -448,8 +457,19 @@ get(Config) when is_list(Config) ->
{header, "Content-Type", "text/html"},
{header, "Date"},
{header, "Server"},
+ {version, Version}]),
+
+ ok = httpd_test_lib:verify_request(proplists:get_value(type, Config), Host,
+ proplists:get_value(port, Config),
+ transport_opts(Type, Config),
+ proplists:get_value(node, Config),
+ http_request("GET /open/ ", Version, Host),
+ [{statuscode, 403},
+ {header, "Content-Type", "text/html"},
+ {header, "Date"},
+ {header, "Server"},
{version, Version}]).
-
+
basic_auth_1_1(Config) when is_list(Config) ->
basic_auth([{http_version, "HTTP/1.1"} | Config]).
@@ -898,6 +918,33 @@ max_clients_0_9() ->
max_clients_0_9(Config) when is_list(Config) ->
do_max_clients([{http_version, "HTTP/0.9"} | Config]).
+
+
+%%-------------------------------------------------------------------------
+put_not_sup() ->
+ [{doc, "Test unhandled request"}].
+
+put_not_sup(Config) when is_list(Config) ->
+ ok = http_status("PUT /index.html ",
+ {"Content-Length:100 \r\n",
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"},
+ Config, [{statuscode, 501}]).
%%-------------------------------------------------------------------------
esi() ->
[{doc, "Test mod_esi"}].
@@ -1793,7 +1840,8 @@ start_apps(Group) when Group == https_basic;
Group == https_auth_api_mnesia;
Group == https_htaccess;
Group == https_security;
- Group == https_reload
+ Group == https_reload;
+ Group == https_not_sup
->
inets_test_lib:start_apps([inets, asn1, crypto, public_key, ssl]);
start_apps(Group) when Group == http_basic;
@@ -1809,7 +1857,9 @@ start_apps(Group) when Group == http_basic;
Group == http_reload;
Group == http_post;
Group == http_mime_types;
- Group == http_rel_path_script_alias ->
+ Group == http_rel_path_script_alias;
+ Group == http_not_sup;
+ Group == http_mime_types->
inets_test_lib:start_apps([inets]).
server_start(_, HttpdConfig) ->
@@ -1844,6 +1894,10 @@ server_config(http_basic, Config) ->
basic_conf() ++ server_config(http, Config);
server_config(https_basic, Config) ->
basic_conf() ++ server_config(https, Config);
+server_config(http_not_sup, Config) ->
+ not_sup_conf() ++ server_config(http, Config);
+server_config(https_not_sup, Config) ->
+ not_sup_conf() ++ server_config(https, Config);
server_config(http_reload, Config) ->
[{keep_alive_timeout, 2}] ++ server_config(http, Config);
server_config(http_post, Config) ->
@@ -1992,7 +2046,9 @@ head_status(_) ->
basic_conf() ->
[{modules, [mod_alias, mod_range, mod_responsecontrol,
- mod_trace, mod_esi, mod_cgi, mod_dir, mod_get, mod_head]}].
+ mod_trace, mod_esi, mod_cgi, mod_get, mod_head]}].
+not_sup_conf() ->
+ [{modules, [mod_get]}].
auth_access_conf() ->
[{modules, [mod_alias, mod_htaccess, mod_dir, mod_get, mod_head]},
diff --git a/lib/inets/test/httpd_bench_SUITE.erl b/lib/inets/test/httpd_bench_SUITE.erl
index 9d8cbf9ae2..4b549dcb5b 100644
--- a/lib/inets/test/httpd_bench_SUITE.erl
+++ b/lib/inets/test/httpd_bench_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/test/httpd_mod.erl b/lib/inets/test/httpd_mod.erl
index 2035b50248..6e3635001a 100644
--- a/lib/inets/test/httpd_mod.erl
+++ b/lib/inets/test/httpd_mod.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/test/inets_SUITE.erl b/lib/inets/test/inets_SUITE.erl
index 07ce594a1d..e7964ff7f1 100644
--- a/lib/inets/test/inets_SUITE.erl
+++ b/lib/inets/test/inets_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/test/inets_socketwrap_SUITE.erl b/lib/inets/test/inets_socketwrap_SUITE.erl
index fc87c595a9..b88cff4e90 100644
--- a/lib/inets/test/inets_socketwrap_SUITE.erl
+++ b/lib/inets/test/inets_socketwrap_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/test/inets_sup_SUITE.erl b/lib/inets/test/inets_sup_SUITE.erl
index 727e91e987..b90d55dadf 100644
--- a/lib/inets/test/inets_sup_SUITE.erl
+++ b/lib/inets/test/inets_sup_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl
index d1f238ba0e..1cc4e11e45 100644
--- a/lib/inets/test/inets_test_lib.erl
+++ b/lib/inets/test/inets_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/test/uri_SUITE.erl b/lib/inets/test/uri_SUITE.erl
index 8e00e6f565..db6a8bdfc3 100644
--- a/lib/inets/test/uri_SUITE.erl
+++ b/lib/inets/test/uri_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index 3a489357ff..b76390ad66 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2001-2017. All Rights Reserved.
+# Copyright Ericsson AB 2001-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 6.5.1
+INETS_VSN = 7.0
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
diff --git a/lib/jinterface/doc/src/Makefile b/lib/jinterface/doc/src/Makefile
index 37de0a35c5..6f1ecc8dea 100644
--- a/lib/jinterface/doc/src/Makefile
+++ b/lib/jinterface/doc/src/Makefile
@@ -129,6 +129,7 @@ html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/jinterface/doc/src/notes.xml b/lib/jinterface/doc/src/notes.xml
index 346d467c2d..640712ad98 100644
--- a/lib/jinterface/doc/src/notes.xml
+++ b/lib/jinterface/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2000</year><year>2017</year>
+ <year>2000</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,21 @@
</header>
<p>This document describes the changes made to the Jinterface application.</p>
+<section><title>Jinterface 1.9</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Add module package name for Java 9</p>
+ <p>
+ Own Id: OTP-14844</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Jinterface 1.8.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -690,7 +705,7 @@
<item>
<p><c>OtpMbox.receive()</c> and <c>OtpMbox.receive(long timeout)</c> can now throw
<c>OtpErlangDecodeException</c> if the received message
- can not be decoded. <c>null</c> is now only returned from
+ cannot be decoded. <c>null</c> is now only returned from
<c>OtpMbox.receive(long timeout)</c> if a timeout occurs.
<c>OtpMbox.receive()</c> will never return <c>null</c>.</p>
<p>*** POTENTIAL INCOMPATIBILITY ***</p>
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile b/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile
index 001acfdd2e..ee616f3d7e 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2000-2016. All Rights Reserved.
+# Copyright Ericsson AB 2000-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java
index 363fdb950a..fffb8475d3 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java
@@ -102,7 +102,7 @@ public class OtpEpmd {
/**
* Set the port number to be used to contact the epmd process. Only needed
* when the default port is not desired and system environment variable
- * ERL_EPMD_PORT can not be read (applet).
+ * ERL_EPMD_PORT cannot be read (applet).
*/
public static void useEpmdPort(final int port) {
EpmdPort.set(port);
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java
index ded8f6e1e5..6d81ce630b 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java
@@ -601,7 +601,7 @@ public class OtpInputStream extends ByteArrayInputStream {
* @return the integer value.
*
* @exception OtpErlangDecodeException
- * if the next term in the stream can not be represented as a
+ * if the next term in the stream cannot be represented as a
* positive integer.
*/
public int read_uint() throws OtpErlangDecodeException {
@@ -622,7 +622,7 @@ public class OtpInputStream extends ByteArrayInputStream {
* @return the integer value.
*
* @exception OtpErlangDecodeException
- * if the next term in the stream can not be represented as
+ * if the next term in the stream cannot be represented as
* an integer.
*/
public int read_int() throws OtpErlangDecodeException {
@@ -643,7 +643,7 @@ public class OtpInputStream extends ByteArrayInputStream {
* @return the short value.
*
* @exception OtpErlangDecodeException
- * if the next term in the stream can not be represented as a
+ * if the next term in the stream cannot be represented as a
* positive short.
*/
public short read_ushort() throws OtpErlangDecodeException {
@@ -664,7 +664,7 @@ public class OtpInputStream extends ByteArrayInputStream {
* @return the short value.
*
* @exception OtpErlangDecodeException
- * if the next term in the stream can not be represented as a
+ * if the next term in the stream cannot be represented as a
* short.
*/
public short read_short() throws OtpErlangDecodeException {
@@ -685,7 +685,7 @@ public class OtpInputStream extends ByteArrayInputStream {
* @return the long value.
*
* @exception OtpErlangDecodeException
- * if the next term in the stream can not be represented as a
+ * if the next term in the stream cannot be represented as a
* positive long.
*/
public long read_ulong() throws OtpErlangDecodeException {
@@ -698,7 +698,7 @@ public class OtpInputStream extends ByteArrayInputStream {
* @return the long value.
*
* @exception OtpErlangDecodeException
- * if the next term in the stream can not be represented as a
+ * if the next term in the stream cannot be represented as a
* long.
*/
public long read_long() throws OtpErlangDecodeException {
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java
index 42e178c3f6..29a8bc1540 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java
@@ -156,7 +156,7 @@ public class OtpMbox {
* of the next message waiting in this mailbox.
*
* @exception OtpErlangDecodeException
- * if the message can not be decoded.
+ * if the message cannot be decoded.
*
* @exception OtpErlangExit
* if a linked {@link OtpErlangPid pid} has exited or has
@@ -184,7 +184,7 @@ public class OtpMbox {
* of the next message waiting in this mailbox.
*
* @exception OtpErlangDecodeException
- * if the message can not be decoded.
+ * if the message cannot be decoded.
*
* @exception OtpErlangExit
* if a linked {@link OtpErlangPid pid} has exited or has
diff --git a/lib/jinterface/test/jinterface_SUITE.erl b/lib/jinterface/test/jinterface_SUITE.erl
index 8c6a6368a9..468981a557 100644
--- a/lib/jinterface/test/jinterface_SUITE.erl
+++ b/lib/jinterface/test/jinterface_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/jinterface/test/nc_SUITE.erl b/lib/jinterface/test/nc_SUITE.erl
index daa17195ee..4f225a396e 100644
--- a/lib/jinterface/test/nc_SUITE.erl
+++ b/lib/jinterface/test/nc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/jinterface/vsn.mk b/lib/jinterface/vsn.mk
index 0a8a1190ec..f527a83092 100644
--- a/lib/jinterface/vsn.mk
+++ b/lib/jinterface/vsn.mk
@@ -1 +1 @@
-JINTERFACE_VSN = 1.8.1
+JINTERFACE_VSN = 1.9
diff --git a/lib/kernel/doc/src/.gitignore b/lib/kernel/doc/src/.gitignore
new file mode 100644
index 0000000000..c2813ac866
--- /dev/null
+++ b/lib/kernel/doc/src/.gitignore
@@ -0,0 +1 @@
+*.eps \ No newline at end of file
diff --git a/lib/kernel/doc/src/Makefile b/lib/kernel/doc/src/Makefile
index 82869d7b15..f8867ccf25 100644
--- a/lib/kernel/doc/src/Makefile
+++ b/lib/kernel/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -42,6 +42,7 @@ XML_REF3_FILES = application.xml \
disk_log.xml \
erl_boot_server.xml \
erl_ddll.xml \
+ erl_epmd.xml \
erl_prim_loader_stub.xml \
erlang_stub.xml \
error_handler.xml \
@@ -83,6 +84,7 @@ XML_CHAPTER_FILES = \
BOOK_FILES = book.xml
+# The .png file is generated from a .dia file with target 'update_png'
IMAGE_FILES = \
logger_arch.png
@@ -111,6 +113,17 @@ SPECS_FILES = $(XML_REF3_FILES:%.xml=$(SPECDIR)/specs_%.xml)
TOP_SPECS_FILE = specs.xml
# ----------------------------------------------------
+# FIGURES
+# ----------------------------------------------------
+# In order to update the figures you have to have both dia
+# and imagemagick installed.
+# The generated .png file must be committed.
+
+update_png:
+ dia --export=logger_arch.eps logger_arch.dia
+ convert logger_arch.eps -resize 65% logger_arch.png
+
+# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
XML_FLAGS +=
@@ -141,12 +154,13 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(MAN4DIR)/*
rm -f $(MAN6DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f $(SPECDIR)/*
- rm -f errs core *~
+ rm -f errs core *~ *.eps
$(SPECDIR)/specs_erl_prim_loader_stub.xml:
$(gen_verbose)escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \
diff --git a/lib/kernel/doc/src/application.xml b/lib/kernel/doc/src/application.xml
index 886286b76d..38c7b5acf1 100644
--- a/lib/kernel/doc/src/application.xml
+++ b/lib/kernel/doc/src/application.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -318,8 +318,13 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
<c>{error,{not_started,App}}</c> is returned, where <c>App</c>
is the name of the missing application.</p>
<p>The application controller then creates an <em>application master</em>
- for the application. The application master is
- the group leader of all the processes in the application.
+ for the application. The application master becomes the
+ group leader of all the processes in the application. I/O is
+ forwarded to the previous group leader, though, this is just
+ a way to identify processes that belong to the application.
+ Used for example to find itself from any process, or,
+ reciprocally, to kill them all when it terminates.</p>
+ <p>
The application master starts the application by calling
the application callback function <c>Module:start/2</c> as
defined by the application specification key <c>mod</c>.</p>
@@ -608,4 +613,3 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
<seealso marker="app">app(4)</seealso></p>
</section>
</erlref>
-
diff --git a/lib/kernel/doc/src/book.xml b/lib/kernel/doc/src/book.xml
index 0b69b547e7..4b3573b9fe 100644
--- a/lib/kernel/doc/src/book.xml
+++ b/lib/kernel/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>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml
index bd95819636..69ce4da61c 100644
--- a/lib/kernel/doc/src/code.xml
+++ b/lib/kernel/doc/src/code.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -538,7 +538,7 @@ zip:create("mnesia-4.4.7.ez",
</item>
<tag><c>not_purged</c></tag>
<item>
- <p>The object code can not be loaded because an old version
+ <p>The object code cannot be loaded because an old version
of the code already exists.</p>
</item>
<tag><c>sticky_directory</c></tag>
@@ -611,7 +611,7 @@ ok = code:finish_loading(Prepared),
<taglist>
<tag><c>not_purged</c></tag>
<item>
- <p>The object code can not be loaded because an old version
+ <p>The object code cannot be loaded because an old version
of the code already exists.</p>
</item>
<tag><c>sticky_directory</c></tag>
diff --git a/lib/kernel/doc/src/config.xml b/lib/kernel/doc/src/config.xml
index fdb2d29f63..714af93f4d 100644
--- a/lib/kernel/doc/src/config.xml
+++ b/lib/kernel/doc/src/config.xml
@@ -4,7 +4,7 @@
<fileref>
<header>
<copyright>
- <year>1997</year><year>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -37,10 +37,10 @@
data in the system configuration file <c>Name.config</c>.</p>
<p>Configuration parameter values in the configuration file
override the values in the application resource files (see
- <seealso marker="app"><c>app(4)</c></seealso>.
+ <seealso marker="app"><c>app(4)</c></seealso>).
The values in the configuration file can be
overridden by command-line flags (see
- <seealso marker="erts:erl"><c>erts:erl(1)</c></seealso>.</p>
+ <seealso marker="erts:erl"><c>erts:erl(1)</c></seealso>).</p>
<p>The value of a configuration parameter is retrieved by calling
<c>application:get_env/1,2</c>.</p>
</description>
@@ -86,8 +86,13 @@
<tag><c>File = string()</c></tag>
<item>Name of another <c>.config</c> file.
Extension <c>.config</c> can be omitted. It is
- recommended to use absolute paths. A relative path is
- relative the current working directory of the emulator.</item>
+ recommended to use absolute paths. If a relative path is used,
+ <c>File</c> is searched, first, relative from <c>sys.config</c> directory, then relative
+ to the current working directory of the emulator, for backward compatibility.
+ This allow to use a <c>sys.config</c> pointing out other <c>.config</c> files in a release
+ or in a node started manually using <c>-config ...</c> with same result whatever
+ the current working directory.
+ </item>
</taglist>
<p>When traversing the contents of <c>sys.config</c> and a filename
is encountered, its contents are read and merged with the result
diff --git a/lib/kernel/doc/src/erl_epmd.xml b/lib/kernel/doc/src/erl_epmd.xml
new file mode 100644
index 0000000000..8b076cd2d7
--- /dev/null
+++ b/lib/kernel/doc/src/erl_epmd.xml
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2018</year><year>2018</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_epmd</title>
+ <prepared>Timmo Verlaan</prepared>
+ <docno>1</docno>
+ <date>2018-02-19</date>
+ <rev>A</rev>
+ </header>
+ <module>erl_epmd</module>
+ <modulesummary>
+ Erlang interface towards epmd
+ </modulesummary>
+ <description>
+ <p>This module communicates with the EPMD daemon, see <seealso
+ marker="erts:epmd">epmd</seealso>. To implement your own epmd module please
+ see <seealso marker="erts:alt_disco">ERTS User's Guide: How to Implement an
+ Alternative Service Discovery for Erlang Distribution</seealso></p>
+ </description>
+
+ <funcs>
+ <func>
+ <name name="start_link" arity="0"/>
+ <fsummary>Callback for erl_distribution supervisor.</fsummary>
+ <desc>
+ <p>This function is invoked as this module is added as a child of the
+ <c>erl_distribution</c> supervisor.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="register_node" arity="2"/>
+ <name name="register_node" arity="3"/>
+ <fsummary>Registers the node with <c>epmd</c>.</fsummary>
+ <desc>
+ <p>Registers the node with <c>epmd</c> and tells epmd what port will be
+ used for the current node. It returns a creation number. This number is
+ incremented on each register to help with identifying if a node is
+ reconnecting to epmd.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="port_please" arity="2"/>
+ <name name="port_please" arity="3"/>
+ <fsummary>Returns the port number for a given node.</fsummary>
+ <desc>
+ <p>Requests the distribution port for the given node of an EPMD
+ instance. Together with the port it returns a distribution protocol
+ version which has been 5 since Erlang/OTP R6.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="address_please" arity="3"/>
+ <fsummary>Returns address and port.</fsummary>
+ <desc>
+ <p>Called by the distribution module. Resolves the <c>Host</c> to an IP
+ address.</p>
+ <p>Another epmd module may return port and distribution protocol version
+ as well.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="names" arity="1"/>
+ <fsummary>Names of Erlang nodes at a host.</fsummary>
+ <desc>
+ <p>Called by <seealso marker="net_adm"><c>net_adm:names/0</c></seealso>.
+ <c>Host</c> defaults to the localhost. Returns the names and associated
+ port numbers of the Erlang nodes that <c>epmd</c> registered at the
+ specified host. Returns <c>{error, address}</c> if <c>epmd</c> is not
+ operational.</p>
+ <p><em>Example:</em></p>
+ <pre>
+(arne@dunn)1> <input>erl_epmd:names(localhost).</input>
+{ok,[{"arne",40262}]}</pre>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/kernel/doc/src/error_logger.xml b/lib/kernel/doc/src/error_logger.xml
index cb6165c73e..c3d68fd79f 100644
--- a/lib/kernel/doc/src/error_logger.xml
+++ b/lib/kernel/doc/src/error_logger.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -33,44 +33,35 @@
<description>
<note>
- <p>In OTP-21, a new API for logging was added to Erlang/OTP. The
+ <p>In Erlang/OTP 21.0, a new API for logging was added. The
old <c>error_logger</c> module can still be used by legacy
- code, but new code should use the new API instead.</p>
+ code, but log events are redirected to the new Logger API. New
+ code should use the Logger API directly.</p>
+ <p><c>error_logger</c> is no longer started by default, but is
+ automatically started when an event handler is added
+ with <c>error_logger:add_report_handler/1,2</c>. The <c>error_logger</c>
+ module is then also added as a handler to the new logger.</p>
<p>See <seealso marker="logger"><c>logger(3)</c></seealso> and
the <seealso marker="logger_chapter">Logging</seealso> chapter
- in the user's guide for more information.</p>
+ in the User's Guide for more information.</p>
</note>
<p>The Erlang <em>error logger</em> is an event manager (see
<seealso marker="doc/design_principles:des_princ">OTP Design Principles</seealso> and
<seealso marker="stdlib:gen_event"><c>gen_event(3)</c></seealso>),
- registered as <c>error_logger</c>. Errors, warnings, and info events
- are sent to the error logger from the Erlang runtime system and
- the different Erlang/OTP applications. The events are, by default,
- logged to the terminal. Notice that an event from a process <c>P</c> is
- logged at the node of the group leader of <c>P</c>. This means
- that log output is directed to the node from which a process was
- created, which not necessarily is the same node as where it is
- executing.</p>
- <p>Initially, <c>error_logger</c> has only a primitive event
- handler, which buffers and prints the raw event messages. During
- system startup, the Kernel application replaces this with a
- <em>standard event handler</em>, by default one that writes
- nicely formatted output to the terminal. Kernel can also be
- configured so that events are logged to a file instead, or not logged at all,
- see <seealso marker="kernel_app"><c>kernel(6)</c></seealso>.</p>
- <p>Also the SASL application, if started, adds its own event
- handler, which by default writes supervisor, crash, and progress
- reports to the terminal. See
- <seealso marker="sasl:sasl_app"><c>sasl(6)</c></seealso>.</p>
- <p>It is recommended that user-defined applications report
- errors through the error logger to get uniform reports.
- User-defined event handlers can be added to handle application-specific
- events, see
- <seealso marker="#add_report_handler/1"><c>add_report_handler/1,2</c></seealso>.
- Also, a useful event handler is provided in STDLIB for multi-file
- logging of events, see
- <seealso marker="stdlib:log_mf_h"><c>log_mf_h(3)</c></seealso>.</p>
+ registered as <c>error_logger</c>.</p>
+ <p>Error logger is no longer started by default, but is
+ automatically started when an event handler is added
+ with <seealso marker="#add_report_handler/1">
+ <c>add_report_handler/1,2</c></seealso>. The <c>error_logger</c>
+ module is then also added as a handler to the new logger,
+ causing log events to be forwarded from logger to error logger,
+ and consequently to all installed error logger event
+ handlers.</p>
+ <p>User-defined event handlers can be added to handle application-specific
+ events.</p>
+ <p>Existing event handlers provided by STDLIB and SASL are still
+ available, but are no longer used by OTP.</p>
<p>Warning events were introduced in Erlang/OTP R9C and are enabled
by default as from Erlang/OTP 18.0. To retain backwards compatibility
with existing user-defined event handlers, the warning events can be
@@ -99,6 +90,9 @@
The function returns <c>ok</c> if successful.</p>
<p>The event handler must be able to handle the events in this module, see
section <seealso marker="#events">Events</seealso>.</p>
+ <p>The first time this function is called,
+ <c>error_logger</c> is added as a Logger handler, and
+ the <c>error_logger</c> process is started.</p>
</desc>
</func>
<func>
@@ -108,37 +102,40 @@
<p>Deletes an event handler from the error logger by calling
<c>gen_event:delete_handler(error_logger, <anno>Handler</anno>, [])</c>,
see <seealso marker="stdlib:gen_event"><c>gen_event(3)</c></seealso>.</p>
+ <p>If no more event handlers exist after the deletion,
+ <c>error_logger</c> is removed as a Logger handler, and
+ the <c>error_logger</c> process is stopped.</p>
</desc>
</func>
<func>
<name name="error_msg" arity="1"/>
<name name="error_msg" arity="2"/>
<name name="format" arity="2"/>
- <fsummary>Send a standard error event to the error logger.</fsummary>
+ <fsummary>Log a standard error event.</fsummary>
<desc>
- <p>Sends a standard error event to the error logger.
- The <c><anno>Format</anno></c> and <c><anno>Data</anno></c> arguments
- are the same as the arguments of
+ <p>Log a standard error event. The <c><anno>Format</anno></c>
+ and <c><anno>Data</anno></c> arguments are the same as the
+ arguments of
<seealso marker="stdlib:io#format/2"><c>io:format/2</c></seealso>
- in STDLIB.
- The event is handled by the standard event handler.</p>
+ in STDLIB.</p>
+ <p>Error logger forwards the event to Logger, including
+ metadata that allows backwards compatibility with legacy
+ error logger event handlers.</p>
+ <p>The event is handled by the default Logger handler.</p>
+ <p>These functions are kept for backwards compatibility and
+ must not be used by new code. Use the <seealso marker="logger#macros">
+ <c>?LOG_ERROR</c></seealso> macro or
+ <seealso marker="logger#error-1"><c>logger:error/1,2,3</c></seealso>
+ instead.</p>
<p><em>Example:</em></p>
<pre>
-1> <input>error_logger:error_msg("An error occurred in ~p~n", [a_module]).</input>
-
-=ERROR REPORT==== 11-Aug-2005::14:03:19 ===
+1> <input>error_logger:error_msg("An error occurred in ~p", [a_module]).</input>
+=ERROR REPORT==== 22-May-2018::11:18:43.376917 ===
An error occurred in a_module
ok</pre>
<warning>
- <p>If called with bad arguments, this function can crash
- the standard event handler, meaning no further events are
- logged. When in doubt, use
- <seealso marker="#error_report/1"><c>error_report/1</c></seealso>
- instead.</p>
- </warning>
- <warning>
<p>If the Unicode translation modifier (<c>t</c>) is used in
- the format string, all error handlers must ensure that the
+ the format string, all event handlers must ensure that the
formatted output is correctly encoded for the I/O
device.</p>
</warning>
@@ -146,79 +143,101 @@ ok</pre>
</func>
<func>
<name name="error_report" arity="1"/>
- <fsummary>Send a standard error report event to the error logger.</fsummary>
+ <fsummary>Log a standard error event.</fsummary>
<desc>
- <p>Sends a standard error report event to the error logger.
- The event is handled by the standard event handler.</p>
+ <p>Log a standard error event. Error logger forwards the event
+ to Logger, including metadata that allows backwards
+ compatibility with legacy error logger event handlers.</p>
+ <p>The event is handled by the default Logger handler.</p>
+ <p>This functions is kept for backwards compatibility and
+ must not be used by new code. Use the <seealso marker="logger#macros">
+ <c>?LOG_ERROR</c></seealso> macro or
+ <seealso marker="logger#error-1"><c>logger:error/1,2,3</c></seealso>
+ instead.</p>
<p><em>Example:</em></p>
<pre>
2> <input>error_logger:error_report([{tag1,data1},a_term,{tag2,data}]).</input>
-
-=ERROR REPORT==== 11-Aug-2005::13:45:41 ===
+=ERROR REPORT==== 22-May-2018::11:24:23.699306 ===
tag1: data1
a_term
tag2: data
ok
3> <input>error_logger:error_report("Serious error in my module").</input>
-
-=ERROR REPORT==== 11-Aug-2005::13:45:49 ===
+=ERROR REPORT==== 22-May-2018::11:24:45.972445 ===
Serious error in my module
ok</pre>
</desc>
</func>
<func>
<name name="error_report" arity="2"/>
- <fsummary>Send a user-defined error report event to the error logger.</fsummary>
+ <fsummary>Log a user-defined error event.</fsummary>
<desc>
- <p>Sends a user-defined error report event to the error logger.
- An event handler to handle the event is supposed to have been
- added. The event is ignored by the standard event handler.</p>
+ <p>Log a user-defined error event. Error logger forwards the
+ event to Logger, including metadata that allows backwards
+ compatibility with legacy error logger event handlers.</p>
+ <p>Error logger also adds a <c>domain</c> field with
+ value <c>[<anno>Type</anno>]</c> to this event's metadata,
+ causing the filters of the default Logger handler to discard
+ the event. A different Logger handler, or an error logger
+ event handler, must be added to handle this event.</p>
<p>It is recommended that <c><anno>Report</anno></c> follows the same
structure as for
<seealso marker="#error_report/1"><c>error_report/1</c></seealso>.</p>
+ <p>This functions is kept for backwards compatibility and
+ must not be used by new code. Use the <seealso marker="logger#macros">
+ <c>?LOG_ERROR</c></seealso> macro or
+ <seealso marker="logger#error-1"><c>logger:error/1,2,3</c></seealso>
+ instead.</p>
</desc>
</func>
<func>
<name name="get_format_depth" arity="0"/>
<fsummary>Get the value of the Kernel application variable
- <c>logger_format_depth</c>.</fsummary>
+ <c>error_logger_format_depth</c>.</fsummary>
<desc>
<p>Returns <c>max(10, Depth)</c>, where <c>Depth</c> is the
- value of
- <seealso marker="kernel_app#logger_format_depth">
- logger_format_depth</seealso>
+ value of <c>error_logger_format_depth</c>
in the Kernel application, if Depth is an integer. Otherwise,
<c>unlimited</c> is returned.</p>
- <p>For backwards compatibility, the value
- of <c>error_logger_format_depth</c> is used
- if <c>logger_format_depth</c> is not set.</p>
+ <note>
+ <p>The <c>error_logger_format_depth</c> variable
+ is <seealso marker="kernel_app#deprecated-configuration-parameters">
+ deprecated</seealso> since
+ the <seealso marker="logger">Logger API</seealso> was
+ introduced in Erlang/OTP 21.0. The variable, and this
+ function, are kept for backwards compatibility since they
+ still might be used by legacy report handlers.</p>
+ </note>
</desc>
</func>
<func>
<name name="info_msg" arity="1"/>
<name name="info_msg" arity="2"/>
- <fsummary>Send a standard information event to the error logger.</fsummary>
+ <fsummary>Log a standard information event.</fsummary>
<desc>
- <p>Sends a standard information event to the error logger.
- The <c><anno>Format</anno></c> and <c><anno>Data</anno></c> arguments
- are the same as the arguments of
+ <p>Log a standard information event. The <c><anno>Format</anno></c>
+ and <c><anno>Data</anno></c> arguments are the same as the
+ arguments of
<seealso marker="stdlib:io#format/2"><c>io:format/2</c></seealso>
- in STDLIB. The event is handled by the standard event handler.</p>
+ in STDLIB.</p>
+ <p>Error logger forwards the event to Logger, including
+ metadata that allows backwards compatibility with legacy
+ error logger event handlers.</p>
+ <p>The event is handled by the default Logger handler.</p>
+ <p>These functions are kept for backwards compatibility and
+ must not be used by new code. Use the <seealso marker="logger#macros">
+ <c>?LOG_INFO</c></seealso> macro or
+ <seealso marker="logger#info-1"><c>logger:info/1,2,3</c></seealso>
+ instead.</p>
<p><em>Example:</em></p>
<pre>
-1> <input>error_logger:info_msg("Something happened in ~p~n", [a_module]).</input>
-
-=INFO REPORT==== 11-Aug-2005::14:06:15 ===
+1> <input>error_logger:info_msg("Something happened in ~p", [a_module]).</input>
+=INFO REPORT==== 22-May-2018::12:03:32.612462 ===
Something happened in a_module
ok</pre>
<warning>
- <p>If called with bad arguments, this function can crash
- the standard event handler, meaning no further events are
- logged. When in doubt, use <c>info_report/1</c> instead.</p>
- </warning>
- <warning>
<p>If the Unicode translation modifier (<c>t</c>) is used in
- the format string, all error handlers must ensure that the
+ the format string, all event handlers must ensure that the
formatted output is correctly encoded for the I/O
device.</p>
</warning>
@@ -226,37 +245,52 @@ ok</pre>
</func>
<func>
<name name="info_report" arity="1"/>
- <fsummary>Send a standard information report event to the error logger.</fsummary>
+ <fsummary>Log a standard information event.</fsummary>
<desc>
- <p>Sends a standard information report event to the error
- logger. The event is handled by the standard event handler.</p>
+ <p>Log a standard information event. Error logger forwards the
+ event to Logger, including metadata that allows backwards
+ compatibility with legacy error logger event handlers.</p>
+ <p>The event is handled by the default Logger handler.</p>
+ <p>This functions is kept for backwards compatibility and
+ must not be used by new code. Use the <seealso marker="logger#macros">
+ <c>?LOG_INFO</c></seealso> macro or
+ <seealso marker="logger#info-1"><c>logger:info/1,2,3</c></seealso>
+ instead.</p>
<p><em>Example:</em></p>
<pre>
2> <input>error_logger:info_report([{tag1,data1},a_term,{tag2,data}]).</input>
-
-=INFO REPORT==== 11-Aug-2005::13:55:09 ===
+=INFO REPORT==== 22-May-2018::12:06:35.994440 ===
tag1: data1
a_term
tag2: data
ok
3> <input>error_logger:info_report("Something strange happened").</input>
-
-=INFO REPORT==== 11-Aug-2005::13:55:36 ===
+=INFO REPORT==== 22-May-2018::12:06:49.066872 ===
Something strange happened
ok</pre>
</desc>
</func>
<func>
<name name="info_report" arity="2"/>
- <fsummary>Send a user-defined information report event to the error logger.</fsummary>
+ <fsummary>Log a user-defined information event.</fsummary>
<desc>
- <p>Sends a user-defined information report event to the error
- logger. An event handler to handle the event is supposed to
- have been added. The event is ignored by the standard event
- handler.</p>
+ <p>Log a user-defined information event. Error logger forwards
+ the event to Logger, including metadata that allows
+ backwards compatibility with legacy error logger event
+ handlers.</p>
+ <p>Error logger also adds a <c>domain</c> field with
+ value <c>[<anno>Type</anno>]</c> to this event's metadata,
+ causing the filters of the default Logger handler to discard
+ the event. A different Logger handler, or an error logger
+ event handler, must be added to handle this event.</p>
<p>It is recommended that <c><anno>Report</anno></c> follows the same
structure as for
<seealso marker="#info_report/1"><c>info_report/1</c></seealso>.</p>
+ <p>This functions is kept for backwards compatibility and
+ must not be used by new code. Use the <seealso marker="logger#macros">
+ <c>?LOG_INFO</c></seealso> macro or
+ <seealso marker="logger#info-1"><c>logger:info/1,2,3</c></seealso>
+ instead.</p>
</desc>
</func>
<func>
@@ -271,14 +305,22 @@ ok</pre>
<type name="open_error"/>
<desc>
<p>Enables or disables printout of standard events to a file.</p>
- <p>This is done by adding or deleting the standard event handler
- for output to file. Thus, calling this function overrides
- the value of the Kernel <c>error_logger</c> configuration
- parameter.</p>
- <p>Enabling file logging can be used together with calling
- <c>tty(false)</c>, to have a silent system where
- all standard events are logged to a file only.
- Only one log file can be active at a time.</p>
+ <p>This is done by adding or deleting
+ the <c>error_logger_file_h</c> event handler, and thus
+ indirectly adding <c>error_logger</c> as a Logger
+ handler.</p>
+ <p>Notice that this function does not manipulate the Logger
+ configuration directly, meaning that if the default Logger
+ handler is already logging to a file, this function can
+ potentially cause logging to a second file.</p>
+ <p>This function is useful as a shortcut during development
+ and testing, but must not be used in a production
+ system. See
+ section <seealso marker="logger_chapter">Logging</seealso>
+ in the Kernel User's Guide, and
+ the <seealso marker="logger"><c>logger(3)</c></seealso>
+ manual page for information about how to configure Logger
+ for live systems.</p>
<p><c>Request</c> is one of the following:</p>
<taglist>
<tag><c>{open, <anno>Filename</anno>}</c></tag>
@@ -310,9 +352,14 @@ ok</pre>
<p>Enables (<c><anno>Flag</anno> == true</c>) or disables
(<c><anno>Flag</anno> == false</c>) printout of standard events
to the terminal.</p>
- <p>This is done by adding or deleting the standard event handler
- for output to the terminal. Thus, calling this function overrides
- the value of the Kernel <c>error_logger</c> configuration parameter.</p>
+ <p>This is done by manipulating the Logger configuration. The
+ function is useful as a shortcut during development and
+ testing, but must not be used in a production system. See
+ section <seealso marker="logger_chapter">Logging</seealso>
+ in the Kernel User's Guide, and
+ the <seealso marker="logger"><c>logger(3)</c></seealso>
+ manual page for information about how to configure Logger
+ for live systems.</p>
</desc>
</func>
<func>
@@ -355,24 +402,27 @@ ok</pre>
<func>
<name name="warning_msg" arity="1"/>
<name name="warning_msg" arity="2"/>
- <fsummary>Send a standard warning event to the error logger.</fsummary>
+ <fsummary>Log a standard warning event.</fsummary>
<desc>
- <p>Sends a standard warning event to the error logger.
- The <c><anno>Format</anno></c> and <c><anno>Data</anno></c> arguments
- are the same as the arguments of
+ <p>Log a standard warning event. The <c><anno>Format</anno></c>
+ and <c><anno>Data</anno></c> arguments are the same as the
+ arguments of
<seealso marker="stdlib:io#format/2"><c>io:format/2</c></seealso>
- in STDLIB.
- The event is handled by the standard event handler. It is tagged
- as an error, warning, or info, see
+ in STDLIB.</p>
+ <p>Error logger forwards the event to Logger, including
+ metadata that allows backwards compatibility with legacy
+ error logger event handlers.</p>
+ <p>The event is handled by the default Logger handler. The log
+ level can be changed to error or info, see
<seealso marker="#warning_map/0"><c>warning_map/0</c></seealso>.</p>
- <warning>
- <p>If called with bad arguments, this function can crash
- the standard event handler, meaning no further events are
- logged. When in doubt, use <c>warning_report/1</c> instead.</p>
- </warning>
+ <p>These functions are kept for backwards compatibility and
+ must not be used by new code. Use the <seealso marker="logger#macros">
+ <c>?LOG_WARNING</c></seealso> macro or
+ <seealso marker="logger#warning-1"><c>logger:warning/1,2,3</c></seealso>
+ instead.</p>
<warning>
<p>If the Unicode translation modifier (<c>t</c>) is used in
- the format string, all error handlers must ensure that the
+ the format string, all event handlers must ensure that the
formatted output is correctly encoded for the I/O
device.</p>
</warning>
@@ -380,24 +430,43 @@ ok</pre>
</func>
<func>
<name name="warning_report" arity="1"/>
- <fsummary>Send a standard warning report event to the error logger.</fsummary>
+ <fsummary>Log a standard warning event.</fsummary>
<desc>
- <p>Sends a standard warning report event to the error logger.
- The event is handled by the standard event handler. It is
- tagged as an error, warning, or info, see
+ <p>Log a standard warning event. Error logger forwards the event
+ to Logger, including metadata that allows backwards
+ compatibility with legacy error logger event handlers.</p>
+ <p>The event is handled by the default Logger handler. The log
+ level can be changed to error or info, see
<seealso marker="#warning_map/0"><c>warning_map/0</c></seealso>.</p>
+ <p>This functions is kept for backwards compatibility and
+ must not be used by new code. Use the <seealso marker="logger#macros">
+ <c>?LOG_WARNING</c></seealso> macro or
+ <seealso marker="logger#warning-1"><c>logger:warning/1,2,3</c></seealso>
+ instead.</p>
</desc>
</func>
<func>
<name name="warning_report" arity="2"/>
- <fsummary>Send a user-defined warning report event to the error logger.</fsummary>
+ <fsummary>Log a user-defined warning event.</fsummary>
<desc>
- <p>Sends a user-defined warning report event to the error
- logger. An event handler to handle the event is supposed to
- have been added. The event is ignored by the standard event
- handler. It is tagged as an error, warning, or info,
- depending on the value of
+ <p>Log a user-defined warning event. Error logger forwards the
+ event to Logger, including metadata that allows backwards
+ compatibility with legacy error logger event handlers.</p>
+ <p>Error logger also adds a <c>domain</c> field with
+ value <c>[<anno>Type</anno>]</c> to this event's metadata,
+ causing the filters of the default Logger handler to discard
+ the event. A different Logger handler, or an error logger
+ event handler, must be added to handle this event.</p>
+ <p>The log level can be changed to error or info, see
<seealso marker="#warning_map/0"><c>warning_map/0</c></seealso>.</p>
+ <p>It is recommended that <c><anno>Report</anno></c> follows the same
+ structure as for
+ <seealso marker="#warning_report/1"><c>warning_report/1</c></seealso>.</p>
+ <p>This functions is kept for backwards compatibility and
+ must not be used by new code. Use the <seealso marker="logger#macros">
+ <c>?LOG_WARNING</c></seealso> macro or
+ <seealso marker="logger#warning-1"><c>logger:warning/1,2,3</c></seealso>
+ instead.</p>
</desc>
</func>
</funcs>
@@ -461,8 +530,9 @@ ok</pre>
<section>
<title>See Also</title>
<p><seealso marker="stdlib:gen_event"><c>gen_event(3)</c></seealso>,
- <seealso marker="stdlib:log_mf_h"><c>log_mf_h(3)</c></seealso>
- <seealso marker="kernel_app"><c>kernel(6)</c></seealso>
+ <seealso marker="kernel:logger"><c>logger(3)</c></seealso>,
+ <seealso marker="stdlib:log_mf_h"><c>log_mf_h(3)</c></seealso>,
+ <seealso marker="kernel_app"><c>kernel(6)</c></seealso>,
<seealso marker="sasl:sasl_app"><c>sasl(6)</c></seealso></p>
</section>
</erlref>
diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml
index 1b72769ce3..9acaf6b41e 100644
--- a/lib/kernel/doc/src/file.xml
+++ b/lib/kernel/doc/src/file.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/heart.xml b/lib/kernel/doc/src/heart.xml
index 46c7ce60b6..ad1a2ffeb9 100644
--- a/lib/kernel/doc/src/heart.xml
+++ b/lib/kernel/doc/src/heart.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index 9552332948..f281d61459 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -734,22 +734,23 @@ get_tcpi_sacked(Sock) ->
</item>
<tag><c>{buffer, Size}</c></tag>
<item>
- <p>The size of the user-level software buffer used by
- the driver.
- Not to be confused with options <c>sndbuf</c>
+ <p>The size of the user-level buffer used by
+ the driver. Not to be confused with options <c>sndbuf</c>
and <c>recbuf</c>, which correspond to the
- Kernel socket buffers. It is recommended
- to have <c>val(buffer) &gt;= max(val(sndbuf),val(recbuf))</c> to
+ Kernel socket buffers. For TCP it is recommended
+ to have <c>val(buffer) &gt;= val(recbuf)</c> to
avoid performance issues because of unnecessary copying.
+ For UDP the same recommendation applies, but the max should
+ not be larger than the MTU of the network path.
<c>val(buffer)</c> is automatically set to the above
- maximum when values <c>sndbuf</c> or <c>recbuf</c> are set.
- However, as the sizes set for <c>sndbuf</c> and <c>recbuf</c>
+ maximum when <c>recbuf</c> is set.
+ However, as the size set for <c>recbuf</c>
usually become larger, you are encouraged to use
<seealso marker="#getopts/2"><c>getopts/2</c></seealso>
to analyze the behavior of your operating system.</p>
<p>Note that this is also the maximum amount of data that can be
- received from a single recv call. If you are using higher than
- normal MTU consider setting buffer higher.</p>
+ received from a single recv call. If you are using higher than
+ normal MTU consider setting buffer higher.</p>
</item>
<tag><c>{delay_send, Boolean}</c></tag>
<item>
@@ -1149,7 +1150,7 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp</code>
<seealso marker="gen_tcp#recv/2"><c>gen_tcp:recv/2</c></seealso>
gets <c>{error, closed}</c>. In active
mode, the controlling process receives a
- <c>{tcp_close, Socket}</c> message, indicating that the
+ <c>{tcp_closed, Socket}</c> message, indicating that the
peer has closed the connection.</p>
<p>Setting this option to <c>true</c> allows you to
distinguish between a connection that was closed normally,
diff --git a/lib/kernel/doc/src/introduction_chapter.xml b/lib/kernel/doc/src/introduction_chapter.xml
index 6e6990ddda..d02b1a2ee5 100644
--- a/lib/kernel/doc/src/introduction_chapter.xml
+++ b/lib/kernel/doc/src/introduction_chapter.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2017</year>
+ <year>2017</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -46,7 +46,6 @@
<item>Start, stop, supervision, configuration, and distribution of applications</item>
<item>Code loading</item>
<item>Logging</item>
- <item>Error logging</item>
<item>Global name service</item>
<item>Supervision of Erlang/OTP</item>
<item>Communication with sockets</item>
diff --git a/lib/kernel/doc/src/kernel_app.xml b/lib/kernel/doc/src/kernel_app.xml
index 7894600c21..15dbdb47dc 100644
--- a/lib/kernel/doc/src/kernel_app.xml
+++ b/lib/kernel/doc/src/kernel_app.xml
@@ -42,7 +42,6 @@
<item>Start, stop, supervision, configuration, and distribution of applications</item>
<item>Code loading</item>
<item>Logging</item>
- <item>Error logging</item>
<item>Global name service</item>
<item>Supervision of Erlang/OTP</item>
<item>Communication with sockets</item>
@@ -55,9 +54,9 @@
<p>Two standard logger handlers are defined in
the Kernel application. These are described in the
<seealso marker="logger_chapter">Kernel User's Guide</seealso>,
- and in <seealso marker="logger_std_h"><c>logger_std_h(3)</c></seealso>
+ and in the <seealso marker="logger_std_h"><c>logger_std_h(3)</c></seealso>
and <seealso marker="logger_disk_log_h"><c>logger_disk_log_h(3)</c>
- </seealso>.</p>
+ </seealso> manual pages.</p>
</section>
<section>
@@ -165,140 +164,73 @@
<p>Permissions are described in
<seealso marker="application#permit/2"><c>application:permit/2</c></seealso>.</p>
</item>
- <tag><c>logger_dest = Value</c></tag>
- <item>
- <p><c>Value</c> is one of:</p>
- <taglist>
- <tag><c>tty</c></tag>
- <item><p>Installs the standard handler, <seealso marker="logger_std_h">
- <c>logger_std_h(3)</c></seealso>, with <c>type</c> set
- to <c>standard_io</c>. This is the default
- option.</p></item>
- <tag><c>{file, FileName}</c></tag>
- <item><p>Installs the standard handler, <seealso marker="logger_std_h">
- <c>logger_std_h(3)</c></seealso>, with <c>type</c> set
- to <c>{file, FileName}</c>, where <c>FileName</c>
- is a string. The file is opened with encoding UTF-8.</p></item>
- <tag><c>{disk_log, FileName}</c></tag>
- <item><p>Installs the disk_log handler, <seealso marker="logger_disk_log_h">
- <c>logger_disk_log_h(3)</c></seealso>, with <c>file</c> set
- to <c>FileName</c> (a string), and possibly other disk_log
- parameters set by the environment variables
- <c>logger_disk_log_type</c>, <c>logger_disk_log_maxfiles</c> and
- <c>logger_disk_log_maxbytes</c>,
- see <seealso marker="#disk_log_vars">below</seealso>. The
- file is opened with encoding UTF-8.</p></item>
- <tag><c>false</c></tag>
- <item>
- <p>No standard handler is installed, but
- the initial, primitive handler is kept, printing
- raw event messages to <c>tty</c>.</p>
- </item>
- <tag><c>silent</c></tag>
- <item>
- <p>No standard handler is started, and the initial,
- primitive handler is removed.</p>
- </item>
- </taglist>
- </item>
- <tag><c>logger_level = Level</c></tag>
- <item>
- <p><c>Value = emergency | alert | critical | error | warning |
- notice | info | debug</c></p>
- <p>This parameter specifies which log levels to log. The
- specified level, and all levels that are more severe, will
- be logged.</p>
- <p>This configuration parameter is used both for the global
- logger level, and for the standard handler started by
- the Kernel application (see <c>logger_dest</c> variable above).</p>
- <p>The default value is <c>info</c>.</p>
- </item>
- <tag><marker id="disk_log_vars"/>
- <c>logger_disk_log_type = halt | wrap</c></tag>
- <item/>
- <tag><c>logger_disk_log_maxfiles = integer()</c></tag>
- <item/>
- <tag><c>logger_disk_log_maxbytes = integer()</c></tag>
- <item>
- <p>If <c>logger_dest</c> is set to {disk_log,File}, then these
- parameters specify the configuration to use when opening the
- disk log file. They specify the type of disk log, the
- maximum number of files (if the type is wrap) and the
- maximum size of each file, respectively.</p>
- <p>The default values are:</p>
- <code>
-logger_disk_log_type = wrap
-logger_disk_log_maxfiles = 10
-logger_disk_log_maxbytes = 1048576</code>
+ <tag><marker id="logger"/><c>logger = [Config]</c></tag>
+ <item>
+ <p>Specifies the configuration
+ for <seealso marker="logger">Logger</seealso>, except the
+ primary log level, which is specified
+ with <seealso marker="#logger_level"><c>logger_level</c></seealso>,
+ and the compatibility
+ with <seealso marker="sasl:error_logging">SASL Error
+ Logging</seealso>, which is specified
+ with <seealso marker="#logger_sasl_compatible">
+ <c>logger_sasl_compatible</c></seealso>.</p>
+ <p>The <c>logger </c> parameter is described in
+ section <seealso marker="logger_chapter#logger_parameter">
+ Logging</seealso> in the Kernel User's Guide.</p>
+ </item>
+ <tag><marker id="logger_level"/><c>logger_level = Level</c></tag>
+ <item>
+ <p>Specifies the primary log level for Logger. Log events with
+ the same, or a more severe level, pass through the primary
+ log level check. See
+ section <seealso marker="logger_chapter">Logging</seealso>
+ in the Kernel User's Guide for more information about Logger
+ and log levels.</p>
+ <p><c>Level = emergency | alert | critical | error | warning |
+ notice | info | debug | all | none</c></p>
+ <p>To change the primary log level at runtime, use
+ <seealso marker="logger#set_primary_config/2">
+ <c>logger:set_primary_config(level, Level)</c></seealso>.</p>
+ <p>Defaults to <c>notice</c>.</p>
</item>
<tag><marker id="logger_sasl_compatible"/>
- <c>logger_sasl_compatible = boolean()</c></tag>
- <item>
- <p>If this parameter is set to true, then the logger handler
- started by kernel will not log any progress-, crash-, or
- supervisor reports. If the SASL application is started,
- these log events will be sent to a second handler instance
- named <c>sasl_h</c>, according to values of the SASL
- environment variables <c>sasl_error_logger</c>
- and <c>sasl_errlog_type</c>, see
- <seealso marker="sasl:sasl_app#configuration">SASL(6)
- </seealso></p>
- <p>The default value is <c>false</c>.</p>
- <p>See chapter <seealso marker="logger_chapter#compatibility">Backwards
- compatibility with error_logger</seealso> for more
- information about handling of the so called SASL reports.</p>
- </item>
- <tag><marker id="logger_log_progress"/>
- <c>logger_log_progress = boolean()</c></tag>
- <item>
- <p>If <c>logger_sasl_compatible = false</c>,
- then <c>logger_log_progress</c> specifies if progress
- reports from <c>supervisor</c>
- and <c>application_controller</c> shall be logged or
- not.</p>
- <p>If <c>logger_sasl_compatible = true</c>,
- then <c>logger_log_progress</c> is ignored.</p>
- </item>
- <tag><marker id="logger_format_depth"/>
- <c>logger_format_depth = Depth</c></tag>
- <item>
- <p>Can be used to limit the size of the
- formatted output from the logger handlers.</p>
-
- <p><c>Depth</c> is a positive integer representing the maximum
- depth to which terms are printed by the logger
- handlers included in OTP. This
- configuration parameter is used by the default formatter,
- <seealso marker="logger_formatter"><c>logger_formatter(3)</c></seealso>,
- unless the formatter's <c>depth</c> parameter is explicitly set.
- (If you have implemented your own formatter, this configuration
- parameter has no effect on that.)</p>
-
- <p><c>Depth</c> is used as follows: Format strings
- received by the formatter are rewritten.
- The format controls <c>~p</c> and <c>~w</c> are replaced with
- <c>~P</c> and <c>~W</c>, respectively, and <c>Depth</c> is
- used as the depth parameter. For details, see
- <seealso marker="stdlib:io#format/2"><c>io:format/2</c></seealso>
- in STDLIB.</p>
-
- <note><p>A reasonable starting value for <c>Depth</c> is
- <c>30</c>. We recommend to test crashing various processes in your
- application, examine the logs from the crashes, and then
- increase or decrease the value.</p></note>
- </item>
- <tag><c>logger_max_size = integer() | unlimited</c></tag>
- <item>
- <p>This parameter specifies a hard maximum size limit (number
- of characters) each log event can have when printed by the
- default logger formatter. If the resulting string after
- formatting an event is bigger than this, it will be
- truncated before printed to the handler's destination.</p>
- </item>
- <tag><c>logger_utc = boolean()</c></tag>
- <item>
- <p>If set to <c>true</c>, the default formatter will display
- all dates in Universal Coordinated Time.</p>
+ <c>logger_sasl_compatible = true | false</c></tag>
+ <item>
+ <p>Specifies if Logger behaves backwards compatible with the
+ SASL error logging functionality from releases prior to
+ Erlang/OTP 21.0.</p>
+ <p>If this parameter is set to <c>true</c>, the default Logger
+ handler does not log any progress-, crash-, or supervisor
+ reports. If the SASL application is then started, it adds a
+ Logger handler named <c>sasl</c>, which logs these events
+ according to values of the SASL configuration
+ parameter <c>sasl_error_logger</c>
+ and <c>sasl_errlog_type</c>.</p>
+ <p>See section
+ <seealso marker="sasl:sasl_app#deprecated_error_logger_config">
+ Deprecated Error Logger Event Handlers and
+ Configuration</seealso> in the sasl(6) manual page for
+ information about the SASL configuration parameters.</p>
+ <p>See section <seealso marker="sasl:error_logging">SASL Error
+ Logging</seealso> in the SASL User's Guide, and
+ section <seealso marker="logger_chapter#compatibility">Backwards
+ Compatibility with error_logger</seealso> in the Kernel
+ User's Guide for information about the SASL error logging
+ functionality, and how Logger can be backwards compatible
+ with this.</p>
+ <p>Defaults to <c>false</c>.</p>
+ <note>
+ <p>If this parameter is set to <c>true</c>,
+ <c>sasl_errlog_type</c> indicates that progress reports
+ shall be logged, and the configured primary log level
+ is <c>notice</c> or more severe, then SASL automatically
+ sets the primary log level to <c>info</c>. That is, this
+ setting can potentially overwrite the value of the Kernel
+ configuration parameter <c>logger_level</c>. This is to
+ allow progress reports, which have log level <c>info</c>,
+ to be forwarded to the handlers.</p>
+ </note>
</item>
<tag><c>global_groups = [GroupTuple]</c></tag>
<item>
@@ -351,9 +283,8 @@ logger_disk_log_maxbytes = 1048576</code>
</item>
<tag><c>inet_parse_error_log = silent</c></tag>
<item>
- <p>If set, no
- <c>error_logger</c> messages are generated when erroneous
- lines are found and skipped in the various Inet configuration
+ <p>If set, no log events are issued when erroneous lines are
+ found and skipped in the various Inet configuration
files.</p>
</item>
<tag><c>inetrc = Filename</c></tag>
@@ -379,24 +310,31 @@ logger_disk_log_maxbytes = 1048576</code>
<tag><c>net_ticktime = TickTime</c></tag>
<item>
<marker id="net_ticktime"></marker>
- <p>Specifies the <c>net_kernel</c> tick time. <c>TickTime</c>
- is specified in seconds. Once every <c>TickTime/4</c> second, all
- connected nodes are ticked (if anything else is written
- to a node). If nothing is received from another node
- within the last four tick times, that node is considered
- to be down. This ensures that nodes that are not responding,
- for reasons such as hardware errors, are considered to be
- down.</p>
- <p>The time <c>T</c>, in which a node that is not responding is
- detected, is calculated as <c><![CDATA[MinT < T < MaxT]]></c>, where:</p>
+ <p>Specifies the <c>net_kernel</c> tick time in seconds. This is the
+ approximate time a connected node may be unresponsive until it is
+ considered down and thereby disconnected.</p>
+ <p>Once every <c>TickTime/4</c> seconds, each connected node is ticked
+ if nothing has been sent to it during that last <c>TickTime/4</c>
+ interval. A tick is a small package sent on the connection. A connected
+ node is considered to be down if no ticks or payload packages have been
+ received during the last four <c>TickTime/4</c> intervals. This ensures
+ that nodes that are not responding, for reasons such as hardware errors,
+ are considered to be down.</p>
+ <p>As the availability is only checked every <c>TickTime/4</c> seconds,
+ the actual time <c>T</c> a node have been unresponsive when
+ detected may vary between <c>MinT</c> and <c>MaxT</c>,
+ where:</p>
<code type="none">
MinT = TickTime - TickTime / 4
MaxT = TickTime + TickTime / 4</code>
- <p><c>TickTime</c> defaults to <c>60</c> (seconds). Thus,
- <c><![CDATA[45 < T < 75]]></c> seconds.</p>
- <p>Notice that <em>all</em> communicating nodes are to have the <em>same</em>
- <c>TickTime</c> value specified.</p>
- <p>Normally, a terminating node is detected immediately.</p>
+ <p><c>TickTime</c> defaults to <c>60</c> seconds. Thus,
+ <c><![CDATA[45 < T < 75]]></c> seconds.</p>
+ <p>Notice that <em>all</em> communicating nodes are to have the
+ <em>same</em> <c>TickTime</c> value specified, as it determines both the
+ frequency of outgoing ticks and the expected frequency of incominging
+ ticks.</p>
+ <p>Normally, a terminating node is detected immediately by the transport
+ protocol (like TCP/IP).</p>
</item>
<tag><c>shutdown_timeout = integer() | infinity</c></tag>
<item>
@@ -563,18 +501,29 @@ MaxT = TickTime + TickTime / 4</code>
<section>
<title>Deprecated Configuration Parameters</title>
- <p>In OTP-21, a new API for logging was added to Erlang/OTP. The
+ <p>In Erlang/OTP 21.0, a new API for logging was added. The
old <c>error_logger</c> event manager, and event handlers
- running on this manager, will still work, but they are not used
+ running on this manager, still work, but they are no longer used
by default.</p>
- <p>The following application environment variables can still be
- set, but they will only be used if the corresponding new logger
- variables are not set.</p>
+ <p>The following application configuration parameters can still be
+ set, but they are only used if the corresponding configuration
+ parameters for Logger are not set.</p>
<taglist>
<tag><c>error_logger</c></tag>
- <item>Replaced by <c>logger_dest</c></item>
+ <item>Replaced by setting the type of the default
+ <seealso marker="logger_std_h#type"><c>logger_std_h</c></seealso>
+ to the same value. Example:
+ <code type="none">
+erl -kernel logger '[{handler,default,logger_std_h,#{config=>#{type=>{file,"/tmp/erlang.log"}}}}]'
+ </code>
+ </item>
<tag><c>error_logger_format_depth</c></tag>
- <item>Replaced by <c>logger_format_depth</c></item>
+ <item>Replaced by setting the <seealso marker="logger_formatter#depth"><c>depth</c></seealso>
+ parameter of the default handlers formatter. Example:
+ <code type="none">
+erl -kernel logger '[{handler,default,logger_std_h,#{formatter=>{logger_formatter,#{legacy_header=>true,template=>[{logger_formatter,header},"\n",msg,"\n"],depth=>10}}}]'
+ </code>
+ </item>
</taglist>
<p>See <seealso marker="logger_chapter#compatibility">Backwards
compatibility with error_logger</seealso> for more
@@ -589,12 +538,12 @@ MaxT = TickTime + TickTime / 4</code>
<seealso marker="disk_log"><c>disk_log(3)</c></seealso>,
<seealso marker="erl_boot_server"><c>erl_boot_server(3)</c></seealso>,
<seealso marker="erl_ddll"><c>erl_ddll(3)</c></seealso>,
- <seealso marker="error_logger"><c>error_logger(3)</c></seealso>,
<seealso marker="file"><c>file(3)</c></seealso>,
<seealso marker="global"><c>global(3)</c></seealso>,
<seealso marker="global_group"><c>global_group(3)</c></seealso>,
<seealso marker="heart"><c>heart(3)</c></seealso>,
<seealso marker="inet"><c>inet(3)</c></seealso>,
+ <seealso marker="logger"><c>logger(3)</c></seealso>,
<seealso marker="net_kernel"><c>net_kernel(3)</c></seealso>,
<seealso marker="os"><c>os(3)</c></seealso>,
<seealso marker="pg2"><c>pg2(3)</c></seealso>,
diff --git a/lib/kernel/doc/src/logger.xml b/lib/kernel/doc/src/logger.xml
index d901454e62..a4d6efa2d8 100644
--- a/lib/kernel/doc/src/logger.xml
+++ b/lib/kernel/doc/src/logger.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2017</year>
+ <year>2017</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -33,33 +33,151 @@
<file>logger.xml</file>
</header>
<module>logger</module>
- <modulesummary>API module for the logger application.</modulesummary>
+ <modulesummary>API module for Logger, the standard logging facility
+ in Erlang/OTP.</modulesummary>
<description>
+ <p>This module implements the main API for logging in
+ Erlang/OTP. To create a log event, use the
+ <seealso marker="#logging_API">API functions</seealso> or the
+ log
+ <seealso marker="#macros">macros</seealso>, for example:</p>
+ <code>
+?LOG_ERROR("error happened because: ~p", [Reason]). % With macro
+logger:error("error happened because: ~p", [Reason]). % Without macro
+ </code>
+ <p>To configure the Logger backend,
+ use <seealso marker="kernel_app#logger">Kernel configuration
+ parameters</seealso>
+ or <seealso marker="#configuration_API">configuration
+ functions</seealso> in the Logger API.</p>
+
+ <p>By default, the Kernel application installs one log handler at
+ system start. This handler is named <c>default</c>. It receives
+ and processes standard log events produced by the Erlang runtime
+ system, standard behaviours and different Erlang/OTP
+ applications. The log events are by default printed to the
+ terminal.</p>
+ <p>If you want your systems logs to be printed to a file instead,
+ you must configure the default handler to do so. The simplest
+ way is to include the following in
+ your <seealso marker="config"><c>sys.config</c></seealso>:</p>
+ <code>
+[{kernel,
+ [{logger,
+ [{handler, default, logger_std_h,
+ #{config => #{type => {file, "path/to/file.log"}}}}]}]}].
+ </code>
+ <p>
+ For more information about:
+ </p>
+ <list type="bulleted">
+ <item>the Logger facility in general, see
+ the <seealso marker="logger_chapter">User's
+ Guide</seealso>.</item>
+ <item>how to configure Logger, see
+ the <seealso marker="logger_chapter#configuration">Configuration</seealso>
+ section in the User's Guide.</item>
+ <item>the built-in handlers,
+ see <seealso marker="logger_std_h">logger_std_h</seealso> and
+ <seealso marker="logger_disk_log_h">logger_disk_log_h</seealso>.</item>
+ <item>the built-in formatter,
+ see <seealso marker="logger_formatter">logger_formatter</seealso>.</item>
+ <item>built-in filters,
+ see <seealso marker="logger_filters">logger_filters</seealso>.</item>
+ </list>
+
+ <note>
+ <p>Since Logger is new in Erlang/OTP 21.0, we do reserve the right
+ to introduce changes to the Logger API and functionality in
+ patches following this release. These changes might or might not
+ be backwards compatible with the initial version.</p>
+ </note>
</description>
<datatypes>
<datatype>
- <name name="level"/>
+ <name name="filter"/>
<desc>
- <p>The severity level for the message to be logged.</p>
+ <p>A filter which can be installed as a handler filter, or as
+ a primary filter in Logger.</p>
</desc>
</datatype>
<datatype>
- <name name="log"/>
+ <name name="filter_arg"/>
<desc>
- <p></p>
+ <p>The second argument to the filter fun.</p>
</desc>
</datatype>
<datatype>
- <name name="report"/>
+ <name name="filter_id"/>
<desc>
- <p></p>
+ <p>A unique identifier for a filter.</p>
</desc>
</datatype>
<datatype>
- <name name="msg_fun"/>
+ <name name="filter_return"/>
+ <desc>
+ <p>The return value from the filter fun.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="formatter_config"/>
+ <desc>
+ <p>Configuration data for the
+ formatter. See <seealso marker="logger_formatter">
+ <c>logger_formatter(3)</c></seealso>
+ for an example of a formatter implementation.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="handler_config"/>
+ <desc>
+ <p>Handler configuration data for Logger. The following
+ default values apply:</p>
+ <list>
+ <item><c>level => all</c></item>
+ <item><c>filter_default => log</c></item>
+ <item><c>filters => []</c></item>
+ <item><c>formatter => {logger_formatter, DefaultFormatterConfig</c>}</item>
+ </list>
+ <p>In addition to these, the following fields are
+ automatically inserted by Logger, values taken from the
+ two first parameters
+ to <seealso marker="#add_handler-3"><c>add_handler/3</c></seealso>:</p>
+ <list>
+ <item><c>id => HandlerId</c></item>
+ <item><c>module => Module</c></item>
+ </list>
+ <p>These are read-only and cannot be changed in runtime.</p>
+ <p>Handler specific configuration data is inserted by the
+ handler callback itself, in a sub structure associated with
+ the field named <c>config</c>. See
+ the <seealso marker="logger_std_h"><c>logger_std_h(3)</c></seealso>
+ and <seealso marker="logger_disk_log_h"><c>logger_disk_log_h</c></seealso>
+ manual pages for information about the specifc configuration
+ for these handlers.</p>
+ <p>See the <seealso marker="logger_formatter#type-config">
+ <c>logger_formatter(3)</c></seealso> manual page for
+ information about the default configuration for this
+ formatter.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="handler_id"/>
+ <desc>
+ <p>A unique identifier for a handler instance.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="level"/>
+ <desc>
+ <p>The severity level for the message to be logged.</p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="log_event"/>
<desc>
<p></p>
</desc>
@@ -72,12 +190,12 @@
<list>
<item><c>pid => self()</c></item>
<item><c>gl => group_leader()</c></item>
- <item><c>time => erlang:monotonic_time(microsecond)</c></item>
+ <item><c>time => erlang:system_time(microsecond)</c></item>
</list>
<p>When a log macro is used, Logger also inserts location
information:</p>
<list>
- <item><c>mfa => {?MODULE,?FUNCTION_NAME,?FUNCTION_ARITY}</c></item>
+ <item><c>mfa => {?MODULE, ?FUNCTION_NAME, ?FUNCTION_ARITY}</c></item>
<item><c>file => ?FILE</c></item>
<item><c>line => ?LINE</c></item>
</list>
@@ -90,63 +208,82 @@
<c>update_process_metadata/1</c></seealso>.</p>
<p>Logger merges all the metadata maps before forwarding the
log event to the handlers. If the same keys occur, values
- from the log call overwrites process metadata, which in turn
- overwrites values set by Logger.</p>
+ from the log call overwrite process metadata, which in turn
+ overwrite values set by Logger.</p>
+ <p>The following custom metadata keys have special meaning:</p>
+ <taglist>
+ <tag><c>domain</c></tag>
+ <item>
+ <p>The value associated with this key is used by filters
+ for grouping log events originating from, for example,
+ specific functional
+ areas. See <seealso marker="logger_filters#domain-2">
+ <c>logger_filters:domain/2</c></seealso>
+ for a description of how this field can be used.</p>
+ </item>
+ <tag><c>report_cb</c></tag>
+ <item>
+ <p>If the log message is specified as
+ a <seealso marker="#type-report"><c>report()</c></seealso>,
+ the <c>report_cb</c> key can be associated with a fun
+ (report callback) that converts the report to a format
+ string and arguments, or directly to a string. See the
+ type definition
+ of <seealso marker="#type-report_cb"><c>report_cb()</c></seealso>,
+ and
+ section <seealso marker="logger_chapter#log_message">Log
+ Message</seealso> in the User's Guide for more
+ information about report callbacks.</p>
+ </item>
+ </taglist>
</desc>
</datatype>
<datatype>
- <name name="config"/>
+ <name name="msg_fun"/>
<desc>
- <p>Configuration data for the logger part of Logger, or for a handler.</p>
- <p>The following default values apply:</p>
+ <p></p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="primary_config"/>
+ <desc>
+ <p>Primary configuration data for Logger. The following
+ default values apply:</p>
<list>
<item><c>level => info</c></item>
<item><c>filter_default => log</c></item>
<item><c>filters => []</c></item>
- <item><c>formatter => {logger_formatter,DefaultFormatterConfig</c>}</item>
</list>
- <p>See the <seealso marker="logger_formatter#configuration">
- <c>logger_formatter(3)</c></seealso> manual page for
- information about the default configuration for this
- formatter.</p>
- </desc>
- </datatype>
- <datatype>
- <name name="handler_id"/>
- <desc>
- <p>A unique identifier for a handler instance.</p>
- </desc>
- </datatype>
- <datatype>
- <name name="filter_id"/>
- <desc>
- <p>A unique identifier for a filter.</p>
</desc>
</datatype>
<datatype>
- <name name="filter"/>
+ <name name="report"/>
<desc>
- <p>A filter which can be installed for logger or for a handler.</p>
+ <p></p>
</desc>
</datatype>
<datatype>
- <name name="filter_arg"/>
+ <name name="report_cb"/>
<desc>
- <p>The second argument to the filter fun.</p>
+ <p>A fun which converts a <seealso marker="#type-report"><c>report()</c>
+ </seealso> to a format string and arguments, or directly to a string.
+ See section <seealso marker="logger_chapter#log_message">Log
+ Message</seealso> in the User's Guide for more
+ information.</p>
</desc>
</datatype>
<datatype>
- <name name="filter_return"/>
+ <name name="report_cb_config"/>
<desc>
- <p>The return value from the filter fun.</p>
+ <p></p>
</desc>
</datatype>
<datatype>
<name name="timestamp"/>
<desc>
<p>A timestamp produced
- with <seealso marker="erts:erlang#monotonic_time-1">
- <c>erlang:monotonic_time(microsecond)</c></seealso>.</p>
+ with <seealso marker="erts:erlang#system_time-1">
+ <c>erlang:system_time(microsecond)</c></seealso>.</p>
</desc>
</datatype>
</datatypes>
@@ -172,19 +309,26 @@
<item><c>?LOG_INFO(FunOrFormat,Args[,Metadata])</c></item>
<item><c>?LOG_DEBUG(StringOrReport[,Metadata])</c></item>
<item><c>?LOG_DEBUG(FunOrFormat,Args[,Metadata])</c></item>
+ <item><c>?LOG(Level,StringOrReport[,Metadata])</c></item>
+ <item><c>?LOG(Level,FunOrFormat,Args[,Metadata])</c></item>
</list>
- <p>All macros expand to a call to logger, where <c>Level</c> is
- taken from the macro name, and location data is added. See the
- description of
+ <p>All macros expand to a call to Logger, where <c>Level</c> is
+ taken from the macro name, or from the first argument in the
+ case of the <c>?LOG</c> macro. Location data is added to the
+ metadata as described under
the <seealso marker="#type-metadata"><c>metadata()</c></seealso>
- type for more information about the location data.</p>
+ type definition.</p>
<p>The call is wrapped in a case statement and will be evaluated
only if <c>Level</c> is equal to or below the configured log
level.</p>
</section>
+ <section>
+ <marker id="logging_API"/>
+ <title>Logging API functions</title>
+ </section>
<funcs>
<func>
<name>emergency(StringOrReport[,Metadata])</name>
@@ -244,7 +388,7 @@
<func>
<name>notice(StringOrReport[,Metadata])</name>
<name>notice(Format,Args[,Metadata])</name>
- <name>notice(Fun,FunArgs[,Metadata])</name>
+ <name>notice(Fun,FunArgs[,Metadata])</name>
<fsummary>Logs the given message as level <c>notice</c>.</fsummary>
<desc>
<p>Equivalent to
@@ -293,112 +437,41 @@
<p>Log the given message.</p>
</desc>
</func>
+ </funcs>
+ <section>
+ <marker id="configuration_API"/>
+ <title>Configuration API functions</title>
+ </section>
+ <funcs>
<func>
- <name name="get_logger_config" arity="0"/>
- <fsummary>Lookup the current configuration for logger.</fsummary>
- <desc>
- <p>Lookup the current configuration for logger.</p>
- </desc>
- </func>
-
- <func>
- <name name="get_handler_config" arity="1"/>
- <fsummary>Lookup the current configuration for the given handler.</fsummary>
- <desc>
- <p>Lookup the current configuration for the given handler.</p>
- </desc>
- </func>
-
- <func>
- <name name="i" arity="0"/>
- <fsummary>Get all logger configurations</fsummary>
+ <name name="add_handler" arity="3"/>
+ <fsummary>Add a handler with the given configuration.</fsummary>
<desc>
- <p>Same as <seealso marker="#i/1"><c>logger:i(term)</c></seealso></p>
+ <p>Add a handler with the given configuration.</p>
+ <p><c><anno>HandlerId</anno></c> is a unique identifier which
+ must be used in all subsequent calls referring to this
+ handler.</p>
</desc>
</func>
<func>
- <name name="i" arity="1" clause_i="1"/>
- <name name="i" arity="1" clause_i="2"/>
- <name name="i" arity="1" clause_i="3"/>
- <fsummary>Get all logger configurations</fsummary>
+ <name name="add_handler_filter" arity="3"/>
+ <fsummary>Add a filter to the specified handler.</fsummary>
<desc>
- <p>Display or return all current logger configuration.</p>
- <taglist>
- <tag><c><anno>Action</anno> = string</c></tag>
- <item>
- <p>Return the pretty printed current logger configuration
- as iodata.</p>
- </item>
- <tag><c><anno>Action</anno> = term</c></tag>
- <item>
- <p>Return the current logger configuration as a term. The
- format of this term may change inbetween releases. For a
- stable format use <seealso marker="#get_handler_config/1">
- <c>logger:get_handler_config/1</c></seealso>
- and <seealso marker="#get_logger_config/0">
- <c>logger:get_logger_config/0</c></seealso>.
- The same as calling <c>logger:i()</c>.</p>
- </item>
- <tag><c><anno>Action</anno> = print</c></tag>
- <item>
- <p>Pretty print all the current logger configuration to
- standard out. Example:</p>
- <code><![CDATA[1> logger:i(print).
-Current logger configuration:
- Level: info
- FilterDefault: log
- Filters:
- Handlers:
- Id: logger_std_h
- Module: logger_std_h
- Level: info
- Formatter:
- Module: logger_formatter
- Config: #{template => [{logger_formatter,header},"\n",msg,"\n"],
- legacy_header => true}
- Filter Default: stop
- Filters:
- Id: stop_progress
- Fun: fun logger_filters:progress/2
- Config: stop
- Id: remote_gl
- Fun: fun logger_filters:remote_gl/2
- Config: stop
- Id: domain
- Fun: fun logger_filters:domain/2
- Config: {log,prefix_of,[beam,erlang,otp,sasl]}
- Id: no_domain
- Fun: fun logger_filters:domain/2
- Config: {log,no_domain,[]}
- Handler Config:
- logger_std_h: #{type => standard_io}
- Level set per module:
- Module: my_module
- Level: debug]]></code>
- </item>
- </taglist>
- </desc>
- </func>
-
- <func>
- <name name="add_logger_filter" arity="2"/>
- <fsummary>Add a filter to the logger.</fsummary>
- <desc>
- <p>Add a filter to the logger.</p>
+ <p>Add a filter to the specified handler.</p>
<p>The filter fun is called with the log event as the first
parameter, and the specified <c>filter_args()</c> as the
second parameter.</p>
<p>The return value of the fun specifies if a log event is to
- be discarded or forwarded to the handlers:</p>
+ be discarded or forwarded to the handler callback:</p>
<taglist>
- <tag><c>log()</c></tag>
+ <tag><c>log_event()</c></tag>
<item>
- <p>The filter <em>passed</em>. The next logger filter, if
- any, is applied. If no more logger filters exist, the
- log event is forwarded to the handler part of the
- logger, where handler filters are applied.</p>
+ <p>The filter <em>passed</em>. The next handler filter, if
+ any, is applied. If no more filters exist for this
+ handler, the log event is forwarded to the handler
+ callback.</p>
</item>
<tag><c>stop</c></tag>
<item>
@@ -408,38 +481,91 @@ Current logger configuration:
<tag><c>ignore</c></tag>
<item>
<p>The filter has no knowledge of the log event. The next
- logger filter, if any, is applied. If no more logger
- filters exist, the value of the <c>filter_default</c>
- configuration parameter for the logger specifies if the
- log event shall be discarded or forwarded to the handler
- part.</p>
+ handler filter, if any, is applied. If no more filters
+ exist for this handler, the value of
+ the <c>filter_default</c> configuration parameter for
+ the handler specifies if the log event shall be
+ discarded or forwarded to the handler callback.</p>
</item>
</taglist>
- <p>See section <seealso marker="logger_chapter#Filter">
- Filter</seealso> in the User's Guide for more information
- about filters.</p>
- <p>Some built-in filters exist. These are defined
- in <seealso marker="logger_filters"><c>logger_filters</c></seealso>.</p>
+ <p>See
+ section <seealso marker="logger_chapter#filters">Filters</seealso>
+ in the User's Guide for more information about filters.</p>
+ <p>Some built-in filters exist. These are defined in
+ <seealso marker="logger_filters"><c>logger_filters</c></seealso>.</p>
</desc>
</func>
<func>
- <name name="add_handler_filter" arity="3"/>
- <fsummary>Add a filter to the specified handler.</fsummary>
+ <name name="add_handlers" arity="1" clause_i="1"/>
+ <fsummary>Set up log handlers from the application's
+ configuration parameters.</fsummary>
<desc>
- <p>Add a filter to the specified handler.</p>
+ <p>Reads the application configuration parameter <c>logger</c> and
+ calls <c>add_handlers/1</c> with its contents.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="add_handlers" arity="1" clause_i="2"/>
+ <fsummary>Setup logger handlers.</fsummary>
+ <type name="config_handler"/>
+ <desc>
+ <p>This function should be used by custom Logger handlers to make
+ configuration consistent no matter which handler the system uses.
+ Normal usage is to add a call to <c>logger:add_handlers/1</c>
+ just after the processes that the handler needs are started,
+ and pass the application's <c>logger</c> configuration as the argument.
+ For example:</p>
+ <code>
+-behaviour(application).
+start(_, []) ->
+ case supervisor:start_link({local, my_sup}, my_sup, []) of
+ {ok, Pid} ->
+ ok = logger:add_handlers(my_app),
+ {ok, Pid, []};
+ Error -> Error
+ end.</code>
+ <p>This reads the <c>logger</c> configuration parameter from
+ the <c>my_all</c> application and starts the configured
+ handlers. The contents of the configuration use the same
+ rules as the
+ <seealso marker="logger_chapter#handler-configuration">logger handler configuration</seealso>.
+ </p>
+ <p>If the handler is meant to replace the default handler, the Kernel's
+ default handler have to be disabled before the new handler is added.
+ A <c>sys.config</c> file that disables the Kernel handler and adds
+ a custom handler could look like this:</p>
+ <code>
+[{kernel,
+ [{logger,
+ %% Disable the default Kernel handler
+ [{handler, default, undefined}]}]},
+ {my_app,
+ [{logger,
+ %% Enable this handler as the default
+ [{handler, default, my_handler, #{}}]}]}].
+ </code>
+ </desc>
+ </func>
+
+ <func>
+ <name name="add_primary_filter" arity="2"/>
+ <fsummary>Add a primary filter to Logger.</fsummary>
+ <desc>
+ <p>Add a primary filter to Logger.</p>
<p>The filter fun is called with the log event as the first
parameter, and the specified <c>filter_args()</c> as the
second parameter.</p>
<p>The return value of the fun specifies if a log event is to
- be discarded or forwarded to the handler callback:</p>
+ be discarded or forwarded to the handlers:</p>
<taglist>
- <tag><c>log()</c></tag>
+ <tag><c>log_event()</c></tag>
<item>
- <p>The filter <em>passed</em>. The next handler filter, if
- any, is applied. If no more filters exist for this
- handler, the log event is forwarded to the handler
- callback.</p>
+ <p>The filter <em>passed</em>. The next primary filter, if
+ any, is applied. If no more primary filters exist, the
+ log event is forwarded to the handler part of Logger,
+ where handler filters are applied.</p>
</item>
<tag><c>stop</c></tag>
<item>
@@ -449,131 +575,134 @@ Current logger configuration:
<tag><c>ignore</c></tag>
<item>
<p>The filter has no knowledge of the log event. The next
- handler filter, if any, is applied. If no more filters
- exist for this handler, the value of
- the <c>filter_default</c> configuration parameter for
- the handler specifies if the log event shall be
- discarded or forwarded to the handler callback.</p>
+ primary filter, if any, is applied. If no more primary
+ filters exist, the value of the
+ primary <c>filter_default</c> configuration parameter
+ specifies if the log event shall be discarded or
+ forwarded to the handler part.</p>
</item>
</taglist>
- <p>See
- section <seealso marker="logger_chapter#Filter">Filter</seealso>
- in the User's Guide for more information about filters.</p>
- <p>Some built-in filters exist. These are defined in
- <seealso marker="logger_filters"><c>logger_filters</c></seealso>.</p>
+ <p>See section <seealso marker="logger_chapter#filters">
+ Filters</seealso> in the User's Guide for more information
+ about filters.</p>
+ <p>Some built-in filters exist. These are defined
+ in <seealso marker="logger_filters"><c>logger_filters</c></seealso>.</p>
</desc>
</func>
<func>
- <name name="remove_logger_filter" arity="1"/>
- <fsummary>Remove a filter from the logger.</fsummary>
+ <name name="get_config" arity="0"/>
+ <fsummary>Look up the current Logger configuration</fsummary>
<desc>
- <p>Remove the filter identified
- by <c><anno>FilterId</anno></c> from the logger.</p>
+ <p>Look up all current Logger configuration, including primary
+ and handler configuration, and module level settings.</p>
</desc>
</func>
<func>
- <name name="remove_handler_filter" arity="2"/>
- <fsummary>Remove a filter from the specified handler.</fsummary>
+ <name name="get_handler_config" arity="0"/>
+ <fsummary>Look up the current configuration for all handlers.</fsummary>
<desc>
- <p>Remove the filter identified
- by <c><anno>FilterId</anno></c> from the handler identified
- by <c><anno>HandlerId</anno></c>.</p>
+ <p>Look up the current configuration for all handlers.</p>
</desc>
</func>
<func>
- <name name="add_handler" arity="3"/>
- <fsummary>Add a handler with the given configuration.</fsummary>
+ <name name="get_handler_config" arity="1"/>
+ <fsummary>Look up the current configuration for the given
+ handler.</fsummary>
<desc>
- <p>Add a handler with the given configuration.</p>
- <p><c><anno>HandlerId</anno></c> is a unique identifier which
- must be used in all subsequent calls reffering to this
- handler.</p>
+ <p>Look up the current configuration for the given handler.</p>
</desc>
</func>
<func>
- <name name="remove_handler" arity="1"/>
- <fsummary>Remove the handler with the specified identity.</fsummary>
+ <name name="get_handler_ids" arity="0"/>
+ <fsummary>Look up the identities for all installed handlers.</fsummary>
<desc>
- <p>Remove the handler identified by <c><anno>HandlerId</anno></c>.</p>
+ <p>Look up the identities for all installed handlers.</p>
</desc>
</func>
<func>
- <name name="set_module_level" arity="2"/>
- <fsummary>Set the log level for the specified module.</fsummary>
+ <name name="get_primary_config" arity="0"/>
+ <fsummary>Look up the current primary configuration for Logger.</fsummary>
<desc>
- <p>Set the log level for the
- specified <c><anno>Module</anno></c>.</p>
- <p>The log level for a module overrides the global log level
- of the logger for log event originating from the module in
- question. Notice, however, that it does not override the
- level configuration for any handler.</p>
- <p>For example: Assume that the global log level for the
- logger is <c>info</c>, and there is one handler, <c>h1</c>,
- with level <c>info</c> and one handler, <c>h2</c>, with
- level <c>debug</c>.</p>
- <p>With this configuration, no debug messages will be logged,
- since they are all stopped by the global log level.</p>
- <p>If the level for <c>mymodule</c> is set now set
- to <c>debug</c>, then debug events from this module will be
- logged by the handler <c>h2</c>, but not by
- handler <c>h1</c>.</p>
- <p>Debug events from other modules are still not logged.</p>
- <p>To change the global log level for the logger, use
- <seealso marker="#set_logger_config/2">
- <c>logger:set_logger_config(level,Level)</c></seealso>.</p>
- <p>To change the log level for a handler, use
- <seealso marker="#set_handler_config/3">
- <c>logger:set_handler_config(HandlerId,level,Level)</c></seealso>.</p>
- <note>
- <p>The originating module for a log event is only detected
- if <c>mfa=>{Module,Function,Arity}</c> exists in the
- metadata. When log macros are used, this association is
- automatically added to all log events. If the logger API
- is called directly, without using a macro, the logging
- client must explicitly add this information.</p>
- </note>
+ <p>Look up the current primary configuration for Logger.</p>
</desc>
</func>
<func>
- <name name="reset_module_level" arity="1"/>
- <fsummary>Remove a module specific log setting.</fsummary>
+ <name name="get_module_level" arity="0"/>
+ <fsummary>Look up all current module levels.</fsummary>
<desc>
- <p>Remove a module specific log setting. After this, the
- global log level is used for the specified module.</p>
+ <p>Look up all current module levels. Returns a list
+ containing one <c>{Module,Level}</c> element for each module
+ for which the module level was previously set
+ with <seealso marker="#set_module_level-2">
+ <c>set_module_level/2</c></seealso>.</p>
</desc>
</func>
<func>
- <name name="set_logger_config" arity="1"/>
- <fsummary>Set configuration data for the logger.</fsummary>
+ <name name="get_module_level" arity="1"/>
+ <fsummary>Look up the current level for the given modules.</fsummary>
<desc>
- <p>Set configuration data for the logger. This overwrites the
- current logger configuration.</p>
- <p>To modify the existing configuration,
- use <seealso marker="#set_logger_config-2"><c>set_logger_config/2</c>
- </seealso>, or read the current configuration
- with <seealso marker="#get_logger_config-0"><c>get_logger_config/0</c>
- </seealso>, then merge in your added or updated
- associations before writing it back.</p>
- <p>If a key is removed compared to the current configuration,
- the default value is used.</p>
+ <p>Look up the current level for the given modules. Returns a
+ list containing one <c>{Module,Level}</c> element for each
+ of the given modules for which the module level was
+ previously set with <seealso marker="#set_module_level-2">
+ <c>set_module_level/2</c></seealso>.</p>
</desc>
</func>
<func>
- <name name="set_logger_config" arity="2"/>
- <fsummary>Add or update configuration data for the logger.</fsummary>
+ <name name="get_process_metadata" arity="0"/>
+ <fsummary>Retrieve data set with set_process_metadata/1.</fsummary>
<desc>
- <p>Add or update configuration data for the logger. If the
- given <c><anno>Key</anno></c> already exists, its associated
- value will be changed to <c><anno>Value</anno></c>. If it
- doesn't exist, it will be added.</p>
+ <p>Retrieve data set
+ with <seealso marker="#set_process_metadata-1">
+ <c>set_process_metadata/1</c></seealso> or
+ <seealso marker="#update_process_metadata-1">
+ <c>update_process_metadata/1</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="remove_handler" arity="1"/>
+ <fsummary>Remove the handler with the specified identity.</fsummary>
+ <desc>
+ <p>Remove the handler identified by <c><anno>HandlerId</anno></c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="remove_handler_filter" arity="2"/>
+ <fsummary>Remove a filter from the specified handler.</fsummary>
+ <desc>
+ <p>Remove the filter identified
+ by <c><anno>FilterId</anno></c> from the handler identified
+ by <c><anno>HandlerId</anno></c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="remove_primary_filter" arity="1"/>
+ <fsummary>Remove a primary filter from Logger.</fsummary>
+ <desc>
+ <p>Remove the primary filter identified
+ by <c><anno>FilterId</anno></c> from Logger.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="set_application_level" arity="2"/>
+ <fsummary>Set the log level for all modules in the specified application.</fsummary>
+ <desc>
+ <p>Set the log level for all the modules of the specified application.</p>
+ <p>This function is a convenience function that calls
+ <seealso marker="#set_module_level/2">logger:set_module_level/2</seealso>
+ for each module associated with an application.</p>
</desc>
</func>
@@ -584,13 +713,14 @@ Current logger configuration:
<p>Set configuration data for the specified handler. This
overwrites the current handler configuration.</p>
<p>To modify the existing configuration,
- use <seealso marker="#set_handler_config-3"><c>set_handler_config/3</c>
- </seealso>, or read the current configuration
+ use <seealso marker="#update_handler_config-2">
+ <c>update_handler_config/2</c></seealso>, or, if a more
+ complex merge is needed, read the current configuration
with <seealso marker="#get_handler_config-1"><c>get_handler_config/1</c>
- </seealso>, then merge in your added or updated
- associations before writing it back.</p>
+ </seealso>, then do the merge before writing the new
+ configuration back with this function.</p>
<p>If a key is removed compared to the current configuration,
- and the key is know by Logger, the default value is used. If
+ and the key is known by Logger, the default value is used. If
it is a custom key, then it is up to the handler
implementation if the value is removed or a default value is
inserted.</p>
@@ -598,26 +728,104 @@ Current logger configuration:
</func>
<func>
- <name name="set_handler_config" arity="3"/>
+ <name name="set_handler_config" arity="3" clause_i="1"/>
+ <name name="set_handler_config" arity="3" clause_i="2"/>
+ <name name="set_handler_config" arity="3" clause_i="3"/>
+ <name name="set_handler_config" arity="3" clause_i="4"/>
+ <name name="set_handler_config" arity="3" clause_i="5"/>
<fsummary>Add or update configuration data for the specified
handler.</fsummary>
+ <type variable="HandlerId"/>
+ <type variable="Level" name_i="1"/>
+ <type variable="FilterDefault" name_i="2"/>
+ <type variable="Filters" name_i="3"/>
+ <type variable="Formatter" name_i="4"/>
+ <type variable="Config" name_i="5"/>
+ <type variable="Return"/>
<desc>
<p>Add or update configuration data for the specified
handler. If the given <c><anno>Key</anno></c> already
exists, its associated value will be changed
- to <c><anno>Value</anno></c>. If it doesn't exist, it will
+ to the given value. If it does not exist, it will
be added.</p>
+ <p>See the definition of
+ the <seealso marker="#type-handler_config">
+ <c>handler_config()</c></seealso> type for more
+ information about the different parameters.</p>
</desc>
</func>
<func>
- <name name="compare_levels" arity="2"/>
- <fsummary>Compare the severity of two log levels.</fsummary>
+ <name name="set_primary_config" arity="1"/>
+ <fsummary>Set primary configuration data for Logger.</fsummary>
<desc>
- <p>Compare the severity of two log levels. Returns <c>gt</c>
- if <c>Level1</c> is more severe than
- <c>Level2</c>, <c>lt</c> if <c>Level1</c> is less severe,
- and <c>eq</c> if the levels are equal.</p>
+ <p>Set primary configuration data for Logger. This
+ overwrites the current configuration.</p>
+ <p>To modify the existing configuration,
+ use <seealso marker="#update_primary_config-1">
+ <c>update_primary_config/1</c></seealso>, or, if a more
+ complex merge is needed, read the current configuration
+ with <seealso marker="#get_primary_config-0"><c>get_primary_config/0</c>
+ </seealso>, then do the merge before writing the new
+ configuration back with this function.</p>
+ <p>If a key is removed compared to the current configuration,
+ the default value is used.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="set_primary_config" arity="2" clause_i="1"/>
+ <name name="set_primary_config" arity="2" clause_i="2"/>
+ <name name="set_primary_config" arity="2" clause_i="3"/>
+ <fsummary>Add or update primary configuration data for Logger.</fsummary>
+ <type variable="Level" name_i="1"/>
+ <type variable="FilterDefault" name_i="2"/>
+ <type variable="Filters" name_i="3"/>
+ <desc>
+ <p>Add or update primary configuration data for Logger. If the
+ given <c><anno>Key</anno></c> already exists, its associated
+ value will be changed to the given value. If it does not
+ exist, it will be added.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="set_module_level" arity="2"/>
+ <fsummary>Set the log level for the specified modules.</fsummary>
+ <desc>
+ <p>Set the log level for the specified modules.</p>
+ <p>The log level for a module overrides the primary log level
+ of Logger for log events originating from the module in
+ question. Notice, however, that it does not override the
+ level configuration for any handler.</p>
+ <p>For example: Assume that the primary log level for Logger
+ is <c>info</c>, and there is one handler, <c>h1</c>, with
+ level <c>info</c> and one handler, <c>h2</c>, with
+ level <c>debug</c>.</p>
+ <p>With this configuration, no debug messages will be logged,
+ since they are all stopped by the primary log level.</p>
+ <p>If the level for <c>mymodule</c> is now set
+ to <c>debug</c>, then debug events from this module will be
+ logged by the handler <c>h2</c>, but not by
+ handler <c>h1</c>.</p>
+ <p>Debug events from other modules are still not logged.</p>
+ <p>To change the primary log level for Logger, use
+ <seealso marker="#set_primary_config/2">
+ <c>set_primary_config(level, Level)</c></seealso>.</p>
+ <p>To change the log level for a handler, use
+ <seealso marker="#set_handler_config/3">
+ <c>set_handler_config(HandlerId, level, Level)</c>
+ </seealso>.</p>
+ <note>
+ <p>The originating module for a log event is only detected
+ if the key <c>mfa</c> exists in the metadata, and is
+ associated with <c>{Module, Function, Arity}</c>. When log
+ macros are used, this association is automatically added
+ to all log events. If an API function is called directly,
+ without using a macro, the logging client must explicitly
+ add this information if module levels shall have any
+ effect.</p>
+ </note>
</desc>
</func>
@@ -641,6 +849,106 @@ Current logger configuration:
</func>
<func>
+ <name name="unset_application_level" arity="1"/>
+ <fsummary>Unset the log level for all modules in the specified application.</fsummary>
+ <desc>
+ <p>Unset the log level for all the modules of the specified application.</p>
+ <p>This function is a convinience function that calls
+ <seealso marker="#unset_module_level/1">logger:unset_module_level/2</seealso>
+ for each module associated with an application.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="unset_module_level" arity="0"/>
+ <fsummary>Remove module specific log settings for all modules.</fsummary>
+ <desc>
+ <p>Remove module specific log settings. After this, the
+ primary log level is used for all modules.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="unset_module_level" arity="1"/>
+ <fsummary>Remove module specific log settings for the given
+ modules.</fsummary>
+ <desc>
+ <p>Remove module specific log settings. After this, the
+ primary log level is used for the specified modules.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="unset_process_metadata" arity="0"/>
+ <fsummary>Delete data set with set_process_metadata/1.</fsummary>
+ <desc>
+ <p>Delete data set
+ with <seealso marker="#set_process_metadata-1">
+ <c>set_process_metadata/1</c></seealso> or
+ <seealso marker="#update_process_metadata-1">
+ <c>update_process_metadata/1</c></seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="update_formatter_config" arity="2"/>
+ <fsummary>Update the formatter configuration for the specified handler.</fsummary>
+ <desc>
+ <p>Update the formatter configuration for the specified handler.</p>
+ <p>The new configuration is merged with the existing formatter
+ configuration.</p>
+ <p>To overwrite the existing configuration without any merge,
+ use</p>
+ <pre>
+<seealso marker="#set_handler_config-3">set_handler_config(HandlerId, formatter,
+ {FormatterModule, FormatterConfig})</seealso>.</pre>
+ </desc>
+ </func>
+
+ <func>
+ <name name="update_formatter_config" arity="3"/>
+ <fsummary>Update the formatter configuration for the specified handler.</fsummary>
+ <desc>
+ <p>Update the formatter configuration for the specified handler.</p>
+ <p>This is equivalent to</p>
+ <pre>
+<seealso marker="#update_formatter_config-2">update_formatter_config(<anno>HandlerId</anno>, #{<anno>Key</anno> => <anno>Value</anno>})</seealso></pre>
+ </desc>
+ </func>
+
+ <func>
+ <name name="update_handler_config" arity="2"/>
+ <fsummary>Update configuration data for the specified handler.</fsummary>
+ <desc>
+ <p>Update configuration data for the specified handler. This function
+ behaves as if it was implemented as follows:</p>
+ <code type="erl">
+{ok, {_, Old}} = logger:get_handler_config(HandlerId),
+logger:set_handler_config(HandlerId, maps:merge(Old, Config)).
+ </code>
+ <p>To overwrite the existing configuration without any merge,
+ use <seealso marker="#set_handler_config-2"><c>set_handler_config/2</c>
+ </seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="update_primary_config" arity="1"/>
+ <fsummary>Update primary configuration data for Logger.</fsummary>
+ <desc>
+ <p>Update primary configuration data for Logger. This function
+ behaves as if it was implemented as follows:</p>
+ <code type="erl">
+Old = logger:get_primary_config(),
+logger:set_primary_config(maps:merge(Old, Config)).
+ </code>
+ <p>To overwrite the existing configuration without any merge,
+ use <seealso marker="#set_primary_config-1"><c>set_primary_config/1</c>
+ </seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
<name name="update_process_metadata" arity="1"/>
<fsummary>Set or update metadata to use when logging from
current process.</fsummary>
@@ -650,7 +958,7 @@ Current logger configuration:
<p>If process metadata exists for the current process, this
function behaves as if it was implemented as follows:</p>
<code type="erl">
-logger:set_process_metadata(maps:merge(logger:get_process_metadata(),Meta))
+logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)).
</code>
<p>If no process metadata exists, the function behaves as
<seealso marker="#set_process_metadata-1">
@@ -658,72 +966,71 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(),Meta))
</seealso>.</p>
</desc>
</func>
+ </funcs>
+ <section>
+ <marker id="misc_API"/>
+ <title>Miscellaneous API functions</title>
+ </section>
+ <funcs>
<func>
- <name name="get_process_metadata" arity="0"/>
- <fsummary>Retrieve data set with set_process_metadata/1.</fsummary>
- <desc>
- <p>Retrieve data set
- with <seealso marker="#set_process_metadata-1">
- <c>set_process_metadata/1</c></seealso> or
- <seealso marker="#update_process_metadata-1">
- <c>update_process_metadata/1</c></seealso>.</p>
- </desc>
- </func>
-
- <func>
- <name name="unset_process_metadata" arity="0"/>
- <fsummary>Delete data set with set_process_metadata/1.</fsummary>
+ <name name="compare_levels" arity="2"/>
+ <fsummary>Compare the severity of two log levels.</fsummary>
<desc>
- <p>Delete data set
- with <seealso marker="#set_process_metadata-1">
- <c>set_process_metadata/1</c></seealso> or
- <seealso marker="#update_process_metadata-1">
- <c>update_process_metadata/1</c></seealso>.</p>
+ <p>Compare the severity of two log levels. Returns <c>gt</c>
+ if <c>Level1</c> is more severe than
+ <c>Level2</c>, <c>lt</c> if <c>Level1</c> is less severe,
+ and <c>eq</c> if the levels are equal.</p>
</desc>
</func>
<func>
<name name="format_report" arity="1"/>
- <fsummary>Convert a log message on report form to {Format,Args}.</fsummary>
+ <fsummary>Convert a log message on report form to {Format, Args}.</fsummary>
<desc>
- <p>Convert a log message on report form to <c>{Format,Args}</c>.</p>
- <p>This is the default report callback used
+ <p>Convert a log message on report form to <c>{Format,
+ Args}</c>. This is the default report callback used
by <seealso marker="logger_formatter">
<c>logger_formatter</c></seealso> when no custom report
- callback is found.</p>
+ callback is found. See
+ section <seealso marker="logger_chapter#log_message">Log
+ Message</seealso> in the Kernel User's Guide for
+ information about report callbacks and valid forms of log
+ messages.</p>
<p>The function produces lines of <c>Key: Value</c> from
key-value lists. Strings are printed with <c>~ts</c> and
other terms with <c>~tp</c>.</p>
- <p>If the <c><anno>Report</anno></c> is a map, it is
- converted to a key-value list before formatting as such.</p>
+ <p>If <c><anno>Report</anno></c> is a map, it is converted to
+ a key-value list before formatting as such.</p>
</desc>
</func>
-
</funcs>
<section>
- <title>Callback Functions</title>
+ <marker id="handler_callback_functions"/>
+ <title>Handler Callback Functions</title>
<p>The following functions are to be exported from a handler
callback module.</p>
</section>
<funcs>
<func>
- <name>Module:adding_handler(HandlerId,Config1) -> {ok,Config2} | {error,Reason}</name>
+ <name>HModule:adding_handler(Config1) -> {ok, Config2} | {error,
+ Reason}</name>
<fsummary>An instance of this handler is about to be added.</fsummary>
<type>
- <v>HandlerId =
- <seealso marker="#type-handler_id">handler_id()</seealso></v>
<v>Config1 = Config2 =
- <seealso marker="#type-config">config()</seealso></v>
+ <seealso marker="#type-handler_config">handler_config()</seealso></v>
<v>Reason = term()</v>
</type>
<desc>
<p>This callback function is optional.</p>
- <p>The function is called when an new handler is about to be
- added, and the purpose is to verify the configuration and
- initiate all resourced needed by the handler.</p>
+ <p>The function is called on a temporary process when an new
+ handler is about to be added. The purpose is to verify the
+ configuration and initiate all resources needed by the
+ handler.</p>
+ <p>The handler identity is associated with the <c>id</c> key
+ in <c>Config1</c>.</p>
<p>If everything succeeds, the callback function can add
possible default values or internal state values to the
configuration, and return the adjusted map
@@ -734,46 +1041,150 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(),Meta))
</func>
<func>
- <name>Module:removing_handler(HandlerId,Config) -> ok</name>
+ <name>HModule:changing_config(Config1, Config2) -> {ok, Config3} | {error, Reason}</name>
+ <fsummary>The configuration for this handler is about to change.</fsummary>
+ <type>
+ <v>Config1 = Config2 = Config3 =
+ <seealso marker="#type-handler_config">handler_config()</seealso></v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>This callback function is optional.</p>
+ <p>The function is called on a temporary process when the
+ configuration for a handler is about to change. The purpose
+ is to verify and act on the new configuration.</p>
+ <p><c>Config1</c> is the existing configuration
+ and <c>Config2</c> is the new configuration.</p>
+ <p>The handler identity is associated with the <c>id</c> key
+ in <c>Config1</c>.</p>
+ <p>If everything succeeds, the callback function must return a
+ possibly adjusted configuration in <c>{ok,Config3}</c>.</p>
+ <p>If the configuration is faulty, the callback function must
+ return <c>{error,Reason}</c>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>HModule:log(LogEvent, Config) -> void()</name>
+ <fsummary>Log the given log event.</fsummary>
+ <type>
+ <v>LogEvent =
+ <seealso marker="#type-log_event">log_event()</seealso></v>
+ <v>Config =
+ <seealso marker="#type-handler_config">handler_config()</seealso></v>
+ </type>
+ <desc>
+ <p>This callback function is mandatory.</p>
+ <p>The function is called when all primary filters and all
+ handler filters for the handler in question have passed for
+ the given log event. It is called on the client process, that
+ is, the process that issued the log event.</p>
+ <p>The handler identity is associated with the <c>id</c> key
+ in <c>Config</c>.</p>
+ <p>The handler must log the event.</p>
+ <p>The return value from this function is ignored by
+ Logger.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>HModule:removing_handler(Config) -> ok</name>
<fsummary>The given handler is about to be removed.</fsummary>
<type>
- <v>HandlerId =
- <seealso marker="#type-handler_id">handler_id()</seealso></v>
<v>Config =
- <seealso marker="#type-config">config()</seealso></v>
+ <seealso marker="#type-handler_config">handler_config()</seealso></v>
</type>
<desc>
<p>This callback function is optional.</p>
- <p>The function is called when a handler is about to be
- removed, and the purpose is to release all resources used by
- the handler. The return value is ignored by Logger.</p>
+ <p>The function is called on a temporary process when a
+ handler is about to be removed. The purpose is to release
+ all resources used by the handler.</p>
+ <p>The handler identity is associated with the <c>id</c> key
+ in <c>Config</c>.</p>
+ <p>The return value is ignored by Logger.</p>
</desc>
</func>
+ </funcs>
+
+ <section>
+ <marker id="formatter_callback_functions"/>
+ <title>Formatter Callback Functions</title>
+ <p>The following functions are to be exported from a formatter
+ callback module.</p>
+ </section>
+
+ <funcs>
<func>
- <name>Module:changing_config(HandlerId,Config1,Config2) -> {ok,Config3} | {error,Reason}</name>
- <fsummary>The configuration for this handler is about to change.</fsummary>
+ <name>FModule:check_config(FConfig) -> ok | {error, Reason}</name>
+ <fsummary>Validate the given formatter configuration.</fsummary>
<type>
- <v>HandlerId =
- <seealso marker="#type-handler_id">handler_id()</seealso></v>
- <v>Config1 = Config2 = Config3 =
- <seealso marker="#type-config">config()</seealso></v>
+ <v>FConfig =
+ <seealso marker="#type-formatter_config">formatter_config()</seealso></v>
<v>Reason = term()</v>
</type>
<desc>
<p>This callback function is optional.</p>
- <p>The function is called when the configuration for a handler
- is about to change, and the purpose is to verify and act on
- the new configuration.</p>
- <p><c>Config1</c> is the existing configuration
- and <c>Config2</c> is the new configuration.</p>
- <p>If everything succeeds, the callback function must return a
- possibly adjusted configuration in <c>{ok,Config3}</c>.</p>
- <p>If the configuration is faulty, the callback function must
- return <c>{error,Reason}</c>.</p>
+ <p>The function is called by a Logger when formatter
+ configuration is set or modified. The formatter must
+ validate the given configuration and return <c>ok</c> if it
+ is correct, and <c>{error,Reason}</c> if it is faulty.</p>
+ <p>The following Logger API functions can trigger this callback:</p>
+ <list>
+ <item><seealso marker="logger#add_handler-3">
+ <c>logger:add_handler/3</c></seealso></item>
+ <item><seealso marker="logger#set_handler_config-2">
+ <c>logger:set_handler_config/2,3</c></seealso></item>
+ <item><seealso marker="logger#update_handler_config-2">
+ <c>logger:updata_handler_config/2</c></seealso></item>
+ <item><seealso marker="logger#update_formatter_config-2">
+ <c>logger:update_formatter_config/2</c></seealso></item>
+ </list>
+ <p>See <seealso marker="logger_formatter">
+ <c>logger_formatter(3)</c></seealso>
+ for an example implementation. <c>logger_formatter</c> is the
+ default formatter used by Logger.</p>
+ </desc>
+ </func>
+ <func>
+ <name>FModule:format(LogEvent, FConfig) -> FormattedLogEntry</name>
+ <fsummary>Format the given log event.</fsummary>
+ <type>
+ <v>LogEvent =
+ <seealso marker="#type-log_event">log_event()</seealso></v>
+ <v>FConfig =
+ <seealso marker="#type-formatter_config">formatter_config()</seealso></v>
+ <v>FormattedLogEntry =
+ <seealso marker="unicode#type-chardata">unicode:chardata()</seealso></v>
+ </type>
+ <desc>
+ <p>This callback function is mandatory.</p>
+ <p>The function can be called by a log handler to convert a
+ log event term to a printable string. The returned value
+ can, for example, be printed as a log entry to the console
+ or a file using <seealso marker="stdlib:io#put_chars-1">
+ <c>io:put_chars/1,2</c></seealso>.</p>
+ <p>See <seealso marker="logger_formatter">
+ <c>logger_formatter(3)</c></seealso>
+ for an example implementation. <c>logger_formatter</c> is the
+ default formatter used by Logger.</p>
</desc>
</func>
</funcs>
+
+ <section>
+ <title>See Also</title>
+ <p>
+ <seealso marker="config"><c>config(4)</c></seealso>,
+ <seealso marker="erts:erlang"><c>erlang(3)</c></seealso>,
+ <seealso marker="stdlib:io"><c>io(3)</c></seealso>,
+ <seealso marker="logger_disk_log_h"><c>logger_disk_log_h(3)</c></seealso>,
+ <seealso marker="logger_filters"><c>logger_filters(3)</c></seealso>,
+ <seealso marker="logger_formatter"><c>logger_formatter(3)</c></seealso>,
+ <seealso marker="logger_std_h"><c>logger_std_h(3)</c></seealso>,
+ <seealso marker="stdlib:unicode"><c>unicode(3)</c></seealso>
+ </p>
+ </section>
</erlref>
diff --git a/lib/kernel/doc/src/logger_arch.dia b/lib/kernel/doc/src/logger_arch.dia
new file mode 100644
index 0000000000..97be31856e
--- /dev/null
+++ b/lib/kernel/doc/src/logger_arch.dia
Binary files differ
diff --git a/lib/kernel/doc/src/logger_arch.png b/lib/kernel/doc/src/logger_arch.png
index 727609a6ef..70933a5a41 100644
--- a/lib/kernel/doc/src/logger_arch.png
+++ b/lib/kernel/doc/src/logger_arch.png
Binary files differ
diff --git a/lib/kernel/doc/src/logger_chapter.xml b/lib/kernel/doc/src/logger_chapter.xml
index 519df2ba48..c2cdf38a64 100644
--- a/lib/kernel/doc/src/logger_chapter.xml
+++ b/lib/kernel/doc/src/logger_chapter.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2017</year>
+ <year>2017</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -30,750 +30,1302 @@
<file>logger_chapter.xml</file>
</header>
+ <p>Erlang/OTP 21.0 provides a standard API for logging
+ through <c>Logger</c>, which is part of the Kernel
+ application. Logger consists of the API for issuing log events,
+ and a customizable backend where log handlers, filters and
+ formatters can be plugged in.</p>
+ <p>By default, the Kernel application installs one log handler at
+ system start. This handler is named <c>default</c>. It receives
+ and processes standard log events produced by the Erlang runtime
+ system, standard behaviours and different Erlang/OTP
+ applications. The log events are by default written to the
+ terminal.</p>
+ <p>You can also configure the system so that the default handler
+ prints log events to a single file, or to a set of wrap logs
+ via <seealso marker="disk_log"><c>disk_log</c></seealso>.</p>
+ <p>By configuration, you can also modify or disable the default
+ handler, replace it by a custom handler, and install additional
+ handlers.</p>
+
+ <note>
+ <p>Since Logger is new in Erlang/OTP 21.0, we do reserve the right
+ to introduce changes to the Logger API and functionality in
+ patches following this release. These changes might or might not
+ be backwards compatible with the initial version.</p>
+ </note>
+
<section>
<title>Overview</title>
- <p>Erlang/OTP provides a standard API for logging. The backend of
- this API can be used as is, or it can be customized to suite
- specific needs.</p>
- <p>It consists of two parts - the <em>logger</em> part and the
- <em>handler</em> part. The logger will forward log events to one
- or more handler(s).</p>
-
+ <p>A <em>log event</em> consists of a <em>log level</em>, the
+ <em>message</em> to be logged, and <em>metadata</em>.</p>
+ <p>The Logger backend forwards log events from the API, first
+ through a set of <em>primary filters</em>, then through a set of
+ secondary filters attached to each log handler. The secondary
+ filters are in the following named <em>handler filters</em>.</p>
+ <p>Each filter set consists of a <em>log level check</em>,
+ followed by zero or more <em>filter functions</em>.</p>
+ <p>The following figure shows a conceptual overview of Logger. The
+ figure shows two log handlers, but any number of handlers can be
+ installed.</p>
+
+ <!-- The image is edited with dia in logger_arch.dia file,
+ and .png file generated with make target 'png'. -->
<image file="logger_arch.png">
- <icaption>Conceptual overview</icaption>
+ <icaption>Conceptual Overview</icaption>
</image>
- <p><em>Filters</em> can be added to the logger and to each
- handler. The filters decide if an event is to be forwarded or
- not, and they can also modify all parts of the log event.</p>
-
- <p>A <em>formatter</em> can be set for each handler. The formatter
- does the final formatting of the log event, including the log
- message itself, and possibly a timestamp, header and other
- metadata.</p>
-
- <p>In accordance with the Syslog protocol, RFC-5424, eight
- severity levels can be specified:</p>
-
- <table align="left">
- <row>
- <cell><strong>Level</strong></cell>
- <cell align="center"><strong>Integer</strong></cell>
- <cell><strong>Description</strong></cell>
- </row>
- <row>
- <cell>emergency</cell>
- <cell align="center">0</cell>
- <cell>system is unusable</cell>
- </row>
- <row>
- <cell>alert</cell>
- <cell align="center">1</cell>
- <cell>action must be taken immediately</cell>
- </row>
- <row>
- <cell>critical</cell>
- <cell align="center">2</cell>
- <cell>critical contidions</cell>
- </row>
- <row>
- <cell>error</cell>
- <cell align="center">3</cell>
- <cell>error conditions</cell>
- </row>
- <row>
- <cell>warning</cell>
- <cell align="center">4</cell>
- <cell>warning conditions</cell>
- </row>
- <row>
- <cell>notice</cell>
- <cell align="center">5</cell>
- <cell>normal but significant conditions</cell>
- </row>
- <row>
- <cell>info</cell>
- <cell align="center">6</cell>
- <cell>informational messages</cell>
- </row>
- <row>
- <cell>debug</cell>
- <cell align="center">7</cell>
- <cell>debug-level messages</cell>
- </row>
- <tcaption>Severity levels</tcaption>
- </table>
-
- <p>A log event is allowed by Logger if the integer value of
- its <c>Level</c> is less than or equal to the currently
- configured log level. The log level can be configured globally,
- or to allow more verbose logging from a specific part of the
- system, per module.</p>
-
+ <p>Log levels are expressed as atoms. Internally in Logger, the
+ atoms are mapped to integer values, and a log event passes the
+ log level check if the integer value of its log level is less
+ than or equal to the currently configured log level. That is,
+ the check passes if the event is equally or more severe than the
+ configured level. See section <seealso marker="#log_level">Log
+ Level</seealso> for a listing and description of all log
+ levels.</p>
+ <p>The primary log level can be overridden by a log level
+ configured per module. This is to, for instance, allow more
+ verbose logging from a specific part of the system.</p>
+ <p>Filter functions can be used for more sophisticated filtering
+ than the log level check provides. A filter function can stop or
+ pass a log event, based on any of the event's contents. It can
+ also modify all parts of the log event. See see
+ section <seealso marker="#filters">Filters</seealso> for more
+ details.</p>
+ <p>If a log event passes through all primary filters and all
+ handler filters for a specific handler, Logger forwards the
+ event to the <em>handler callback</em>. The handler formats and
+ prints the event to its destination. See
+ section <seealso marker="#handlers">Handlers</seealso> for more
+ details.</p>
+ <p>Everything up to and including the call to the handler
+ callbacks is executed on the client process, that is, the
+ process where the log event was issued. It is up to the handler
+ implementation if other processes are involved or not.</p>
+ <p>The handlers are called in sequence, and the order is not
+ defined.</p>
+ </section>
+ <section>
+ <marker id="logger_api"/>
+ <title>Logger API</title>
+ <p>The API for logging consists of a set
+ of <seealso marker="logger#macros">macros</seealso>, and a set
+ of functions on the form <c>logger:Level/1,2,3</c>, which are
+ all shortcuts
+ for <seealso marker="logger#log-2">
+ <c>logger:log(Level,Arg1[,Arg2[,Arg3]])</c></seealso>.</p>
+ <p>The difference between using the macros and the exported
+ functions is that macros add location (originator) information
+ to the metadata, and performs lazy evaluation by wrapping the
+ logger call in a case statement, so it is only evaluated if the
+ log level of the event passes the primary log level check.</p>
<section>
- <title>Customizable parts</title>
-
+ <marker id="log_level"/>
+ <title>Log Level</title>
+ <p>The log level indicates the severity of a event. In
+ accordance with the Syslog protocol,
+ <url href="https://www.ietf.org/rfc/rfc5424.txt">RFC
+ 5424</url>, eight log levels can be specified. The following
+ table lists all possible log levels by name (atom), integer
+ value, and description:</p>
+
+ <table align="left">
+ <row>
+ <cell><strong>Level</strong></cell>
+ <cell align="center"><strong>Integer</strong></cell>
+ <cell><strong>Description</strong></cell>
+ </row>
+ <row>
+ <cell>emergency</cell>
+ <cell align="center">0</cell>
+ <cell>system is unusable</cell>
+ </row>
+ <row>
+ <cell>alert</cell>
+ <cell align="center">1</cell>
+ <cell>action must be taken immediately</cell>
+ </row>
+ <row>
+ <cell>critical</cell>
+ <cell align="center">2</cell>
+ <cell>critical conditions</cell>
+ </row>
+ <row>
+ <cell>error</cell>
+ <cell align="center">3</cell>
+ <cell>error conditions</cell>
+ </row>
+ <row>
+ <cell>warning</cell>
+ <cell align="center">4</cell>
+ <cell>warning conditions</cell>
+ </row>
+ <row>
+ <cell>notice</cell>
+ <cell align="center">5</cell>
+ <cell>normal but significant conditions</cell>
+ </row>
+ <row>
+ <cell>info</cell>
+ <cell align="center">6</cell>
+ <cell>informational messages</cell>
+ </row>
+ <row>
+ <cell>debug</cell>
+ <cell align="center">7</cell>
+ <cell>debug-level messages</cell>
+ </row>
+ <tcaption>Log Levels</tcaption>
+ </table>
+ <p>Notice that the integer value is only used internally in
+ Logger. In the API, you must always use the atom. To compare
+ the severity of two log levels,
+ use <seealso marker="logger#compare_levels-2">
+ <c>logger:compare_levels/2</c></seealso>.</p>
+ </section>
+ <section>
+ <marker id="log_message"/>
+ <title>Log Message</title>
+ <p>The log message contains the information to be logged. The
+ message can consist of a format string and arguments (given as
+ two separate parameters in the Logger API), a string or a
+ report. The latter, which is either a map or a key-value list,
+ can be accompanied by a <em>report callback</em> specified in
+ the log event's <seealso marker="#metadata">metadata</seealso>.
+ The report callback is a convenience function that
+ the <seealso marker="#formatters">formatter</seealso> can use
+ to convert the report to a format string and arguments, or
+ directly to a string. The
+ formatter can also use its own conversion function, if no
+ callback is provided, or if a customized formatting is
+ desired.</p>
+ <p>The report callback must be a fun with one or two
+ arguments. If it takes one argument, this is the report
+ itself, and the fun returns a format string and arguments:</p>
+ <pre>fun((<seealso marker="logger#type-report"><c>logger:report()</c></seealso>) -> {<seealso marker="stdlib:io#type-format"><c>io:format()</c></seealso>,[term()]})</pre>
+ <p>If it takes two arguments, the first is the report, and the
+ second is a map containing extra data that allows direct
+ coversion to a string:</p>
+ <pre>fun((<seealso marker="logger#type-report"><c>logger:report()</c></seealso>,<seealso marker="logger#type-report_cb_config"><c>logger:report_cb_config()</c></seealso>) -> <seealso marker="stdlib:unicode#type-chardata"><c>unicode:chardata()</c></seealso>)
+ </pre>
+ <p>The fun must obey the <c>encoding</c>, <c>depth</c>
+ and <c>chars_limit</c> parameters provided in the second
+ argument, as the formatter cannot do anything useful of these
+ parameters with the returned string. This variant is used when
+ the formatting of the report depends on the size and encoding
+ parameters.</p>
+ <p>Example, format string and arguments:</p>
+ <code>logger:error("The file does not exist: ~ts",[Filename])</code>
+ <p>Example, string:</p>
+ <code>logger:notice("Something strange happened!")</code>
+ <p>Example, report, and metadata with report callback:</p>
+ <code>
+logger:debug(#{got => connection_request, id => Id, state => State},
+ #{report_cb => fun(R) -> {"~p",[R]} end})</code>
+ <p>The log message can also be provided through a fun for lazy
+ evaluation. The fun is only evaluated if the primary log level
+ check passes, and is therefore recommended if it is expensive
+ to generate the message. The lazy fun must return a string, a
+ report, or a tuple with format string and arguments.</p>
+ </section>
+ <section>
+ <title>Metadata</title>
+ <p>Metadata contains additional data associated with a log
+ message. Logger inserts some metadata fields by default, and
+ the client can add custom metadata in two different ways:</p>
<taglist>
- <tag><marker id="Handler"/>Handler</tag>
- <item>
- <p>A handler is defined as a module exporting the following
- function:</p>
-
- <code>log(Log, Config) -> ok</code>
-
- <p>A handler is called by the logger backend after filtering on
- logger level and on handler level for the handler which is
- about to be called. The function call is done on the client
- process, and it is up to the handler implementation if other
- processes are to be involved or not.</p>
-
- <p>Multiple instances of the same handler can be
- added. Configuration is per instance.</p>
-
- </item>
-
- <tag><marker id="Filter"/>Filter</tag>
+ <tag>Set process metadata</tag>
<item>
- <p>Filters can be set on the logger or on a handler. Logger
- filters are applied first, and if passed, the handler filters
- for each handler are applied. The handler plugin is only
- called if all handler filters for the handler in question also
- pass.</p>
-
- <p>A filter is specified as:</p>
-
- <code>{fun((Log,Extra) -> Log | stop | ignore), Extra}</code>
-
- <p>The configuration parameter <c>filter_default</c>
- specifies the behavior if all filters return <c>ignore</c>.
- <c>filter_default</c> is by default set to <c>log</c>.</p>
-
- <p>The <c>Extra</c> parameter may contain any data that the
- filter needs.</p>
+ <p>Process metadata is set and updated
+ with <seealso marker="logger#set_process_metadata-1">
+ <c>logger:set_process_metadata/1</c></seealso>
+ and <seealso marker="logger#update_process_metadata-1">
+ <c>logger:update_process_metadata/1</c></seealso>,
+ respectively. This metadata applies to the process on
+ which these calls are made, and Logger adds the metadata
+ to all log events issued on that process.</p>
</item>
-
- <tag><marker id="Formatter"/>Formatter</tag>
+ <tag>Add metadata to a specific log event</tag>
<item>
- <p>A formatter is defined as a module exporting the following
- function:</p>
-
- <code>format(Log,Extra) -> unicode:chardata()</code>
-
- <p>The formatter plugin is called by each handler, and the
- returned string can be printed to the handler's destination
- (stdout, file, ...).</p>
+ <p>Metadata associated with one specific log event is given
+ as the last parameter to the log macro or Logger API
+ function when the event is issued. For example:</p>
+ <code>?LOG_ERROR("Connection closed",#{context => server})</code>
</item>
-
</taglist>
+ <p>See the description of
+ the <seealso marker="logger#type-metadata">
+ <c>logger:metadata()</c></seealso> type for information
+ about which default keys Logger inserts, and how the different
+ metadata maps are merged.</p>
</section>
+ </section>
+ <section>
+ <marker id="filter"/>
+ <title>Filters</title>
+ <p>Filters can be primary, or attached to a specific
+ handler. Logger calls the primary filters first, and if they all
+ pass, it calls the handler filters for each handler. Logger
+ calls the handler callback only if all filters attached to the
+ handler in question also pass.</p>
+ <p>A filter is defined as:</p>
+ <pre>{FilterFun, Extra}</pre>
+ <p>where <c>FilterFun</c> is a function of arity 2,
+ and <c>Extra</c> is any term. When applying the filter, Logger
+ calls the function with the log event as the first argument,
+ and the value of <c>Extra</c> as the second
+ argument. See <seealso marker="logger#type-filter">
+ <c>logger:filter()</c></seealso> for type definitions.</p>
+ <p>The filter function can return <c>stop</c>, <c>ignore</c> or
+ the (possibly modified) log event.</p>
+ <p>If <c>stop</c> is returned, the log event is immediately
+ discarded. If the filter is primary, no handler filters or
+ callbacks are called. If it is a handler filter, the
+ corresponding handler callback is not called, but the log event
+ is forwarded to filters attached to the next handler, if
+ any.</p>
+ <p>If the log event is returned, the next filter function is
+ called with the returned value as the first argument. That is,
+ if a filter function modifies the log event, the next filter
+ function receives the modified event. The value returned from
+ the last filter function is the value that the handler callback
+ receives.</p>
+ <p>If the filter function returns <c>ignore</c>, it means that it
+ did not recognize the log event, and thus leaves to other
+ filters to decide the event's destiny.</p>
+ <p>The configuration option <c>filter_default</c> specifies the
+ behaviour if all filter functions return <c>ignore</c>, or if no
+ filters exist. <c>filter_default</c> is by default set
+ to <c>log</c>, meaning that if all existing filters ignore a log
+ event, Logger forwards the event to the handler
+ callback. If <c>filter_default</c> is set to <c>stop</c>, Logger
+ discards such events.</p>
+ <p>Primary filters are added
+ with <seealso marker="logger#add_primary_filter-2">
+ <c>logger:add_primary_filter/2</c></seealso>
+ and removed
+ with <seealso marker="logger#remove_primary_filter-1">
+ <c>logger:remove_primary_filter/1</c></seealso>. They can also
+ be added at system start via the Kernel configuration
+ parameter <seealso marker="#logger_parameter"><c>logger</c></seealso>.</p>
+ <p>Handler filters are added
+ with <seealso marker="logger#add_handler_filter-3">
+ <c>logger:add_handler_filter/3</c></seealso>
+ and removed
+ with <seealso marker="logger#remove_handler_filter-2">
+ <c>logger:remove_handler_filter/2</c></seealso>. They can also
+ be specified directly in the configuration when adding a handler
+ with <seealso marker="logger#add_handler/3">
+ <c>logger:add_handler/3</c></seealso>
+ or via the Kernel configuration
+ parameter <seealso marker="#logger_parameter"><c>logger</c></seealso>.</p>
+
+ <p>To see which filters are currently installed in the system,
+ use <seealso marker="logger#get_config-0">
+ <c>logger:get_config/0</c></seealso>,
+ or <seealso marker="logger#get_primary_config-0">
+ <c>logger:get_primary_config/0</c></seealso>
+ and <seealso marker="logger#get_handler_config-1">
+ <c>logger:get_handler_config/1</c></seealso>. Filters are
+ listed in the order they are applied, that is, the first
+ filter in the list is applied first, and so on.</p>
+
+ <p>For convenience, the following built-in filters exist:</p>
- <section>
- <title>Built-in handlers</title>
-
- <taglist>
- <tag><c>logger_std_h</c></tag>
+ <taglist>
+ <tag><seealso marker="logger_filters#domain-2">
+ <c>logger_filters:domain/2</c></seealso></tag>
<item>
- <p>This is the default handler used by OTP. Multiple instances
- can be started, and each instance will write log events to a
- given destination, console or file. Filters can be used for
- selecting which event to send to which handler instance.</p>
+ <p>Provides a way of filtering log events based on a
+ <c>domain</c> field in <c>Metadata</c>.</p>
</item>
-
- <tag><c>logger_disk_log_h</c></tag>
+ <tag><seealso marker="logger_filters#level-2">
+ <c>logger_filters:level/2</c></seealso></tag>
<item>
- <p>This handler behaves much like logger_std_h, except it uses
- <seealso marker="disk_log"><c>disk_log</c></seealso> as its
- destination.</p>
+ <p>Provides a way of filtering log events based on the log
+ level.</p>
</item>
-
- <tag><marker id="ErrorLoggerManager"/><c>error_logger</c></tag>
+ <tag><seealso marker="logger_filters#progress-2">
+ <c>logger_filters:progress/2</c></seealso></tag>
<item>
- <p>This handler is to be used for backwards compatibility
- only. It is not started by default, but will be automatically
- started the first time an event handler is added
- with <seealso marker="error_logger#add_report_handler-1">
- <c>error_logger:add_report_handler/1,2</c></seealso>.</p>
-
- <p>No built-in event handlers exist.</p>
+ <p>Stops or allows progress reports from <c>supervisor</c>
+ and <c>application_controller</c>.</p>
</item>
- </taglist>
- </section>
-
- <section>
- <title>Built-in filters</title>
-
- <taglist>
- <tag><c>logger_filters:domain/2</c></tag>
+ <tag><seealso marker="logger_filters#remote_gl-2">
+ <c>logger_filters:remote_gl/2</c></seealso></tag>
<item>
- <p>This filter provides a way of filtering log events based on a
- <c>domain</c> field <c>Metadata</c>. See
- <seealso marker="logger_filters#domain-2">
- <c>logger_filters:domain/2</c></seealso></p>
+ <p>Stops or allows log events originating from a process
+ that has its group leader on a remote node.</p>
</item>
+ </taglist>
+ </section>
- <tag><c>logger_filters:level/2</c></tag>
- <item>
- <p>This filter provides a way of filtering log events based
- on the log level. See <seealso marker="logger_filters#domain-2">
- <c>logger_filters:domain/2</c></seealso></p>
- </item>
+ <section>
+ <marker id="handlers"/>
+ <title>Handlers</title>
+ <p>A handler is defined as a module exporting at least the
+ following callback function:</p>
+
+ <pre><seealso marker="logger#HModule:log-2">log(LogEvent, Config) -> void()</seealso></pre>
+
+ <p>This function is called when a log event has passed through all
+ primary filters, and all handler filters attached to the handler
+ in question. The function call is executed on the client
+ process, and it is up to the handler implementation if other
+ processes are involved or not.</p>
+
+ <p>Logger allows adding multiple instances of a handler
+ callback. That is, if a callback module implementation allows
+ it, you can add multiple handler instances using the same
+ callback module. The different instances are identified by
+ unique handler identities.</p>
+
+ <p>In addition to the mandatory callback function <c>log/2</c>, a
+ handler module can export the optional callback
+ functions <c>adding_handler/1</c>, <c>changing_config/2</c>
+ and <c>removing_handler/1</c>. See
+ section <seealso marker="logger#handler_callback_functions">Handler
+ Callback Functions</seealso> in the logger(3) manual page for
+ more information about these function.</p>
+
+ <p>The following built-in handlers exist:</p>
- <tag><c>logger_filters:progress/2</c></tag>
- <item>
- <p>This filter matches all progress reports
- from <c>supervisor</c> and <c>application_controller</c>.
- See <seealso marker="logger_filters#progress/2">
- <c>logger_filters:progress/2</c></seealso></p>
- </item>
+ <taglist>
+ <tag><c>logger_std_h</c></tag>
+ <item>
+ <p>This is the default handler used by OTP. Multiple instances
+ can be started, and each instance will write log events to a
+ given destination, terminal or file.</p>
+ </item>
- <tag><c>logger_filters:remote_gl/2</c></tag>
- <item>
- <p>This filter matches all events originating from a process
- that has its group leader on a remote node.
- See <seealso marker="logger_filters#remote_gl/2">
- <c>logger_filters:remote_gl/2</c></seealso></p>
- </item>
- </taglist>
- </section>
+ <tag><c>logger_disk_log_h</c></tag>
+ <item>
+ <p>This handler behaves much like <c>logger_std_h</c>, except it uses
+ <seealso marker="disk_log"><c>disk_log</c></seealso> as its
+ destination.</p>
+ </item>
- <section>
- <title>Default formatter</title>
+ <tag><marker id="ErrorLoggerManager"/><c>error_logger</c></tag>
+ <item>
+ <p>This handler is provided for backwards compatibility
+ only. It is not started by default, but will be
+ automatically started the first time an <c>error_logger</c>
+ event handler is added
+ with <seealso marker="error_logger#add_report_handler-1">
+ <c>error_logger:add_report_handler/1,2</c></seealso>.</p>
+
+ <p>The old <c>error_logger</c> event handlers in STDLIB and
+ SASL still exist, but they are not added by Erlang/OTP 21.0
+ or later.</p>
+ </item>
+ </taglist>
+ </section>
- <p>The default formatter is <c>logger_formatter</c>.
- See <seealso marker="logger_formatter#format-2">
- <c>logger_formatter:format/2</c></seealso>.</p>
- </section>
+ <section>
+ <marker id="formatters"/>
+ <title>Formatters</title>
+ <p>A formatter can be used by the handler implementation to do the
+ final formatting of a log event, before printing to the
+ handler's destination. The handler callback receives the
+ formatter information as part of the handler configuration,
+ which is passed as the second argument
+ to <seealso marker="logger#HModule:log-2">
+ <c>HModule:log/2</c></seealso>.</p>
+ <p>The formatter information consist of a formatter
+ module, <c>FModule</c> and its
+ configuration, <c>FConfig</c>. <c>FModule</c> must export the
+ following function, which can be called by the handler:</p>
+ <pre><seealso marker="logger#FModule:format-2">format(LogEvent,FConfig)
+ -> FormattedLogEntry</seealso></pre>
+ <p>The formatter information for a handler is set as a part of its
+ configuration when the handler is added. It can also be changed
+ during runtime
+ with <seealso marker="logger#set_handler_config-3">
+ <c>logger:set_handler_config(HandlerId,formatter,{FModule,FConfig})</c>
+ </seealso>, which overwrites the current formatter information,
+ or with <seealso marker="logger#update_formatter_config-2">
+ <c>logger:update_formatter_config/2,3</c></seealso>, which
+ only modifies the formatter configuration.</p>
+ <p>If the formatter module exports the optional callback
+ function <seealso marker="logger#FModule:check_config-1">
+ <c>check_config(FConfig)</c></seealso>, Logger calls this
+ function when the formatter information is set or modified, to
+ verify the validity of the formatter configuration.</p>
+ <p>If no formatter information is specified for a handler, Logger
+ uses <c>logger_formatter</c> as default. See
+ the <seealso marker="logger_formatter"><c>logger_formatter(3)</c></seealso>
+ manual page for more information about this module.</p>
</section>
<section>
<title>Configuration</title>
- <section>
- <title>Application environment variables</title>
- <p>See <seealso marker="kernel_app#configuration">Kernel(6)</seealso> for
- information about the application environment variables that can
- be used for configuring logger.</p>
- </section>
+ <p>At system start, Logger is configured through Kernel
+ configuration parameters. The parameters that apply to Logger
+ are described in
+ section <seealso marker="#kernel_config_params">Kernel
+ Configuration Parameters</seealso>. Examples are found in
+ section <seealso marker="#config_examples">Configuration
+ Examples</seealso>.</p>
+ <p>During runtime, Logger configuration is changed via API
+ functions. See
+ section <seealso marker="logger#configuration_API">Configuration
+ API Functions</seealso> in the <c>logger(3)</c> manual page.</p>
<section>
- <title>Logger configuration</title>
-
+ <title>Primary Logger Configuration</title>
+ <p>Logger API functions that apply to the primary Logger
+ configuration are:</p>
+ <list>
+ <item><seealso marker="logger#get_primary_config-0">
+ <c>get_primary_config/0</c></seealso></item>
+ <item><seealso marker="logger#set_primary_config-1">
+ <c>set_primary_config/1,2</c></seealso></item>
+ <item><seealso marker="logger#update_primary_config-1">
+ <c>update_primary_config/1</c></seealso></item>
+ <item><seealso marker="logger#add_primary_filter-2">
+ <c>add_primary_filter/2</c></seealso></item>
+ <item><seealso marker="logger#remove_primary_filter-1">
+ <c>remove_primary_filter/1</c></seealso></item>
+ </list>
+ <p>The primary Logger configuration is a map with the following
+ keys:</p>
<taglist>
- <tag><c>level</c></tag>
+ <tag><marker id="primary_level"/>
+ <c>level = </c><seealso marker="logger#type-level">
+ <c>logger:level()</c></seealso><c> | all | none</c></tag>
<item>
- <p>Specifies the severity level to log.</p>
+ <p>Specifies the primary log level, that is, log event that
+ are equally or more severe than this level, are forwarded
+ to the primary filters. Less severe log events are
+ immediately discarded.</p>
+ <p>See section <seealso marker="#log_level">Log
+ Level</seealso> for a listing and description of
+ possible log levels.</p>
+ <p>The initial value of this option is set by the Kernel
+ configuration parameter <seealso marker="#logger_level">
+ <c>logger_level</c></seealso>. It is changed during
+ runtime with <seealso marker="logger#set_primary_config-2">
+ <c>logger:set_primary_config(level,Level)</c></seealso>.</p>
+ <p>Defaults to <c>info</c>.</p>
</item>
- <tag><c>filters</c></tag>
+ <tag><c>filters = [{FilterId,Filter}]</c></tag>
<item>
- <p>Logger filters are added or removed with
- <seealso marker="logger#add_logger_filter-2">
- <c>logger:add_logger_filter/2</c></seealso> and
- <seealso marker="logger#remove_logger_filter-1">
- <c>logger:remove_logger_filter/1</c></seealso>,
+ <p>Specifies the primary filters.</p>
+ <list>
+ <item><c>FilterId = </c><seealso marker="logger#type-filter_id">
+ <c>logger:filter_id()</c></seealso></item>
+ <item><c>Filter = </c><seealso marker="logger#type-filter">
+ <c>logger:filter()</c></seealso></item>
+ </list>
+ <p>The initial value of this option is set by the Kernel
+ configuration
+ parameter <seealso marker="#logger_parameter"><c>logger</c></seealso>.
+ During runtime, primary filters are added and removed with
+ <seealso marker="logger#add_primary_filter-2">
+ <c>logger:add_primary_filter/2</c></seealso> and
+ <seealso marker="logger#remove_primary_filter-1">
+ <c>logger:remove_primary_filter/1</c></seealso>,
respectively.</p>
- <p>See <seealso marker="#Filter">Filter</seealso> for more
- information.</p>
- <p>By default, no filters exist.</p>
+ <p>See section <seealso marker="#filters">Filters</seealso>
+ for more detailed information.</p>
+ <p>Defaults to <c>[]</c>.</p>
</item>
<tag><c>filter_default = log | stop</c></tag>
<item>
- <p>Specifies what to do with an event if all filters
- return <c>ignore</c>.</p>
- <p>Default is <c>log</c>.</p>
- </item>
- <tag><c>handlers</c></tag>
- <item>
- <p>Handlers are added or removed with
- <seealso marker="logger#add_handler-3">
- <c>logger:add_handler/3</c></seealso> and
- <seealso marker="logger#remove_handler-1">
- <c>logger:remove_handler/1</c></seealso>,
- respectively.</p>
- <p>See <seealso marker="#Handler">Handler</seealso> for more
- information.</p>
+ <p>Specifies what happens to a log event if all filters
+ return <c>ignore</c>, or if no filters exist.</p>
+ <p>See section <seealso marker="#filters">Filters</seealso>
+ for more information about how this option is used.</p>
+ <p>Defaults to <c>log</c>.</p>
</item>
</taglist>
</section>
<section>
<marker id="handler_configuration"/>
- <title>Handler configuration</title>
+ <title>Handler Configuration</title>
+ <p>Logger API functions that apply to handler configuration
+ are:</p>
+ <list>
+ <item><seealso marker="logger#get_handler_config-0">
+ <c>get_handler_config/0,1</c></seealso></item>
+ <item><seealso marker="logger#set_handler_config-2">
+ <c>set_handler_config/2,3</c></seealso></item>
+ <item><seealso marker="logger#update_handler_config-2">
+ <c>update_handler_config/2</c></seealso></item>
+ <item><seealso marker="logger#add_handler_filter-3">
+ <c>add_handler_filter/3</c></seealso></item>
+ <item><seealso marker="logger#remove_handler_filter-2">
+ <c>remove_handler_filter/2</c></seealso></item>
+ <item><seealso marker="logger#update_formatter_config-2">
+ <c>update_formatter_config/2,3</c></seealso></item>
+ </list>
+ <p>The configuration for a handler is a map with the following keys:</p>
<taglist>
- <tag><c>level</c></tag>
+ <tag><c>id = </c><seealso marker="logger#type-handler_id">
+ <c>logger:handler_id()</c></seealso></tag>
+ <item>
+ <p>Automatically inserted by Logger. The value is the same
+ as the <c>HandlerId</c> specified when adding the handler,
+ and it cannot be changed.</p>
+ </item>
+ <tag><c>module = module()</c></tag>
+ <item>
+ <p>Automatically inserted by Logger. The value is the same
+ as the <c>Module</c> specified when adding the handler,
+ and it cannot be changed.</p>
+ </item>
+ <tag><c>level = </c><seealso marker="logger#type-level">
+ <c>logger:level()</c></seealso><c> | all | none</c></tag>
<item>
- <p>Specifies the severity level to log.</p>
+ <p>Specifies the log level for the handler, that is, log
+ events that are equally or more severe than this level,
+ are forwarded to the handler filters for this
+ handler.</p>
+ <p>See section <seealso marker="#log_level">Log
+ Level</seealso> for a listing and description of
+ possible log levels.</p>
+ <p>The log level is specified when adding the handler, or
+ changed during runtime with, for
+ instance, <seealso marker="logger#set_handler_config/3">
+ <c>logger:set_handler_config(HandlerId,level,Level)</c></seealso>.
+ </p>
+ <p>Defaults to <c>all</c>.</p>
</item>
- <tag><c>filters</c></tag>
+ <tag><c>filters = [{FilterId,Filter}]</c></tag>
<item>
- <p>Handler filters can be specified when adding the handler,
- or added or removed later with
+ <p>Specifies the handler filters.</p>
+ <list>
+ <item><c>FilterId = </c><seealso marker="logger#type-filter_id">
+ <c>logger:filter_id()</c></seealso></item>
+ <item><c>Filter = </c><seealso marker="logger#type-filter">
+ <c>logger:filter()</c></seealso></item>
+ </list>
+ <p>Handler filters are specified when adding the handler,
+ or added or removed during runtime with
<seealso marker="logger#add_handler_filter-3">
<c>logger:add_handler_filter/3</c></seealso> and
<seealso marker="logger#remove_handler_filter-2">
<c>logger:remove_handler_filter/2</c></seealso>,
respectively.</p>
- <p>See <seealso marker="#Filter">Filter</seealso> for more
- information.</p>
- <p>By default, no filters exist.</p>
+ <p>See <seealso marker="#filters">Filters</seealso> for more
+ detailed information.</p>
+ <p>Defaults to <c>[]</c>.</p>
</item>
<tag><c>filter_default = log | stop</c></tag>
<item>
- <p>Specifies what to do with an event if all filters
- return <c>ignore</c>.</p>
- <p>Default is <c>log</c>.</p>
+ <p>Specifies what happens to a log event if all filters
+ return <c>ignore</c>, or if no filters exist.</p>
+ <p>See section <seealso marker="#filters">Filters</seealso>
+ for more information about how this option is used.</p>
+ <p>Defaults to <c>log</c>.</p>
+ </item>
+ <tag><c>formatter = {FormatterModule,FormatterConfig}</c></tag>
+ <item>
+ <p>Specifies a formatter that the handler can use for
+ converting the log event term to a printable string.</p>
+ <list>
+ <item><c>FormatterModule = module()</c></item>
+ <item><c>FormatterConfig = </c>
+ <seealso marker="logger#type-formatter_config">
+ <c>logger:formatter_config()</c></seealso></item>
+ </list>
+ <p>The formatter information is specified when adding the
+ handler. The formatter configuration can be changed during
+ runtime
+ with <seealso marker="logger#update_formatter_config-2">
+ <c>logger:update_formatter_config/2,3</c></seealso>,
+ or the complete formatter information can be overwritten
+ with, for
+ instance, <seealso marker="logger#set_handler_config-3">
+ <c>logger:set_handler_config/3</c></seealso>.</p>
+ <p>See
+ section <seealso marker="#formatters">Formatters</seealso>
+ for more detailed information.</p>
+ <p>Defaults
+ to <c>{logger_formatter,DefaultFormatterConfig}</c>. See
+ the <seealso marker="logger_formatter">
+ <c>logger_formatter(3)</c></seealso> manual page for
+ information about this formatter and its default
+ configuration.</p>
</item>
- <tag><c>formatter = {Module::module(),Extra::term()}</c></tag>
+ <tag><c>config = term()</c></tag>
<item>
- <p>See <seealso marker="#Formatter">Formatter</seealso> for more
- information.</p>
- <p>The default module is <seealso marker="logger_formatter">
- <c>logger_formatter</c></seealso>, and <c>Extra</c> is
- it's configuration map.</p>
+ <p>Handler specific configuration, that is, configuration
+ data related to a specific handler implementation.</p>
+ <p>The configuration for the built-in handlers is described
+ in
+ the <seealso marker="logger_std_h"><c>logger_std_h(3)</c></seealso>
+ and
+ <seealso marker="logger_disk_log_h"><c>logger_disk_log_h(3)</c>
+ </seealso> manual pages.</p>
</item>
</taglist>
- <p>Note that <c>level</c> and <c>filters</c> are obeyed by
+ <p>Notice that <c>level</c> and <c>filters</c> are obeyed by
Logger itself before forwarding the log events to each
- handler, while <c>formatter</c> is left to the handler
- implementation. All Logger's built-in handlers will call the
- given formatter before printing.</p>
+ handler, while <c>formatter</c> and all handler specific
+ options are left to the handler implementation.</p>
+ </section>
+
+ <section>
+ <marker id="kernel_config_params"/>
+ <title>Kernel Configuration Parameters</title>
+
+ <p>The following Kernel configuration parameters apply to
+ Logger:</p>
+ <taglist>
+ <tag><marker id="logger_parameter"/><c>logger = [Config]</c></tag>
+ <item>
+ <p>Specifies the configuration
+ for <seealso marker="logger">Logger</seealso>, except the
+ primary log level, which is specified
+ with <seealso marker="#logger_level"><c>logger_level</c></seealso>,
+ and the compatibility
+ with <seealso marker="sasl:error_logging">SASL Error
+ Logging</seealso>, which is specified
+ with <seealso marker="#logger_sasl_compatible">
+ <c>logger_sasl_compatible</c></seealso>.</p>
+ <p>With this parameter, you can modify or disable the default
+ handler, add custom handlers and primary logger filters, and
+ set log levels per module.</p>
+ <p><c>Config</c> is any (zero or more) of the following:</p>
+ <taglist>
+ <tag><c>{handler, default, undefined}</c></tag>
+ <item>
+ <p>Disables the default handler. This allows another
+ application to add its own default handler.</p>
+ <p>Only one entry of this type is allowed.</p>
+ </item>
+ <tag><c>{handler, HandlerId, Module, HandlerConfig}</c></tag>
+ <item>
+ <p>If <c>HandlerId</c> is <c>default</c>, then this entry
+ modifies the default handler, equivalent to calling</p>
+ <pre><seealso marker="logger#set_handler_config-2">
+ logger:set_handler_config(default, Module, HandlerConfig)
+ </seealso></pre>
+ <p>For all other values of <c>HandlerId</c>, this entry
+ adds a new handler, equivalent to calling</p>
+ <pre><seealso marker="logger:add_handler/3">
+ logger:add_handler(HandlerId, Module, HandlerConfig)
+ </seealso></pre>
+ <p>Multiple entries of this type are allowed.</p></item>
+ <tag><c>{filters, FilterDefault, [Filter]}</c></tag>
+ <item>
+ <p>Adds the specified primary filters.</p>
+ <list>
+ <item><c>FilterDefault = log | stop</c></item>
+ <item><c>Filter = {FilterId, {FilterFun, FilterConfig}}</c></item>
+ </list>
+ <p>Equivalent to calling</p>
+ <pre><seealso marker="logger#add_primary_filter/2">
+ logger:add_primary_filter(FilterId, {FilterFun, FilterConfig})
+ </seealso></pre>
+ <p>for each <c>Filter</c>.</p>
+ <p><c>FilterDefault</c> specifies the behaviour if all
+ primary filters return <c>ignore</c>, see
+ section <seealso marker="#filters">Filters</seealso>.</p>
+ <p>Only one entry of this type is allowed.</p>
+ </item>
+ <tag><c>{module_level, Level, [Module]}</c></tag>
+ <item>
+ <p>Sets module log level for the given modules. Equivalent
+ to calling</p>
+ <pre><seealso marker="logger#set_module_level/2">
+ logger:set_module_level(Module, Level)</seealso></pre>
+ <p>for each <c>Module</c>.</p>
+ <p>Multiple entries of this type are allowed.</p>
+ </item>
+ </taglist>
+ <p>See
+ section <seealso marker="#config_examples">Configuration
+ Examples</seealso> for examples using the <c>logger</c>
+ parameter for system configuration.</p>
+ </item>
+ <tag><marker id="logger_level"/>
+ <c>logger_level = Level</c></tag>
+ <item>
+ <p>Specifies the primary log level. See
+ the <seealso marker="kernel_app#logger_level"><c>kernel(6)</c></seealso>
+ manual page for more information about this parameter.</p>
+ </item>
+ <tag><marker id="logger_sasl_compatible"/>
+ <c>logger_sasl_compatible = true | false</c></tag>
+ <item>
+ <p>Specifies Logger's compatibility
+ with <seealso marker="sasl:error_logging">SASL Error
+ Logging</seealso>. See
+ the <seealso marker="kernel_app#logger_sasl_compatible">
+ <c>kernel(6)</c></seealso> manual page for more
+ information about this parameter.</p>
+ </item>
+ </taglist>
+ </section>
+
+ <section>
+ <marker id="config_examples"/>
+ <title>Configuration Examples</title>
+ <p>The value of the Kernel configuration parameter <c>logger</c>
+ is a list of tuples. It is possible to write the term on the
+ command line when starting an erlang node, but as the term
+ grows, a better approach is to use the system configuration
+ file. See
+ the <seealso marker="config"><c>config(4)</c></seealso> manual
+ page for more information about this file.</p>
+ <p>Each of the following examples shows a simple system
+ configuration file that configures Logger according to the
+ description.</p>
+ <p>Modify the default handler to print to a file instead of
+ <c>standard_io</c>:</p>
+ <code>
+[{kernel,
+ [{logger,
+ [{handler, default, logger_std_h, % {handler, HandlerId, Module,
+ #{config => #{type => {file,"log/erlang.log"}}}} % Config}
+ ]}]}].
+ </code>
+ <p>Modify the default handler to print each log event as a
+ single line:</p>
+ <code>
+[{kernel,
+ [{logger,
+ [{handler, default, logger_std_h,
+ #{formatter => {logger_formatter, #{single_line => true}}}}
+ ]}]}].
+ </code>
+ <p>Modify the default handler to print the pid of the logging
+ process for each log event:</p>
+ <code>
+[{kernel,
+ [{logger,
+ [{handler, default, logger_std_h,
+ #{formatter => {logger_formatter,
+ #{template => [time," ",pid," ",msg,"\n"]}}}}
+ ]}]}].
+ </code>
+ <p>Modify the default handler to only print errors and more
+ severe log events to "log/erlang.log", and add another handler
+ to print all log events to "log/debug.log".</p>
+ <code>
+[{kernel,
+ [{logger,
+ [{handler, default, logger_std_h,
+ #{level => error,
+ config => #{type => {file, "log/erlang.log"}}}},
+ {handler, info, logger_std_h,
+ #{level => debug,
+ config => #{type => {file, "log/debug.log"}}}}
+ ]}]}].
+ </code>
</section>
</section>
<section>
<marker id="compatibility"/>
- <title>Backwards compatibility with error_logger</title>
- <p>Logger provides backwards compatibility with the old
+ <title>Backwards Compatibility with error_logger</title>
+ <p>Logger provides backwards compatibility with
<c>error_logger</c> in the following ways:</p>
<taglist>
- <tag>Legacy event handlers</tag>
- <item>
- <p>To use event handlers written for <c>error_logger</c>, just
- add your event handler with</p>
- <code>
-error_logger:add_report_handler/1,2.
- </code>
- <p>This will automatically start the <c>error_logger</c>
- event manager, and add <c>error_logger</c> as a
- handler to <c>logger</c>, with configuration</p>
-<code>
-#{level=>info,
- filter_default=>log,
- filters=>[]}.
-</code>
- <p>Note that this handler will ignore events that do not
- originate from the old <c>error_logger</c> API, or from
- within OTP. This means that if your code uses the logger API
- for logging, then your log events will be discarded by this
- handler.</p>
- <p>Also note that <c>error_logger</c> is not overload
- protected.</p>
- </item>
- <tag>Logger API</tag>
+ <tag>API for Logging</tag>
<item>
- <p>The old <c>error_logger</c> API still exists, but should
- only be used by legacy code. It will be removed in a later
+ <p>The <c>error_logger</c> API still exists, but should only
+ be used by legacy code. It will be removed in a later
release.</p>
+ <p>Calls
+ to <seealso marker="error_logger#error_report-1">
+ <c>error_logger:error_report/1,2</c></seealso>,
+ <seealso marker="error_logger#error_msg-1">
+ <c>error_logger:error_msg/1,2</c></seealso>, and
+ corresponding functions for warning and info messages, are
+ all forwarded to Logger as calls
+ to <seealso marker="logger#log-3">
+ <c>logger:log(Level,Report,Metadata)</c></seealso>.</p>
+ <p><c>Level = error | warning | info</c> and is taken
+ from the function name. <c>Report</c> contains the actual
+ log message, and <c>Metadata</c> contains additional
+ information which can be used for creating backwards
+ compatible events for legacy <c>error_logger</c> event
+ handlers, see
+ section <seealso marker="#legacy_event_handlers">Legacy
+ Event Handlers</seealso>.</p>
</item>
- <tag>Output format</tag>
+ <tag>Output Format</tag>
<item>
<p>To get log events on the same format as produced
by <c>error_logger_tty_h</c> and <c>error_logger_file_h</c>,
use the default formatter, <c>logger_formatter</c>, with
- configuration parameter <c>legacy_header=>true</c>. This is
- also the default.</p>
+ configuration parameter <c>legacy_header</c> set
+ to <c>true</c>. This is the default configuration of
+ the <c>default</c> handler started by Kernel.</p>
</item>
- <tag>Default format of log events from OTP</tag>
+ <tag>Default Format of Log Events from OTP</tag>
<item>
<p>By default, all log events originating from within OTP,
except the former so called "SASL reports", look the same as
before.</p>
</item>
- <tag>SASL reports</tag>
+ <tag><marker id="sasl_reports"/>SASL Reports</tag>
<item>
<p>By SASL reports we mean supervisor reports, crash reports
and progress reports.</p>
- <p>In earlier releases, these reports were only logged when
- the SASL application was running, and they were printed
- trough specific event handlers
- named <c>sasl_report_tty_h</c>
+ <p>Prior to Erlang/OTP 21.0, these reports were only logged
+ when the SASL application was running, and they were printed
+ trough SASL's own event handlers <c>sasl_report_tty_h</c>
and <c>sasl_report_file_h</c>.</p>
- <p>The destination of these log events were configured by
- environment variables for the SASL application.</p>
+ <p>The destination of these log events was configured by
+ <seealso marker="sasl:sasl_app#deprecated_error_logger_config">SASL
+ configuration parameters</seealso>.</p>
<p>Due to the specific event handlers, the output format
slightly differed from other log events.</p>
- <p>As of OTP-21, the concept of SASL reports is removed,
- meaning that the default behavior is as follows:</p>
+ <p>As of Erlang/OTP 21.0, the concept of SASL reports is
+ removed, meaning that the default behaviour is as
+ follows:</p>
<list>
- <item>Supervisor reports, crash reports and progress reports
+ <item>Supervisor reports, crash reports, and progress reports
are no longer connected to the SASL application.</item>
- <item>Supervisor reports and crash reports are logged by
- default.</item>
- <item>Progress reports are not logged by default, but can be
- enabled with the kernel environment
- variable <c>logger_log_progress</c>.</item>
+ <item>Supervisor reports and crash reports are issued
+ as <c>error</c> level log events, and are logged through
+ the default handler started by Kernel.</item>
+ <item>Progress reports are issued as <c>info</c> level log
+ events, and since the default primary log level
+ is <c>notice</c>, these are not logged by default. To
+ enable printing of progress reports, set
+ the <seealso marker="#primary_level">primary log
+ level</seealso> to <c>info</c>.</item>
<item>The output format is the same for all log
events.</item>
</list>
- <p>If the old behavior is preferred, the kernel environment
- variable <c>logger_sasl_compatible</c> can be set
- to <c>true</c>. The old SASL environment variables can then
- be used as before, and the SASL reports will only be printed
- if the SASL application is running - through a second log
- handler named <c>sasl_h</c>.</p>
- <p>All SASL reports have a metadata
- field <c>domain=>[beam,erlang,otp,sasl]</c>, which can be
- used, for example, by filters to to stop or allow the
- events.</p>
+ <p>If the old behaviour is preferred, the Kernel configuration
+ parameter <seealso marker="kernel_app#logger_sasl_compatible">
+ <c>logger_sasl_compatible</c></seealso> can be set
+ to <c>true</c>. The
+ <seealso marker="sasl:sasl_app#deprecated_error_logger_config">SASL
+ configuration parameters</seealso> can then be used as
+ before, and the SASL reports will only be printed if the
+ SASL application is running, through a second log handler
+ named <c>sasl</c>.</p>
+ <p>All SASL reports have a metadata field <c>domain</c> which
+ is set to <c>[otp,sasl]</c>. This field can be
+ used by filters to stop or allow the log events.</p>
+ <p>See section <seealso marker="sasl:error_logging">SASL User's
+ Guide</seealso> for more information about the old SASL
+ error logging functionality.</p>
+ </item>
+ <tag><marker id="legacy_event_handlers"/>Legacy Event Handlers</tag>
+ <item>
+ <p>To use event handlers written for <c>error_logger</c>, just
+ add your event handler with</p>
+ <code>
+error_logger:add_report_handler/1,2.
+ </code>
+ <p>This automatically starts the error logger event manager,
+ and adds <c>error_logger</c> as a handler to Logger, with
+ the following configuration:</p>
+<code>
+#{level => info,
+ filter_default => log,
+ filters => []}.
+</code>
+ <note>
+ <p>This handler ignores events that do not originate from
+ the <c>error_logger</c> API, or from within OTP. This
+ means that if your code uses the Logger API for logging,
+ then your log events will be discarded by this
+ handler.</p>
+ <p>The handler is not overload protected.</p>
+ </note>
</item>
</taglist>
</section>
<section>
- <title>Error handling</title>
- <p>Log data is expected to be either a format string and
- arguments, a string (unicode:chardata), or a report (map or
- key-value list) which can be converted to a format string and
- arguments by the handler. A default report callback should be
- included in the log event's metadata, which can be used for
- converting the report to a format string and arguments. The
- handler might also do a custom conversion if the default format
- is not desired.</p>
- <p><c>logger</c> does, to a certain extent, check its input data
- before forwarding a log event to the handlers, but it does not
- evaluate conversion funs or check the validity of format strings
- and arguments. This means that any filter or handler must be
- careful when formatting the data of a log event, making sure
- that it does not crash due to bad input data or faulty
- callbacks.</p>
- <p>If a filter or handler still crashes, logger will remove the
- filter or handler in question from the configuration, and then
- print a short error message on the console. A debug event
- containing the crash reason and other details is also issued,
- and can be seen if a handler is installed which logs on debug
- level.</p>
+ <title>Error Handling</title>
+ <p>Logger does, to a certain extent, check its input data before
+ forwarding a log event to filters and handlers. It does,
+ however, not evaluate report callbacks, or check the validity of
+ format strings and arguments. This means that all filters and
+ handlers must be careful when formatting the data of a log
+ event, making sure that it does not crash due to bad input data
+ or faulty callbacks.</p>
+ <p>If a filter or handler still crashes, Logger will remove the
+ filter or handler in question from the configuration, and print
+ a short error message to the terminal. A debug event containing
+ the crash reason and other details is also issued.</p>
+ <p>See section <seealso marker="#log_message">Log
+ Message</seealso> for more information about report callbacks
+ and valid forms of log messages.</p>
</section>
<section>
- <title>Example: add a handler to log debug events to file</title>
- <p>When starting an erlang node, the default behavior is that all
- log events with level info and above are logged to the
- console. In order to also log debug events, you can either
- change the global log level to <c>debug</c> or add a separate
- handler to take care of this. In this example we will add a new
- handler which prints the debug events to a separate file.</p>
- <p>First, we add an instance of logger_std_h with
- type <c>{file,File}</c>, and we set the handler's level
- to <c>debug</c>:</p>
+ <title>Example: Add a handler to log info events to file</title>
+ <p>When starting an Erlang node, the default behaviour is that all
+ log events on level <c>notice</c> or more severe, are logged to
+ the terminal via the default handler. To also log info events,
+ you can either change the primary log level to <c>info</c>:</p>
<pre>
-1> <input>Config = #{level=>debug,logger_std_h=>#{type=>{file,"./debug.log"}}}.</input>
-#{logger_std_h => #{type => {file,"./debug.log"}},
- level => debug}
-2> <input>logger:add_handler(debug_handler,logger_std_h,Config).</input>
+1> <input>logger:set_primary_config(level, info).</input>
ok</pre>
- <p>By default, the handler receives all events
- (<c>filter_defalt=log</c>), so we need to add a filter to stop
- all non-debug events:</p>
+ <p>or set the level for one or a few modules only:</p>
<pre>
-3> <input>Fun = fun(#{level:=debug}=Log,_) -> Log; (_,_) -> stop end.</input>
-#Fun&lt;erl_eval.12.98642416>
-4> <input>logger:add_handler_filter(debug_handler,allow_debug,{Fun,[]}).</input>
+2> <input>logger:set_module_level(mymodule, info).</input>
ok</pre>
- <p>And finally, we need to make sure that the logger itself allows
- debug events. This can either be done by setting the global
- logger level:</p>
+ <p>This allows info events to pass through to the default handler,
+ and be printed to the terminal as well. If there are many info
+ events, it can be useful to print these to a file instead.</p>
+ <p>First, set the log level of the default handler
+ to <c>notice</c>, preventing it from printing info events to the
+ terminal:</p>
<pre>
-5> <input>logger:set_logger_config(level,debug).</input>
+3> <input>logger:set_handler_config(default, level, notice).</input>
ok</pre>
- <p>Or by allowing debug events from one or a few modules only:</p>
+ <p>Then, add a new handler which prints to file. You can use the
+ handler
+ module <seealso marker="logger_std_h"><c>logger_std_h</c></seealso>,
+ and specify type <c>{file,File}</c>.:</p>
<pre>
-6> <input>logger:set_module_level(mymodule,debug).</input>
+4> <input>Config = #{config => #{type => {file,"./info.log"}}, level => info}.</input>
+#{config => #{type => {file,"./info.log"}},level => info}
+5> <input>logger:add_handler(myhandler, logger_std_h, Config).</input>
ok</pre>
+ <p>Since <c>filter_default</c> defaults to <c>log</c>, this
+ handler now receives all log events. If you want info events
+ only in the file, you must add a filter to stop all non-info
+ events. The built-in
+ filter <seealso marker="logger_filters#level-2">
+ <c>logger_filters:level/2</c></seealso>
+ can do this:</p>
+ <pre>
+6> <input>logger:add_handler_filter(myhandler, stop_non_info,
+ {fun logger_filters:level/2, {stop, neq, info}}).</input>
+ok</pre>
+ <p>See section <seealso marker="#filters">Filters</seealso> for
+ more information about the filters and the <c>filter_default</c>
+ configuration parameter.</p>
</section>
<section>
- <title>Example: implement a handler</title>
- <p>The only requirement that a handler MUST fulfill is to export
- the following function:</p>
- <code>log(logger:log(),logger:config()) ->ok</code>
- <p>It may also implement the following callbacks:</p>
- <code>
-adding_handler(logger:handler_id(),logger:config()) -> {ok,logger:config()} | {error,term()}
-removing_handler(logger:handler_id(),logger:config()) -> ok
-changing_config(logger:handler_id(),logger:config(),logger:config()) -> {ok,logger:config()} | {error,term()}
- </code>
- <p>When logger:add_handler(Id,Module,Config) is called, logger
- will first call Module:adding_handler(Id,Config), and if it
- returns {ok,NewConfig} the NewConfig is written to the
- configuration database. After this, the handler may receive log
- events as calls to Module:log/2.</p>
+ <title>Example: Implement a handler</title>
+ <p>Section <seealso marker="logger#handler_callback_functions">Handler
+ Callback Functions</seealso> in the logger(3) manual page
+ describes the callback functions that can be implemented for a
+ Logger handler.</p>
+ <p>A handler callback module must export:</p>
+ <list>
+ <item><c>log(Log, Config)</c></item>
+ </list>
+ <p>It can optionally also export some, or all, of the following:</p>
+ <list>
+ <item><c>adding_handler(Config)</c></item>
+ <item><c>removing_handler(Config)</c></item>
+ <item><c>changing_config(OldConfig, NewConfig)</c></item>
+ </list>
+ <p>When a handler is added, by for example a call
+ to <seealso marker="logger#add_handler-3">
+ <c>logger:add_handler(Id, HModule, Config)</c></seealso>,
+ Logger first calls <c>HModule:adding_handler(Config)</c>. If
+ this function returns <c>{ok,Config1}</c>, Logger
+ writes <c>Config1</c> to the configuration database, and
+ the <c>logger:add_handler/3</c> call returns. After this, the
+ handler is installed and must be ready to receive log events as
+ calls to <c>HModule:log/2</c>.</p>
<p>A handler can be removed by calling
- logger:remove_handler(Id). logger will call
- Module:removing_handler(Id,Config), and then remove the handler's
- configuration from the configuration database.</p>
- <p>When logger:set_handler_config is called, logger calls
- Module:changing_config(Id,OldConfig,NewConfig). If this function
- returns ok, the NewConfig is written to the configuration
- database.</p>
-
- <p>A simple handler which prints to the console could be
- implemented as follows:</p>
+ <seealso marker="logger#remove_handler-1">
+ <c>logger:remove_handler(Id)</c></seealso>. Logger calls
+ <c>HModule:removing_handler(Config)</c>, and removes the
+ handler's configuration from the configuration database.</p>
+ <p>When <seealso marker="logger#set_handler_config-2">
+ <c>logger:set_handler_config/2,3</c></seealso>
+ or <seealso marker="logger#update_handler_config/2">
+ <c>logger:update_handler_config/2</c></seealso> is called,
+ Logger
+ calls <c>HModule:changing_config(OldConfig, NewConfig)</c>. If
+ this function returns <c>{ok,NewConfig1}</c>, Logger
+ writes <c>NewConfig1</c> to the configuration database.</p>
+
+ <p>A simple handler that prints to the terminal can be implemented
+ as follows:</p>
<code>
--module(myhandler).
+-module(myhandler1).
-export([log/2]).
-log(Log,#{formatter:={FModule,FConfig}) ->
- io:put_chars(FModule:format(Log,FConfig)).
+log(LogEvent, #{formatter := {FModule, FConfig}}) ->
+ io:put_chars(FModule:format(LogEvent, FConfig)).
</code>
- <p>A simple handler which prints to file could be implemented like
- this:</p>
- <code>
--module(myhandler).
--export([adding_handler/2, removing_handler/2, log/2]).
--export([init/1, handle_call/3, handle_cast/2, terminate/2]).
-
-adding_handler(Id,Config) ->
- {ok,Fd} = file:open(File,[append,{encoding,utf8}]),
- {ok,Config#{myhandler_fd=>Fd}}.
-
-removing_handler(Id,#{myhandler_fd:=Fd}) ->
- _ = file:close(Fd),
- ok.
-
-log(Log,#{myhandler_fd:=Fd,formatter:={FModule,FConfig}}) ->
- io:put_chars(Fd,FModule:format(Log,FConfig)).
- </code>
-
- <note><p>The above handlers do not have any overload
+ <p>Notice that the above handler does not have any overload
protection, and all log events are printed directly from the
- client process.</p></note>
-
- <p>For examples of overload protection, please refer to the
- implementation
+ client process.</p>
+ <p>For information and examples of overload protection, please
+ refer to
+ section <seealso marker="#overload_protection">Protecting the
+ Handler from Overload</seealso>, and the implementation
of <seealso marker="logger_std_h"><c>logger_std_h</c></seealso>
and <seealso marker="logger_disk_log_h"><c>logger_disk_log_h</c>
</seealso>.</p>
-
- <p>Below is a simpler example of a handler which logs through one
- single process.</p>
+ <p>The following is a simpler example of a handler which logs to a
+ file through one single process:</p>
<code>
--module(myhandler).
--export([adding_handler/2, removing_handler/2, log/2]).
+-module(myhandler2).
+-export([adding_handler/1, removing_handler/1, log/2]).
-export([init/1, handle_call/3, handle_cast/2, terminate/2]).
-adding_handler(Id,Config) ->
- {ok,Pid} = gen_server:start(?MODULE,Config),
- {ok,Config#{myhandler_pid=>Pid}}.
+adding_handler(Config) ->
+ MyConfig = maps:get(config,Config,#{file => "myhandler2.log"}),
+ {ok, Pid} = gen_server:start(?MODULE, MyConfig, []),
+ {ok, Config#{config => MyConfig#{pid => Pid}}}.
-removing_handler(Id,#{myhandler_pid:=Pid}) ->
+removing_handler(#{config := #{pid := Pid}}) ->
gen_server:stop(Pid).
-log(Log,#{myhandler_pid:=Pid} = Config) ->
- gen_server:cast(Pid,{log,Log,Config}).
+log(LogEvent,#{config := #{pid := Pid}} = Config) ->
+ gen_server:cast(Pid, {log, LogEvent, Config}).
-init(#{myhandler_file:=File}) ->
- {ok,Fd} = file:open(File,[append,{encoding,utf8}]),
- {ok,#{file=>File,fd=>Fd}}.
+init(#{file := File}) ->
+ {ok, Fd} = file:open(File, [append, {encoding, utf8}]),
+ {ok, #{file => File, fd => Fd}}.
-handle_call(_,_,State) ->
- {reply,{error,bad_request},State}.
+handle_call(_, _, State) ->
+ {reply, {error, bad_request}, State}.
-handle_cast({log,Log,Config},#{fd:=Fd} = State) ->
- do_log(Fd,Log,Config),
- {noreply,State}.
+handle_cast({log, LogEvent, Config}, #{fd := Fd} = State) ->
+ do_log(Fd, LogEvent, Config),
+ {noreply, State}.
-terminate(Reason,#{fd:=Fd}) ->
+terminate(_Reason, #{fd := Fd}) ->
_ = file:close(Fd),
ok.
-do_log(Fd,Log,#{formatter:={FModule,FConfig}}) ->
- String = FModule:format(Log,FConfig),
- io:put_chars(Fd,String).
+do_log(Fd, LogEvent, #{formatter := {FModule, FConfig}}) ->
+ String = FModule:format(LogEvent, FConfig),
+ io:put_chars(Fd, String).
</code>
</section>
<section>
<marker id="overload_protection"/>
- <title>Protecting the handler from overload</title>
- <p>In order for the built-in handlers to survive, and stay responsive,
- during periods of high load (i.e. when huge numbers of incoming
- log requests must be handled), a mechanism for overload protection
- has been implemented in the
- <seealso marker="logger_std_h"><c>logger_std_h</c></seealso>
- and <seealso marker="logger_disk_log_h"><c>logger_disk_log_h</c>
- </seealso> handler. The mechanism, used by both handlers, works
- as follows:</p>
+ <title>Protecting the Handler from Overload</title>
+ <p>The default handlers, <seealso marker="logger_std_h">
+ <c>logger_std_h</c></seealso> and <seealso marker="logger_disk_log_h">
+ <c>logger_disk_log_h</c></seealso>, feature an overload protection
+ mechanism, which makes it possible for the handlers to survive,
+ and stay responsive, during periods of high load (when huge
+ numbers of incoming log requests must be handled).
+ The mechanism works as follows:</p>
<section>
- <title>Message queue length</title>
+ <title>Message Queue Length</title>
<p>The handler process keeps track of the length of its message
- queue and reacts in different ways depending on the current status.
- The purpose is to keep the handler in, or (as quickly as possible),
- get the handler into, a state where it can keep up with the pace
- of incoming log requests. The memory usage of the handler must never
- keep growing larger and larger, since that would eventually cause the
- handler to crash. Three thresholds with associated actions have been
- defined:</p>
+ queue and takes some form of action when the current length exceeds a
+ configurable threshold. The purpose is to keep the handler in, or to
+ as quickly as possible get the handler into, a state where it can
+ keep up with the pace of incoming log events. The memory use of the
+ handler must never grow larger and larger, since that will eventually
+ cause the handler to crash. These three thresholds, with associated
+ actions, exist:</p>
<taglist>
- <tag><c>toggle_sync_qlen</c></tag>
+ <tag><c>sync_mode_qlen</c></tag>
<item>
- <p>The default value of this level is <c>10</c> messages,
- and as long as the length of the message queue is lower, all log
- requests are handled asynchronously. This simply means that the
- process sending the log request (by calling a log function in the
- logger API) does not wait for a response from the handler but
- continues executing immediately after the request (i.e. it will not
- be affected by the time it takes the handler to print to the log
- device). If the message queue grows larger than this value, however,
- the handler starts handling the log requests synchronously instead,
- meaning the process sending the request will have to wait for a
- response. When the handler manages to reduce the message queue to a
- level below the <c>toggle_sync_qlen</c> threshold, asynchronous
+ <p>As long as the length of the message queue is lower than this
+ value, all log events are handled asynchronously. This means that
+ the client process sending the log event, by calling a log function
+ in the <seealso marker="logger_chapter#logger_api">Logger API</seealso>,
+ does not wait for a response from the handler but continues
+ executing immediately after the event is sent. It is not affected
+ by the time it takes the handler to print the event to the log
+ device. If the message queue grows larger than this value,
+ the handler starts handling log events synchronously instead,
+ meaning that the client process sending the event must wait for a
+ response. When the handler reduces the message queue to a
+ level below the <c>sync_mode_qlen</c> threshold, asynchronous
operation is resumed. The switch from asynchronous to synchronous
- mode will force the logging tempo of few busy senders to slow down,
- but can not protect the handler sufficiently in situations of many
- concurrent senders.</p>
+ mode can slow down the logging tempo of one, or a few, busy senders,
+ but cannot protect the handler sufficiently in a situation of many
+ busy concurrent senders.</p>
+ <p>Defaults to <c>10</c> messages.</p>
</item>
- <tag><c>drop_new_reqs_qlen</c></tag>
+ <tag><c>drop_mode_qlen</c></tag>
<item>
- <p>When the message queue has grown larger than this threshold, which
- defaults to <c>200</c> messages, the handler switches to a mode in
- which it drops any new requests being made. Dropping a message in
- this state means that the log function never actually sends a message
- to the handler. The log call simply returns without an action. When
- the length of the message queue has been reduced to a level below this
- threshold, synchronous or asynchronous request handling mode is
- resumed.</p>
+ <p>When the message queue grows larger than this threshold, the
+ handler switches to a mode in which it drops all new events that
+ senders want to log. Dropping an event in this mode means that the
+ call to the log function never results in a message being sent to
+ the handler, but the function returns without taking any action.
+ The handler keeps logging the events that are already in its message
+ queue, and when the length of the message queue is reduced to a level
+ below the threshold, synchronous or asynchronous mode is resumed.
+ Notice that when the handler activates or deactivates drop mode,
+ information about it is printed in the log.</p>
+ <p>Defaults to <c>200</c> messages.</p>
</item>
- <tag><c>flush_reqs_qlen</c></tag>
+ <tag><c>flush_qlen</c></tag>
<item>
- <p>Above this threshold, which defaults to <c>1000</c> messages, a
- flush operation takes place, in which all messages buffered in the
- process mailbox get deleted without any logging actually taking
- place. (Processes waiting for a response from a synchronous log request
- will receive a reply indicating that the request has been dropped).</p>
+ <p>If the length of the message queue grows larger than this threshold,
+ a flush (delete) operation takes place. To flush events, the handler
+ discards the messages in the message queue by receiving them in a
+ loop without logging. Client processes waiting for a response from a
+ synchronous log request receive a reply from the handler indicating
+ that the request is dropped. The handler process increases its
+ priority during the flush loop to make sure that no new events
+ are received during the operation. Notice that after the flush operation
+ is performed, the handler prints information in the log about how many
+ events have been deleted.</p>
+ <p>Defaults to <c>1000</c> messages.</p>
</item>
</taglist>
- <p>For the overload protection algorithm to work properly, it is a
- requirement that:</p>
+ <p>For the overload protection algorithm to work properly, it is
+ required that:</p>
+
+ <p><c>sync_mode_qlen =&lt; drop_mode_qlen =&lt; flush_qlen</c></p>
- <p><c>toggle_sync_qlen &lt; drop_new_reqs_qlen &lt; flush_reqs_qlen</c></p>
+ <p>and that:</p>
+
+ <p><c>drop_mode_qlen &gt; 1</c></p>
+
+ <p>To disable certain modes, do the following:</p>
+ <list>
+ <item>If <c>sync_mode_qlen</c> is set to <c>0</c>, all log events are handled
+ synchronously. That is, asynchronous logging is disabled.</item>
+ <item>If <c>sync_mode_qlen</c> is set to the same value as
+ <c>drop_mode_qlen</c>, synchronous mode is disabled. That is, the handler
+ always runs in asynchronous mode, unless dropping or flushing is invoked.</item>
+ <item>If <c>drop_mode_qlen</c> is set to the same value as <c>flush_qlen</c>,
+ drop mode is disabled and can never occur.</item>
+ </list>
<p>During high load scenarios, the length of the handler message queue
rarely grows in a linear and predictable way. Instead, whenever the
- handler process gets scheduled in, it can have an almost arbitrary number
- of messages waiting in the mailbox. It's for this reason that the overload
- protection mechanism is focused on acting quickly and quite drastically
- (such as immediately dropping or flushing messages) as soon as a large
- queue length is detected. </p>
-
- <p>The thresholds listed above may be modified by the user if, e.g, a handler
- shouldn't drop or flush messages unless the message queue length grows
- extremely large. (The handler must be allowed to use large amounts of memory
- under such circumstances however). Another example of when the user might want
- to change the settings is if, for performance reasons, the logging processes must
- never get blocked by synchronous log requests, while dropping or flushing requests
- is perfectly acceptable (since it doesn't affect the performance of the
- loggers).</p>
+ handler process is scheduled in, it can have an almost arbitrary number
+ of messages waiting in the message queue. It is for this reason that the overload
+ protection mechanism is focused on acting quickly, and quite drastically,
+ such as immediately dropping or flushing messages, when a large queue length
+ is detected.</p>
+
+ <p>The values of the previously listed thresholds can be specified by the user.
+ This way, a handler can be configured to, for example, not drop or flush
+ messages unless the message queue length of the handler process grows extremely
+ large. Notice that large amounts of memory can be required for the node under such
+ circumstances. Another example of user configuration is when, for performance
+ reasons, the client processes must never be blocked by synchronous log requests.
+ It is possible, perhaps, that dropping or flushing events is still acceptable, since
+ it does not affect the performance of the client processes sending the log events.</p>
<p>A configuration example:</p>
<code type="none">
logger:add_handler(my_standard_h, logger_std_h,
- #{logger_std_h =>
- #{type => {file,"./system_info.log"},
- toggle_sync_qlen => 100,
- drop_new_reqs_qlen => 1000,
- flush_reqs_qlen => 2000}}).
+ #{config => #{type => {file,"./system_info.log"},
+ sync_mode_qlen => 100,
+ drop_mode_qlen => 1000,
+ flush_qlen => 2000}}).
</code>
</section>
<section>
- <title>Controlling bursts of log requests</title>
- <p>A potential problem with large bursts of log requests, is that log files
- may get full or wrapped too quickly (in the latter case overwriting
- previously logged data that could be of great importance). For this reason,
- both built-in handlers offer the possibility to set a maximum level of how
- many requests to process with a certain time frame. With this burst control
- feature enabled, the handler will take care of bursts of log requests
- without choking log files, or the console, with massive amounts of
- printouts. These are the configuration parameters:</p>
-
+ <title>Controlling Bursts of Log Requests</title>
+ <p>Large bursts of log events - many events received by the handler
+ under a short period of time - can potentially cause problems, such as:</p>
+ <list>
+ <item>Log files grow very large, very quickly.</item>
+ <item>Circular logs wrap too quickly so that important data is overwritten.</item>
+ <item>Write buffers grow large, which slows down file sync operations.</item>
+ </list>
+
+ <p>For this reason, both built-in handlers offer the possibility to specify the
+ maximum number of events to be handled within a certain time frame.
+ With this burst control feature enabled, the handler can avoid choking the log with
+ massive amounts of printouts. The configuration parameters are:</p>
<taglist>
- <tag><c>enable_burst_limit</c></tag>
+ <tag><c>burst_limit_enable</c></tag>
<item>
- <p>This is set to <c>true</c> by default. The value <c>false</c>
- disables the burst control feature.</p>
+ <p>Value <c>true</c> enables burst control and <c>false</c> disables it.</p>
+ <p>Defaults to <c>true</c>.</p>
</item>
- <tag><c>burst_limit_size</c></tag>
+ <tag><c>burst_limit_max_count</c></tag>
<item>
- <p>This is how many requests should be processed within the
- <c>burst_window_time</c> time frame. After this maximum has been
- reached, successive requests will be dropped until the end of the
- time frame. The default value is <c>500</c> messages.</p>
+ <p>This is the maximum number of events to handle within a
+ <c>burst_limit_window_time</c> time frame. After the limit is
+ reached, successive events are dropped until the end of the time frame.</p>
+ <p>Defaults to <c>500</c> events.</p>
</item>
- <tag><c>burst_window_time</c></tag>
+ <tag><c>burst_limit_window_time</c></tag>
<item>
- <p>The default window is <c>1000</c> milliseconds long.</p>
+ <p>See the previous description of <c>burst_limit_max_count</c>.</p>
+ <p>Defaults to <c>1000</c> milliseconds.</p>
</item>
</taglist>
<p>A configuration example:</p>
<code type="none">
logger:add_handler(my_disk_log_h, logger_disk_log_h,
- #{disk_log_opts =>
- #{file => "./my_disk_log"},
- logger_disk_log_h =>
- #{burst_limit_size => 10,
- burst_window_time => 500}}).
+ #{config => #{file => "./my_disk_log",
+ burst_limit_enable => true,
+ burst_limit_max_count => 20,
+ burst_limit_window_time => 500}}).
</code>
</section>
<section>
- <title>Terminating a large handler</title>
- <p>A handler process may grow large even if it can manage peaks of high load
- without crashing. The overload protection mechanism includes user configurable
- levels for a maximum allowed message queue length and maximum allowed memory
- usage. This feature is disabled by default, but can be switched on by means
- of the following configuration parameters:</p>
-
+ <title>Terminating an Overloaded Handler</title>
+ <p>It is possible that a handler, even if it can successfully manage peaks
+ of high load without crashing, can build up a large message queue, or use a
+ large amount of memory. The overload protection mechanism includes an
+ automatic termination and restart feature for the purpose of guaranteeing
+ that a handler does not grow out of bounds. The feature is configured
+ with the following parameters:</p>
<taglist>
- <tag><c>enable_kill_overloaded</c></tag>
+ <tag><c>overload_kill_enable</c></tag>
<item>
- <p>This is set to <c>false</c> by default. The value <c>true</c>
- enables the feature.</p>
+ <p>Value <c>true</c> enables the feature and <c>false</c> disables it.</p>
+ <p>Defaults to <c>false</c>.</p>
</item>
- <tag><c>handler_overloaded_qlen</c></tag>
+ <tag><c>overload_kill_qlen</c></tag>
<item>
- <p>This is the maximum allowed queue length. If the mailbox grows larger
- than this, the handler process gets terminated.</p>
+ <p>This is the maximum allowed queue length. If the message queue grows
+ larger than this, the handler process is terminated.</p>
+ <p>Defaults to <c>20000</c> messages.</p>
</item>
- <tag><c>handler_overloaded_mem</c></tag>
+ <tag><c>overload_kill_mem_size</c></tag>
<item>
- <p>This is the maximum allowed memory usage of the handler process. If
- the handler grows any larger, the process gets terminated.</p>
+ <p>This is the maximum memory size that the handler process is allowed to use.
+ If the handler grows larger than this, the process is terminated.</p>
+ <p>Defaults to <c>3000000</c> bytes.</p>
</item>
- <tag><c>handler_restart_after</c></tag>
+ <tag><c>overload_kill_restart_after</c></tag>
<item>
- <p>If the handler gets terminated because of its queue length or
- memory usage, it can get automatically restarted again after a
- configurable delay time. The time is specified in milliseconds
- and <c>5000</c> is the default value. The value <c>never</c> can
- also be set, which prevents a restart.</p>
+ <p>If the handler is terminated, it restarts automatically after a
+ delay specified in milliseconds. The value <c>infinity</c> prevents
+ restarts.</p>
+ <p>Defaults to <c>5000</c> milliseconds.</p>
</item>
</taglist>
+ <p>If the handler process is terminated because of overload, it prints
+ information about it in the log. It also prints information about when a
+ restart has taken place, and the handler is back in action.</p>
+ <note>
+ <p>The sizes of the log events affect the memory needs of the handler.
+ For information about how to limit the size of log events, see the
+ <seealso marker="logger_formatter"><c>logger_formatter(3)</c></seealso>
+ manual page.</p>
+ </note>
</section>
</section>
<section>
<title>See Also</title>
- <p><seealso marker="error_logger"><c>error_logger(3)</c></seealso>,
- <seealso marker="sasl:sasl_app"><c>SASL(6)</c></seealso></p>
+ <p>
+ <seealso marker="disk_log"><c>disk_log(3)</c></seealso>,
+ <seealso marker="error_logger"><c>error_logger(3)</c></seealso>,
+ <seealso marker="logger"><c>logger(3)</c></seealso>,
+ <seealso marker="logger_disk_log_h"><c>logger_disk_log_h(3)</c></seealso>,
+ <seealso marker="logger_filters"><c>logger_filters(3)</c></seealso>,
+ <seealso marker="logger_formatter"><c>logger_formatter(3)</c></seealso>,
+ <seealso marker="logger_std_h"><c>logger_std_h(3)</c></seealso>,
+ <seealso marker="sasl:sasl_app"><c>sasl(6)</c></seealso></p>
</section>
</chapter>
diff --git a/lib/kernel/doc/src/logger_disk_log_h.xml b/lib/kernel/doc/src/logger_disk_log_h.xml
index 90cc4fec30..dfe2ab3275 100644
--- a/lib/kernel/doc/src/logger_disk_log_h.xml
+++ b/lib/kernel/doc/src/logger_disk_log_h.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2017</year>
+ <year>2017</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -33,106 +33,112 @@
<file>logger_disk_log_h.xml</file>
</header>
<module>logger_disk_log_h</module>
- <modulesummary>A disk_log based handler for the Logger
- application.</modulesummary>
+ <modulesummary>A disk_log based handler for Logger</modulesummary>
<description>
- <p>This is a handler for the Logger application that offers circular
- (wrapped) logs by using the disk_log application. Multiple instances
- of this handler can be added to logger, and each instance will print to
- its own disk_log file, created with the name and settings specified in
- the handler configuration.</p>
+ <p>This is a handler for Logger that offers circular
+ (wrapped) logs by using <seealso marker="disk_log"><c>disk_log</c></seealso>.
+ Multiple instances of this handler can be added to Logger, and each instance
+ prints to its own disk log file, created with the name and settings specified
+ in the handler configuration.</p>
<p>The default standard handler,
<seealso marker="logger_std_h"><c>logger_std_h</c></seealso>, can be
- replaced by a disk_log handler at startup of the kernel application.
+ replaced by a disk_log handler at startup of the Kernel application.
See an example of this below.</p>
- <p>The handler has an overload protection mechanism that will keep the handler
- process and the kernel application alive during a high load of log
- requests. How this feature works, and how to modify the configuration,
- is described in the
+ <p>The handler has an overload protection mechanism that keeps the handler
+ process and the Kernel application alive during high loads of log
+ events. How overload protection works, and how to configure it, is
+ described in the
<seealso marker="logger_chapter#overload_protection"><c>User's Guide</c>
</seealso>.</p>
<p>To add a new instance of the disk_log handler, use
<seealso marker="logger#add_handler-3"><c>logger:add_handler/3</c>
- </seealso>. The handler configuration argument is a map which may contain
+ </seealso>. The handler configuration argument is a map which can contain
general configuration parameters, as documented in the
<seealso marker="logger_chapter#handler_configuration"><c>User's Guide</c>
- </seealso>, as well as handler specific parameters.</p>
- <p>The settings for the disk_log log file should be specified with the
- key <c>disk_log_opts</c>. These settings are a subset of the disk_log
- datatype
- <seealso marker="disk_log#open-1"><c>dlog_option()</c></seealso>.</p>
- <p>Parameters in the <c>disk_log_opts</c> map:</p>
+ </seealso>, and handler specific parameters. The specific data
+ is stored in a sub map with the key <c>config</c>, and can contain the
+ following parameters:</p>
<taglist>
<tag><c>file</c></tag>
- <item>This is the full name of the disk_log log file.</item>
+ <item>
+ <p>This is the full name of the disk log file. The option
+ corresponds to the <c>name</c> property in the
+ <seealso marker="disk_log#open-1"><c>dlog_option()</c></seealso>
+ datatype.</p>
+ </item>
<tag><c>type</c></tag>
- <item>This is the disk_log type, <c>wrap</c> or <c>halt</c>. The
- default value is <c>wrap</c>.</item>
+ <item>
+ <p>This is the disk log type, <c>wrap</c> or <c>halt</c>. The option
+ corresponds to the <c>type</c> property in the
+ <seealso marker="disk_log#open-1"><c>dlog_option()</c></seealso>
+ datatype.</p>
+ <p>Defaults to <c>wrap</c>.</p>
+ </item>
<tag><c>max_no_files</c></tag>
- <item>This is the maximum number of files that disk_log will use
- for its circular logging. The default value is <c>10</c>. (The setting
- has no effect on a halt log).</item>
+ <item>
+ <p>This is the maximum number of files that disk_log uses
+ for its circular logging. The option
+ corresponds to the <c>MaxNoFiles</c> element in the <c>size</c> property in the
+ <seealso marker="disk_log#open-1"><c>dlog_option()</c></seealso>
+ datatype.</p>
+ <p>Defaults to <c>10</c>.</p>
+ <p>The setting has no effect on a halt log.</p>
+ </item>
<tag><c>max_no_bytes</c></tag>
- <item>This is the maximum number of bytes that will be written to
- a log file before disk_log proceeds with the next file in order (or
- generates an error in case of a full halt log). The default value for
- a wrap log is <c>1048576</c> bytes, and <c>infinity</c> for a halt
- log.</item>
- </taglist>
- <p>Specific configuration for the handler (represented as a sub map)
- is specified with the key <c>logger_disk_log_h</c>. It may contain the
- following parameter:</p>
- <taglist>
+ <item>
+ <p>This is the maximum number of bytes that is written to
+ a log file before disk_log proceeds with the next file in order, or
+ generates an error in case of a full halt log. The option
+ corresponds to the <c>MaxNoBytes</c> element in the <c>size</c> property in the
+ <seealso marker="disk_log#open-1"><c>dlog_option()</c></seealso>
+ datatype.</p>
+ <p>Defaults to <c>1048576</c> bytes for a wrap log, and
+ <c>infinity</c> for a halt log.</p>
+ </item>
<tag><c>filesync_repeat_interval</c></tag>
<item>
- <p>This value (in milliseconds) specifies how often the handler will
- do a disk_log sync operation in order to make sure that buffered data
- gets written to disk. The handler will repeatedly attempt this
- operation, but only perform it if something has actually been logged
- since the last sync. The default value is <c>5000</c> milliseconds.
- If <c>no_repeat</c> is set as value, the repeated sync operation is
- disabled. The user can also call the
- <seealso marker="logger_disk_log_h#disk_log_sync-1"><c>disk_log_sync/1</c>
- </seealso> function to perform a disk_log sync.</p></item>
+ <p>This value, in milliseconds, specifies how often the handler does
+ a disk_log sync operation to write buffered data to disk. The handler attempts
+ the operation repeatedly, but only performs a new sync if something has
+ actually been logged.</p>
+ <p>Defaults to <c>5000</c> milliseconds.</p>
+ <p>If <c>no_repeat</c> is set as value, the repeated sync operation
+ is disabled. The user can also call the
+ <seealso marker="logger_disk_log_h#filesync-1"><c>filesync/1</c>
+ </seealso> function to perform a disk_log sync.</p>
+ </item>
</taglist>
- <p>There are a number of other configuration parameters available, that are
- to be used for customizing the overload protection behaviour. The same
- parameters are used both in the standard handler and the disk_log handler,
- and are documented in the
+ <p>Other configuration parameters exist, to be used for customizing
+ the overload protection behaviour. The same parameters are used both in the
+ standard handler and the disk_log handler, and are documented in the
<seealso marker="logger_chapter#overload_protection"><c>User's Guide</c>
</seealso>.</p>
- <p>Note that when changing the configuration of the handler in runtime, by
- calling
- <seealso marker="logger#set_handler_config-2"><c>logger:set_handler_config/2
- or logger:set_handler_config/3</c></seealso>, the <c>disk_log_opts</c>
- settings may not be modified.</p>
+ <p>Notice that when changing the configuration of the handler in runtime, the
+ disk_log options (<c>file</c>, <c>type</c>, <c>max_no_files</c>,
+ <c>max_no_bytes</c>) must not be modified.</p>
<p>Example of adding a disk_log handler:</p>
<code type="none">
logger:add_handler(my_disk_log_h, logger_disk_log_h,
- #{level => error,
- filter_default => log,
- disk_log_opts =>
- #{file => "./my_disk_log",
- type => wrap,
- max_no_files => 4,
- max_no_bytes => 10000},
- logger_disk_log_h =>
- #{filesync_repeat_interval => 1000}}).
+ #{config => #{file => "./my_disk_log",
+ type => wrap,
+ max_no_files => 4,
+ max_no_bytes => 10000},
+ filesync_repeat_interval => 1000}}).
</code>
- <p>In order to use the disk_log handler instead of the default standard
- handler when starting en Erlang node, use the kernel configuration parameter
- <seealso marker="kernel_app#configuration"><c>logger_dest</c></seealso> with
- value <c>{disk_log,FileName}</c>. Example:</p>
+ <p>To use the disk_log handler instead of the default standard
+ handler when starting an Erlang node, change the Kernel default logger to
+ use <c>logger_disk_log_h</c>. Example:</p>
<code type="none">
-erl -kernel logger_dest '{disk_log,"./system_disk_log"}'
+erl -kernel logger '[{handler,default,logger_disk_log_h,
+ #{config => #{file => "./system_disk_log"}}}]'
</code>
</description>
<funcs>
<func>
- <name name="disk_log_sync" arity="1" clause_i="1"/>
+ <name name="filesync" arity="1" clause_i="1"/>
<fsummary>Writes buffered data to disk.</fsummary>
<desc>
<p>Write buffered data to disk.</p>
@@ -141,6 +147,12 @@ erl -kernel logger_dest '{disk_log,"./system_disk_log"}'
</funcs>
+ <section>
+ <title>See Also</title>
+ <p><seealso marker="logger"><c>logger(3)</c></seealso>,
+ <seealso marker="logger_std_h"><c>logger_std_h(3)</c></seealso>,
+ <seealso marker="disk_log"><c>disk_log(3)</c></seealso></p>
+ </section>
</erlref>
diff --git a/lib/kernel/doc/src/logger_filters.xml b/lib/kernel/doc/src/logger_filters.xml
index c34ec7d14c..90f1fcc270 100644
--- a/lib/kernel/doc/src/logger_filters.xml
+++ b/lib/kernel/doc/src/logger_filters.xml
@@ -36,15 +36,15 @@
<modulesummary>Filters to use with Logger.</modulesummary>
<description>
- <p>All functions exported from this module can be used as logger
+ <p>All functions exported from this module can be used as primary
or handler
- filters. See <seealso marker="logger#add_logger_filter-2">
- <c>logger:add_logger_filter/2</c></seealso>
+ filters. See <seealso marker="logger#add_primary_filter-2">
+ <c>logger:add_primary_filter/2</c></seealso>
and <seealso marker="logger#add_handler_filter-3">
<c>logger:add_handler_filter/3</c></seealso> for more information
about how filters are added.</p>
- <p>Filters are removed with <seealso marker="logger#remove_logger_filter-1">
- <c>logger:remove_logger_filter/1</c></seealso>
+ <p>Filters are removed with <seealso marker="logger#remove_primary_filter-1">
+ <c>logger:remove_primary_filter/1</c></seealso>
and <seealso marker="logger#remove_handler_filter-2">
<c>logger:remove_handler_filter/2</c></seealso>.</p>
</description>
@@ -52,58 +52,101 @@
<funcs>
<func>
<name name="domain" arity="2"/>
- <fsummary>Filter log events based on the domain field in metadata.</fsummary>
+ <fsummary>Filter log events based on the domain field in
+ metadata.</fsummary>
<desc>
- <p>This filter provides a way of filtering log events based on a
- <c>domain</c> field <c>Metadata</c>.</p>
-
- <p>The <c><anno>Extra</anno></c> parameter is specified when
- adding the filter
- via <seealso marker="logger#add_logger_filter-2">
- <c>logger:add_logger_filter/2</c></seealso>
- or <seealso marker="logger#add_handler_filter-3">
- <c>logger:add_handler_filter/3</c></seealso>.</p>
-
- <p>The filter compares the value of the <c>domain</c> field
- in the log event's metadata (<c>Domain</c>)
- to <c><anno>MatchDomain</anno></c> as follows:</p>
-
- <taglist>
- <tag><c><anno>Compare</anno> = starts_with</c></tag>
- <item><p>The filter matches if <c>MatchDomain</c> is a prefix
- of <c>Domain</c>.</p></item>
- <tag><c><anno>Compare</anno> = prefix_of</c></tag>
- <item><p>The filter matches if <c>Domain</c> is a prefix
- of <c>MatchDomain</c>.</p></item>
- <tag><c><anno>Compare</anno> = equals</c></tag>
- <item><p>The filter matches if <c>Domain</c> is equal
- to <c>MatchDomain</c>.</p></item>
- <tag><c><anno>Compare</anno> = no_domain</c></tag>
- <item><p>The filter matches if there is no domain field in
- metadata. In this case <c><anno>MatchDomain</anno></c> shall
- be <c>[]</c>.</p></item>
- </taglist>
-
- <p>If the filter matches and <c><anno>Action</anno> =
- log</c>, the log event is allowed. If the filter matches
- and <c><anno>Action</anno> = stop</c>, the log event is
- stopped.</p>
-
- <p>If the filter does not match, it returns <c>ignore</c>,
- meaning that other filters, or the value of the
- configuration parameter <c>filter_default</c>, will decide
- if the event is allowed or not.</p>
-
- <p>Log events that do not contain any domain field, will
- only match when <c><anno>Compare</anno> = no_domain</c>.</p>
-
- <p>Example: stop all events with
- domain <c>[beam,erlang,otp,sasl|_]</c></p>
-
- <code>
-logger:set_handler_config(h1,filter_default,log). % this is the default
-Filter = {fun logger_filters:domain/2,{stop,starts_with,[beam,erlang,otp,sasl]}}.
-logger:add_handler_filter(h1,no_sasl,Filter).
+ <p>This filter provides a way of filtering log events based on a
+ <c>domain</c> field in <c>Metadata</c>. This field is
+ optional, and the purpose of using it is to group log events
+ from, for example, a specific functional area. This allows
+ filtering or other specialized treatment in a Logger
+ handler.</p>
+
+ <p>A domain field must be a list of atoms, creating smaller
+ and more specialized domains as the list grows longer. The
+ greatest domain is <c>[]</c>, which comprises all possible
+ domains.</p>
+
+ <p>For example, consider the following domains:</p>
+ <pre>
+D1 = [otp]
+D2 = [otp, sasl]</pre>
+
+ <p><c>D1</c> is the greatest of the two, and is said to be a
+ super-domain of <c>D2</c>. <c>D2</c> is a
+ sub-domain <c>D1</c>. Both <c>D1</c> and <c>D2</c> are
+ sub-domains of <c>[]</c>.</p>
+
+ <p>The above domains are used for logs originating from
+ Erlang/OTP. D1 specifies that the log event comes from
+ Erlang/OTP in general, and D2 indicates that the log event
+ is a so
+ called <seealso marker="logger_chapter#sasl_reports">SASL
+ report</seealso>.</p>
+
+ <p>The <c><anno>Extra</anno></c> parameter to
+ the <c>domain/2</c> function is specified when adding the
+ filter via <seealso marker="logger#add_primary_filter-2">
+ <c>logger:add_primary_filter/2</c></seealso>
+ or <seealso marker="logger#add_handler_filter-3">
+ <c>logger:add_handler_filter/3</c></seealso>.</p>
+
+ <p>The filter compares the value of the <c>domain</c> field in
+ the log event's metadata (<c>Domain</c>) against
+ <c><anno>MatchDomain</anno></c>. The filter matches if the
+ value of <c>Compare</c> is:</p>
+
+ <taglist>
+ <tag><c>sub</c></tag>
+ <item>
+ <p>and <c>Domain</c> is equal to or a sub-domain
+ of <c>MatchDomain</c>, that is, if <c>MatchDomain</c> is
+ a prefix of <c>Domain</c>.</p>
+ </item>
+ <tag><c>super</c></tag>
+ <item>
+ <p>and <c>Domain</c> is equal to or a super-domain
+ of <c>MatchDomain</c>, that is, if <c>Domain</c> is a
+ prefix of <c>MatchDomain</c>.</p>
+ </item>
+ <tag><c>equal</c></tag>
+ <item>
+ <p>and <c>Domain</c> is equal to <c>MatchDomain</c>.</p>
+ </item>
+ <tag><c>not_equal</c></tag>
+ <item>
+ <p>and <c>Domain</c> differs from <c>MatchDomain</c>, or
+ if there is no domain field in metadata.</p>
+ </item>
+ <tag><c>undefined</c></tag>
+ <item>
+ <p>and there is no domain field in metadata. In this
+ case <c><anno>MatchDomain</anno></c> must be set
+ to <c>[]</c>.</p>
+ </item>
+ </taglist>
+
+ <p>If the filter matches and <c><anno>Action</anno></c> is
+ <c>log</c>, the log event is allowed. If the filter matches
+ and <c><anno>Action</anno></c> is <c>stop</c>, the log event
+ is stopped.</p>
+
+ <p>If the filter does not match, it returns <c>ignore</c>,
+ meaning that other filters, or the value of the
+ configuration parameter <c>filter_default</c>, decide if the
+ event is allowed or not.</p>
+
+ <p>Log events that do not contain any domain field, match only
+ when <c><anno>Compare</anno></c> is equal
+ to <c>undefined</c> or <c>not_equal</c>.</p>
+
+ <p>Example: stop all events with domain <c>[otp,
+ sasl | _]</c></p>
+
+ <code>
+logger:set_handler_config(h1, filter_default, log). % this is the default
+Filter = {fun logger_filters:domain/2, {stop, sub, [otp, sasl]}}.
+logger:add_handler_filter(h1, no_sasl, Filter).
ok</code>
</desc>
</func>
@@ -114,34 +157,44 @@ ok</code>
<desc>
<p>This filter provides a way of filtering log events based
on the log level. It matches log events by comparing the
- log level with a predefined <c>MatchLevel</c></p>
+ log level with a specified <c>MatchLevel</c></p>
<p>The <c><anno>Extra</anno></c> parameter is specified when
adding the filter
- via <seealso marker="logger#add_logger_filter-2">
- <c>logger:add_logger_filter/2</c></seealso>
+ via <seealso marker="logger#add_primary_filter-2">
+ <c>logger:add_primary_filter/2</c></seealso>
or <seealso marker="logger#add_handler_filter-3">
<c>logger:add_handler_filter/3</c></seealso>.</p>
<p>The filter compares the value of the event's log level
(<c>Level</c>) to <c><anno>MatchLevel</anno></c> by
calling <seealso marker="logger#compare_levels-2">
- <c>logger:compare_levels(Level,MatchLevel) -> CmpRet</c></seealso>. It
- matches the event if:</p>
-
- <list>
- <item><c>CmpRet = eq</c> and <c><anno>Operator</anno> =
- eq | lteq | gteq</c></item>
- <item><c>CmpRet = lt</c> and <c><anno>Operator</anno> =
- lt | lteq | neq</c></item>
- <item><c>CmpRet = gt</c> and <c><anno>Operator</anno> =
- gt | gteq | neq</c></item>
- </list>
-
- <p>If the filter matches and <c><anno>Action</anno> =
- log</c>, the log event is allowed. If the filter matches
- and <c><anno>Action</anno> = stop</c>, the log event is
- stopped.</p>
+ <c>logger:compare_levels(Level, MatchLevel)</c></seealso>.
+ The filter matches if the value
+ of <c><anno>Operator</anno></c> is:</p>
+
+ <taglist>
+ <tag><c>neq</c></tag>
+ <item><p>and the compare function returns <c>lt</c>
+ or <c>gt</c>.</p></item>
+ <tag><c>eq</c></tag>
+ <item><p>and the compare function returns <c>eq</c>.</p></item>
+ <tag><c>lt</c></tag>
+ <item><p>and the compare function returns <c>lt</c>.</p></item>
+ <tag><c>gt</c></tag>
+ <item><p>and the compare function returns <c>gt</c>.</p></item>
+ <tag><c>lteq</c></tag>
+ <item><p>and the compare function returns <c>lt</c>
+ or <c>eq</c>.</p></item>
+ <tag><c>gteq</c></tag>
+ <item><p>and the compare function returns <c>gt</c>
+ or <c>eq</c>.</p></item>
+ </taglist>
+
+ <p>If the filter matches and <c><anno>Action</anno></c> is
+ <c>log</c>, the log event is allowed. If the filter
+ matches and <c><anno>Action</anno></c> is <c>stop</c>, the
+ log event is stopped.</p>
<p>If the filter does not match, it returns <c>ignore</c>,
meaning that other filters, or the value of the
@@ -151,9 +204,9 @@ ok</code>
<p>Example: only allow debug level log events</p>
<code>
-logger:set_handler_config(h1,filter_default,stop).
-Filter = {fun logger_filters:level/2,{log,eq,debug}}.
-logger:add_handler_filter(h1,debug_only,Filter).
+logger:set_handler_config(h1, filter_default, stop).
+Filter = {fun logger_filters:level/2, {log, eq, debug}}.
+logger:add_handler_filter(h1, debug_only, Filter).
ok</code>
</desc>
</func>
@@ -165,9 +218,9 @@ ok</code>
<p>This filter matches all progress reports
from <c>supervisor</c> and <c>application_controller</c>.</p>
- <p>If <c><anno>Extra</anno> = log</c>, the progress reports
- are allowed. If <c><anno>Extra</anno> = stop</c>, the
- progress reports are stopped.</p>
+ <p>If <c><anno>Extra</anno></c> is <c>log</c>, the progress
+ reports are allowed. If <c><anno>Extra</anno></c>
+ is <c>stop</c>, the progress reports are stopped.</p>
<p>The filter returns <c>ignore</c> for all other log events.</p>
</desc>
@@ -180,9 +233,9 @@ ok</code>
<p>This filter matches all events originating from a process
that has its group leader on a remote node.</p>
- <p>If <c><anno>Extra</anno> = log</c>, the matching events
- are allowed. If <c><anno>Extra</anno> = stop</c>, the
- matching events are stopped.</p>
+ <p>If <c><anno>Extra</anno></c> is <c>log</c>, the matching
+ events are allowed. If <c><anno>Extra</anno></c>
+ is <c>stop</c>, the matching events are stopped.</p>
<p>The filter returns <c>ignore</c> for all other log events.</p>
</desc>
@@ -190,6 +243,12 @@ ok</code>
</funcs>
+ <section>
+ <title>See Also</title>
+ <p>
+ <seealso marker="logger"><c>logger(3)</c></seealso>
+ </p>
+ </section>
</erlref>
diff --git a/lib/kernel/doc/src/logger_formatter.xml b/lib/kernel/doc/src/logger_formatter.xml
index 7df4c88f40..5a060fd42b 100644
--- a/lib/kernel/doc/src/logger_formatter.xml
+++ b/lib/kernel/doc/src/logger_formatter.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2017</year>
+ <year>2017</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -36,194 +36,287 @@
<modulesummary>Default formatter for Logger.</modulesummary>
<description>
- <p>Each log handler has a configured formatter specified as a
+ <p>Each Logger handler has a configured formatter specified as a
module and a configuration term. The purpose of the formatter is
to translate the log events to a final printable string
- (<c>unicode:chardata()</c>) which can be written to the output
- device of the handler.</p>
+ (<seealso marker="stdlib:unicode#type-chardata"><c>unicode:chardata()</c>
+ </seealso>) which can be written to the output device of the
+ handler. See
+ sections <seealso marker="logger_chapter#handlers">Handlers</seealso>
+ and <seealso marker="logger_chapter#formatters">Formatters</seealso>
+ in the Kernel User's Guide for more information.</p>
<p><c>logger_formatter</c> is the default formatter used by
Logger.</p>
</description>
- <section>
- <title>Configuration</title>
- <p>The configuration term for <c>logger_formatter</c> is a map,
- and the following keys can be set as configuration
- parameters:</p>
- <taglist>
- <tag><c>chars_limit = pos_integer() | unlimited</c></tag>
- <item>
- <p>A positive integer representing the value of the option
- with the same name to be used when calling
- <seealso marker="stdlib:io_lib#format-3">io_lib:format/3</seealso>.
- This value limits the total number of characters printed
- for each log event. Notice that this is a soft limit. For a
- hard truncation limit, see option <c>max_size</c>.</p>
- <p>Default is <c>unlimited</c>.</p>
- <note>
- <p><c>chars_limit</c> has no effect on log messages on
- string form. These are expected to be short, but can still
- be truncated by the <c>max_size</c> parameter.</p>
- </note>
- </item>
- <tag><c>depth = pos_integer() | unlimited</c></tag>
- <item>
- <p>A positive integer representing the maximum depth to
- which terms shall be printed by this formatter. Format
- strings passed to this formatter are rewritten. The format
- controls ~p and ~w are replaced with ~P and ~W,
- respectively, and the value is used as the depth
- parameter. For details, see
- <seealso marker="stdlib:io#format-2">io:format/2,3</seealso>
- in STDLIB.</p>
- <p>Default is <c>unlimited</c>.</p>
- <note>
- <p><c>depth</c> has no effect on log messages on string
- form. These are expected to be short, but can still be
- truncated by the <c>max_size</c> parameter.</p>
- </note>
- </item>
- <tag><c>max_size = pos_integer() | unlimited</c></tag>
- <item>
- <p>A positive integer representing the absolute maximum size a
- string returned from this formatter can have. If the
- formatted string is longer, after possibly being limited
- by <c>chars_limit</c> or <c>depth</c>, it is truncated.</p>
- <p>Default is <c>unlimited</c>.</p>
- </item>
- <tag><c>single_line = boolean()</c></tag>
- <item>
- <p>If set to <c>true</c>, all newlines in the message are
- replaced with <c>", "</c>, and whitespaces following
- directly after newlines are removed. Note that newlines
- added by the <c>template</c> parameter are not replaced.</p>
- <p>Default is <c>true</c>.</p>
- </item>
- <tag><c>legacy_header = boolen()</c></tag>
- <item>
- <p>If set to <c>true</c> a header field is added to
- logger_formatter's part of <c>Metadata</c>. The value of
- this field is a string similar to the header created by the
- old <c>error_logger</c> event handlers. It can be included
- in the log event by adding the
- tuple <c>{logger_formatter,header}</c> to the template. See
- section <seealso marker="#default_templates">Default
- Templates</seealso> for more information.</p>
- <p>Default is <c>false</c>.</p>
- </item>
- <tag><c>report_cb = fun((</c><seealso marker="logger#type-report"><c>logger:report()</c></seealso><c>) -> {</c><seealso marker="stdlib:io#type-format"><c>io:format()</c></seealso><c>,[term()]})</c></tag>
- <item>
- <p>A report callback is used by the formatter to transform log
- messages on report form to a format string and
- arguments. The report callback can be specified in the
- metadata for the log event. If no report callback exist in
- metadata, <c>logger_formatter</c> will
- use <seealso marker="logger#format_report-1">
- <c>logger:format_report/1</c></seealso> as default
- callback.</p>
- <p>If this configuration parameter is set, it replaces both
- the default report callback, and any report callback found
- in metadata. That is, all reports are converted by this
- configured function.</p>
- <p>The value must be a function with arity 1,
- returning <c>{Format,Args}</c>, and it will be called with a
- report as only argument.</p>
- </item>
- <tag><c>template = </c><seealso marker="#type-template"><c>template()</c></seealso></tag>
- <item>
- <p>The template is a list of atoms, tuples and strings. The
+
+ <datatypes>
+ <datatype>
+ <name name="config"/>
+ <desc>
+ <p>The configuration term for <c>logger_formatter</c> is a
+ <seealso marker="stdlib:maps">map</seealso>, and the
+ following keys can be set as configuration parameters:</p>
+ <taglist>
+ <tag><marker id="chars_limit"/>
+ <c>chars_limit = integer() > 0 | unlimited</c></tag>
+ <item>
+ <p>A positive integer representing the value of the option
+ with the same name to be used when calling
+ <seealso marker="stdlib:io_lib#format-3">
+ <c>io_lib:format/3</c></seealso>.
+ This value limits the total number of characters printed
+ for each log event. Notice that this is a soft limit. For a
+ hard truncation limit, see option <c>max_size</c>.</p>
+ <p>Defaults to <c>unlimited</c>.</p>
+ </item>
+ <tag><marker id="depth"/><c>depth = integer() > 0 | unlimited</c></tag>
+ <item>
+ <p>A positive integer representing the maximum depth to
+ which terms shall be printed by this formatter. Format
+ strings passed to this formatter are rewritten. The
+ format controls ~p and ~w are replaced with ~P and ~W,
+ respectively, and the value is used as the depth
+ parameter. For details, see
+ <seealso marker="stdlib:io#format-2"><c>io:format/2,3</c></seealso>
+ in STDLIB.</p>
+ <p>Defaults to <c>unlimited</c>.</p>
+ </item>
+ <tag><c>encoding = </c><seealso marker="stdlib:unicode#type-encoding">
+ <c>unicode:encoding()</c></seealso></tag>
+ <item>
+ <p>This parameter must reflect the encoding of the device
+ that the handler prints to.</p>
+ <p>Defaults to <c>utf8</c></p>
+ </item>
+ <tag><c>legacy_header = boolean()</c></tag>
+ <item>
+ <p>If set to <c>true</c> a header field is added to
+ logger_formatter's part of <c>Metadata</c>. The value of
+ this field is a string similar to the header created by
+ the
+ old <seealso marker="error_logger"><c>error_logger</c></seealso>
+ event handlers. It can be included in the log event by
+ adding the list <c>[logger_formatter,header]</c> to the
+ template. See the description of
+ the <seealso marker="#type-template"><c>template()</c></seealso>
+ type for more information.</p>
+ <p>Defaults to <c>false</c>.</p>
+ </item>
+ <tag><marker id="max_size"/>
+ <c>max_size = integer() > 0 | unlimited</c></tag>
+ <item>
+ <p>A positive integer representing the absolute maximum size a
+ string returned from this formatter can have. If the
+ formatted string is longer, after possibly being limited
+ by <c>chars_limit</c> or <c>depth</c>, it is truncated.</p>
+ <p>Defaults to <c>unlimited</c>.</p>
+ </item>
+ <tag><c>report_cb = </c><seealso marker="logger#type-report_cb">
+ <c>logger:report_cb()</c></seealso></tag>
+ <item>
+ <p>A report callback is used by the formatter to transform
+ log messages on report form to a format string and
+ arguments. The report callback can be specified in the
+ metadata for the log event. If no report callback exists
+ in metadata, <c>logger_formatter</c> will
+ use <seealso marker="logger#format_report-1">
+ <c>logger:format_report/1</c></seealso> as default
+ callback.</p>
+ <p>If this configuration parameter is set, it replaces
+ both the default report callback, and any report
+ callback found in metadata. That is, all reports are
+ converted by this configured function.</p>
+ </item>
+ <tag><c>single_line = boolean()</c></tag>
+ <item>
+ <p>If set to <c>true</c>, each log event is printed as a
+ single line. To achieve this, <c>logger_formatter</c>
+ sets the field width to <c>0</c> for all <c>~p</c>
+ and <c>~P</c> control sequences in the format a string
+ (see <seealso marker="stdlib:io#format-2">
+ <c>io:format/2</c></seealso>), and replaces all
+ newlines in the message with <c>", "</c>. White spaces
+ following directly after newlines are removed. Notice
+ that newlines added by the <c>template</c> parameter are
+ not replaced.</p>
+ <p>Defaults to <c>true</c>.</p>
+ </item>
+ <tag><marker id="template"/>
+ <c>template = </c><seealso marker="#type-template"><c>template()</c>
+ </seealso></tag>
+ <item>
+ <p>The template describes how the formatted string is
+ composed by combining different data values from the log
+ event. See the description of
+ the <seealso marker="#type-template"><c>template()</c></seealso>
+ type for more information about this.</p>
+ </item>
+ <tag><c>time_designator = byte()</c></tag>
+ <item>
+ <p>Timestamps are formatted according to RFC3339, and the
+ time designator is the character used as date and time
+ separator.</p>
+ <p>Defaults to <c>$T</c>.</p>
+ <p>The value of this parameter is used as
+ the <c>time_designator</c> option
+ to <seealso marker="stdlib:calendar#system_time_to_rfc3339-2">
+ <c>calendar:system_time_to_rcf3339/2</c></seealso>.</p>
+ </item>
+ <tag><c>time_offset = integer() | [byte()]</c></tag>
+ <item>
+ <p>The time offset, either a string or an integer, to be
+ used when formatting the timestamp.</p>
+ <p>An empty string is interpreted as local time. The
+ values <c>"Z"</c>, <c>"z"</c> or <c>0</c> are
+ interpreted as Universal Coordinated Time (UTC).</p>
+ <p>Strings, other than <c>"Z"</c>, <c>"z"</c>,
+ or <c>""</c>, must be on the form <c>±[hh]:[mm]</c>, for
+ example <c>"-02:00"</c> or <c>"+00:00"</c>.</p>
+ <p>Integers must be in microseconds, meaning that the
+ offset <c>7200000000</c> is equivalent
+ to <c>"+02:00"</c>.</p>
+ <p>Defaults to an empty string, meaning that timestamps
+ are displayed in local time. However, for backwards
+ compatibility, if the SASL configuration
+ parameter <seealso marker="sasl:sasl_app#utc_log">
+ <c>utc_log</c></seealso><c>=true</c>, the default is
+ changed to <c>"Z"</c>, meaning that timestamps are displayed
+ in UTC.</p>
+ <p>The value of this parameter is used as
+ the <c>offset</c> option
+ to <seealso marker="stdlib:calendar#system_time_to_rfc3339-2">
+ <c>calendar:system_time_to_rcf3339/2</c></seealso>.</p>
+ </item>
+ </taglist>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="metakey"/>
+ <desc>
+ <p></p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="template"/>
+ <desc>
+ <p>The template is a list of atoms, atom lists, tuples and strings. The
atoms <c>level</c> or <c>msg</c>, are treated as
placeholders for the severity level and the log message,
- repectively. Other atoms or tuples are interpreted as
+ respectively. Other atoms or atom lists are interpreted as
placeholders for metadata, where atoms are expected to match
- top level keys, and tuples represent paths to sub keys when
+ top level keys, and atom lists represent paths to sub keys when
the metadata is a nested map. For example the
- tuple <c>{key1,key2}</c> is replaced by the value of
+ list <c>[key1,key2]</c> is replaced by the value of
the <c>key2</c> field in the nested map below. The
atom <c>key1</c> on its own is replaced by the complete
value of the <c>key1</c> field. The values are converted to
strings.</p>
-<code>
-#{key1=>#{key2=>my_value,
- ...}
+ <code>
+#{key1 => #{key2 => my_value,
+ ...}
...}</code>
+ <p>Tuples in the template express if-exist tests for metadata
+ keys. For example, the following tuple says that
+ if <c>key1</c> exists in the metadata map,
+ print <c>"key1=Value"</c>, where <c>Value</c> is the value
+ that <c>key1</c> is associated with in the metadata map. If
+ <c>key1</c> does not exist, print nothing.</p>
+ <code>
+{key1, ["key1=",key1], []}</code>
+
<p>Strings in the template are printed literally.</p>
- <p>The default template differs depending on the values
- of <c>legacy_header</c>
- and <c>single_line</c>. See <seealso marker="#default_templates">Default
- Templates</seealso> for more information</p>
- </item>
- <tag><c>utc = boolean()</c></tag>
- <item>
- <p>If set to <c>true</c>, all dates are displayed in Universal
- Coordinated Time.</p>
- <p>Default is <c>false</c>.</p>
- </item>
- </taglist>
- </section>
+ <p>The default value for the <c>template</c> configuration
+ parameter depends on the value of the <c>single_line</c>
+ and <c>legacy_header</c> configuration parameters as
+ follows.</p>
- <section>
- <marker id="default_templates"/>
- <title>Default templates</title>
+ <p>The log event used in the examples is:</p>
+ <code>
+?LOG_ERROR("name: ~p~nexit_reason: ~p", [my_name, "It crashed"])</code>
- <p>The default value for the <c>template</c> configuration
- parameter depends on the value of <c>single_line</c>
- and <c>legacy_header</c> as follows.</p>
+ <taglist>
+ <tag><c>legacy_header = true, single_line = false</c></tag>
+ <item>
+ <p>Default
+ template: <c>[[logger_formatter,header],"\n",msg,"\n"]</c></p>
- <p>The log event used in the examples is:</p>
- <code>
-?LOG_ERROR("name: ~p~nexit_reason: ~p",[my_reg_name,"It crashed"])</code>
+ <p>Example log entry:</p>
+ <code type="none">
+=ERROR REPORT==== 17-May-2018::18:30:19.453447 ===
+name: my_name
+exit_reason: "It crashed"</code>
- <taglist>
- <tag><c>legacy_header=true</c></tag>
- <item>
- <p>Default template: <c>[{logger_formatter,header},"\n",msg,"\n"]</c></p>
+ <p>Notice that all eight levels can occur in the heading,
+ not only <c>ERROR</c>, <c>WARNING</c> or <c>INFO</c> as
+ <seealso marker="error_logger"><c>error_logger</c></seealso>
+ produces. And microseconds are added at the end of the
+ timestamp.</p>
+ </item>
- <p>Example log entry:</p>
- <code>
-=ERROR REPORT==== 29-Dec-2017::13:30:51.245123 ===
-name: my_reg_name
-exit_reason: "It crashed"</code>
+ <tag><c>legacy_header = true, single_line = true</c></tag>
+ <item>
+ <p>Default
+ template: <c>[[logger_formatter,header],"\n",msg,"\n"]</c></p>
- <p>Notice that all eight levels might occur in the heading,
- not only <c>ERROR</c>, <c>WARNING</c> or <c>INFO</c> as the
- old <c>error_logger</c> produced. And microseconds are
- added at the end of the timestamp.</p>
- </item>
+ <p>Notice that the template is here the same as
+ for <c>single_line=false</c>, but the resulting log entry
+ differs in that there is only one line after the
+ heading:</p>
+ <code type="none">
+=ERROR REPORT==== 17-May-2018::18:31:06.952665 ===
+name: my_name, exit_reason: "It crashed"</code>
+ </item>
- <tag><c>single_line=true</c></tag>
- <item>
- <p>Default template: <c>[time," ",level,": ",msg,"\n"]</c></p>
+ <tag><c>legacy_header = false, single_line = true</c></tag>
+ <item>
+ <p>Default template: <c>[time," ",level,": ",msg,"\n"]</c></p>
- <p>Example log entry:</p>
- <code>2017-12-29 13:31:49.640317 error: name: my_reg_name, exit_reason: "It crashed"</code>
- </item>
+ <p>Example log entry:</p>
+ <code type="none">
+2018-05-17T18:31:31.152864+02:00 error: name: my_name, exit_reason: "It crashed"</code>
+ </item>
- <tag><c>legacy_header=false, single_line=false</c></tag>
- <item>
- <p>Default template: <c>[time," ",level,":\n",msg,"\n"]</c></p>
+ <tag><c>legacy_header = false, single_line = false</c></tag>
+ <item>
+ <p>Default template: <c>[time," ",level,":\n",msg,"\n"]</c></p>
- <p>Example log entry:</p>
- <code>
-2017-12-29 13:32:25.191925 error:
-name: my_reg_name
+ <p>Example log entry:</p>
+ <code type="none">
+2018-05-17T18:32:20.105422+02:00 error:
+name: my_name
exit_reason: "It crashed"</code>
- </item>
- </taglist>
- </section>
-
- <datatypes>
- <datatype>
- <name name="template"/>
- <desc>
+ </item>
+ </taglist>
</desc>
</datatype>
</datatypes>
<funcs>
<func>
+ <name name="check_config" arity="1"/>
+ <fsummary>Validates the given formatter configuration.</fsummary>
+ <desc>
+ <p>The function is called by Logger when the formatter
+ configuration for a handler is set or modified. It
+ returns <c>ok</c> if the configuration is valid,
+ and <c>{error,term()}</c> if it is faulty.</p>
+ <p>The following Logger API functions can trigger this callback:</p>
+ <list>
+ <item><seealso marker="logger#add_handler-3">
+ <c>logger:add_handler/3</c></seealso></item>
+ <item><seealso marker="logger#set_handler_config-2">
+ <c>logger:set_handler_config/2,3</c></seealso></item>
+ <item><seealso marker="logger#update_handler_config-2">
+ <c>logger:updata_handler_config/2</c></seealso></item>
+ <item><seealso marker="logger#update_formatter_config-2">
+ <c>logger:update_formatter_config/2</c></seealso></item>
+ </list>
+ </desc>
+ </func>
+ <func>
<name name="format" arity="2"/>
<fsummary>Formats the given message.</fsummary>
<desc>
@@ -231,23 +324,38 @@ exit_reason: "It crashed"</code>
handlers. The log event is processed as follows:</p>
<list>
<item>If the message is on report form, it is converted to
- <c>{Format,Args}</c> by calling the report
- callback.</item>
- <item>The size is limited according to the values of
- configuration parameters <c>chars_limit</c>
- and <c>depth</c>. Notice that this does not apply to
- messages on string form.</item>
+ <c>{Format,Args}</c> by calling the report callback. See
+ section <seealso marker="logger_chapter#log_message">Log
+ Message</seealso> in the Kernel User's Guide for more
+ information about report callbacks and valid forms of log
+ messages.</item>
+ <item>The message size is limited according to the values of
+ configuration parameters <seealso marker="#chars_limit">
+ <c>chars_limit</c></seealso>
+ and <seealso marker="#depth"><c>depth</c></seealso>.</item>
<item>The full log entry is composed according to
- the <c>template</c>.</item>
+ the <seealso marker="#template"><c>template</c></seealso>.</item>
<item>If the final string is too long, it is truncated
according to the value of configuration
- parameter <c>max_size</c>.</item>
+ parameter <seealso marker="#max_size"><c>max_size</c></seealso>.</item>
</list>
</desc>
</func>
-
</funcs>
+ <section>
+ <title>See Also</title>
+ <p>
+ <seealso marker="stdlib:calendar"><c>calendar(3)</c></seealso>,
+ <seealso marker="error_logger"><c>error_logger(3)</c></seealso>,
+ <seealso marker="stdlib:io"><c>io(3)</c></seealso>,
+ <seealso marker="stdlib:io_lib"><c>io_lib(3)</c></seealso>,
+ <seealso marker="logger"><c>logger(3)</c></seealso>,
+ <seealso marker="stdlib:maps"><c>maps(3)</c></seealso>,
+ <seealso marker="sasl:sasl_app"><c>sasl(6)</c></seealso>,
+ <seealso marker="stdlib:unicode"><c>unicode(3)</c></seealso>
+ </p>
+ </section>
</erlref>
diff --git a/lib/kernel/doc/src/logger_std_h.xml b/lib/kernel/doc/src/logger_std_h.xml
index fe9b9ca5a9..b526ed037d 100644
--- a/lib/kernel/doc/src/logger_std_h.xml
+++ b/lib/kernel/doc/src/logger_std_h.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2017</year>
+ <year>2017</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -33,87 +33,78 @@
<file>logger_std_h.xml</file>
</header>
<module>logger_std_h</module>
- <modulesummary>Default handler for the Logger application.</modulesummary>
+ <modulesummary>Standard handler for Logger.</modulesummary>
<description>
- <p>This is the default handler for the Logger
- application. Multiple instances of this handler can be added to
- logger, and each instance will print logs to <c>standard_io</c>,
- <c>standard_error</c> or to file. The default instance that starts
- with kernel is named <c>logger_std_h</c> - which is the name to be used
- for reconfiguration.</p>
- <p>The handler has an overload protection mechanism that will keep the handler
- process and the kernel application alive during a high load of log
- requests. How this feature works, and how to modify the configuration,
- is described in the
+ <p>This is the standard handler for Logger.
+ Multiple instances of this handler can be added to
+ Logger, and each instance prints logs to <c>standard_io</c>,
+ <c>standard_error</c>, or to file.</p>
+ <p>The handler has an overload protection mechanism that keeps the handler
+ process and the Kernel application alive during high loads of log
+ events. How overload protection works, and how to configure it, is
+ described in the
<seealso marker="logger_chapter#overload_protection"><c>User's Guide</c>
</seealso>.</p>
<p>To add a new instance of the standard handler, use
<seealso marker="logger#add_handler-3"><c>logger:add_handler/3</c>
- </seealso>. The handler configuration argument is a map which may contain
- general configuration parameters, as documented in the
+ </seealso>. The handler configuration argument is a map which can contain
+ general configuration parameters, as documented in the
<seealso marker="logger_chapter#handler_configuration"><c>User's Guide</c>
- </seealso>, as well as handler specific parameters. The specific parameters
- are stored in a sub map with the key <c>logger_std_h</c>. The following
- keys and values may be specified:</p>
+ </seealso>, and handler specific parameters. The specific data
+ is stored in a sub map with the key <c>config</c>, and can contain the
+ following parameters:</p>
<taglist>
- <tag><c>type</c></tag>
+ <tag><marker id="type"/><c>type</c></tag>
<item>
- <p>This will have the value <c>standard_io</c>, <c>standard_error</c>,
- <c>{file,LogFileName}</c>, or <c>{file,LogFileName,LogFileOpts}</c>,
- where <c>standard_io</c> is the default value for type. It's recommended
- to not specify <c>LogFileOpts</c> if not absolutely necessary. The
- default options used by the handler to open a file for logging are:
- <c>raw</c>, <c>append</c> and <c>delayed_write</c>. The standard
- handler does not have support for circular logging. Use the
- <seealso marker="logger_disk_log_h"><c>logger_disk_log_h</c>
- </seealso> handler for this.</p></item>
+ <p>This has the value <c>standard_io</c>, <c>standard_error</c>,
+ <c>{file,LogFileName}</c>, or <c>{file,LogFileName,LogFileOpts}</c>.</p>
+ <p> Defaults to <c>standard_io</c>.</p>
+ <p>It is recommended not to specify <c>LogFileOpts</c> unless absolutely
+ necessary. The default options used by the handler to open a file for logging are
+ <c>raw</c>, <c>append</c>, and <c>delayed_write</c>. Notice that the standard
+ handler does not have support for circular logging. Use the disk_log handler,
+ <seealso marker="logger_disk_log_h"><c>logger_disk_log_h</c></seealso>,
+ for this.</p>
+ </item>
<tag><c>filesync_repeat_interval</c></tag>
<item>
- <p>This value (in milliseconds) specifies how often the handler will
- do a file sync operation in order to make sure that buffered data gets
- written to disk. The handler will repeatedly attempt this
- operation, but only perform it if something has actually been logged
- since the last sync. The default value is <c>5000</c> milliseconds.
- If <c>no_repeat</c> is set as value, the repeated file sync operation
- is disabled, and it will be the operating system settings that determine
- how quickly or slowly data gets written to disk. The user can also call
+ <p>This value, in milliseconds, specifies how often the handler does
+ a file sync operation to write buffered data to disk. The handler attempts
+ the operation repeatedly, but only performs a new sync if something has
+ actually been logged.</p>
+ <p>Defaults to <c>5000</c> milliseconds.</p>
+ <p>If <c>no_repeat</c> is set as value, the repeated file sync operation
+ is disabled, and it is the operating system settings that determine
+ how quickly or slowly data is written to disk. The user can also call
the <seealso marker="logger_std_h#filesync-1"><c>filesync/1</c></seealso>
- function to perform a file sync.</p></item>
+ function to perform a file sync.</p>
+ </item>
</taglist>
- <p>There are a number of other configuration parameters available, that are
- to be used for customizing the overload protection behaviour. The same
- parameters are used both in the standard handler and the disk_log handler,
- and are documented in the
+ <p>Other configuration parameters exist, to be used for customizing
+ the overload protection behaviour. The same parameters are used both in the
+ standard handler and the disk_log handler, and are documented in the
<seealso marker="logger_chapter#overload_protection"><c>User's Guide</c>
</seealso>.</p>
- <p>Note that when changing the configuration of the handler in runtime, by
- calling
- <seealso marker="logger#set_handler_config-2"><c>logger:set_handler_config/2</c>
- </seealso>, or
- <seealso marker="logger#set_handler_config-3"><c>logger:set_handler_config/3</c>
- </seealso>,
- the <c>type</c> parameter may not be modified.</p>
+ <p>Notice that if changing the configuration of the handler in runtime,
+ the <c>type</c> parameter must not be modified.</p>
<p>Example of adding a standard handler:</p>
<code type="none">
logger:add_handler(my_standard_h, logger_std_h,
- #{level => info,
- filter_default => log,
- logger_std_h =>
- #{type => {file,"./system_info.log"},
- filesync_repeat_interval => 1000}}).
+ #{config => #{type => {file,"./system_info.log"},
+ filesync_repeat_interval => 1000}}).
</code>
- <p>In order to configure the default handler (that starts initially with
- the kernel application) to log to file instead of <c>standard_io</c>,
- use the kernel configuration parameter
- <seealso marker="kernel_app#configuration"><c>logger_dest</c></seealso> with
- value <c>{file,FileName}</c>. Example:</p>
+ <p>To set the default handler, that starts initially with
+ the Kernel application, to log to file instead of <c>standard_io</c>,
+ change the Kernel default logger configuration. Example:</p>
<code type="none">
-erl -kernel logger_dest '{file,"./erl.log"}'
+erl -kernel logger '[{handler,default,logger_std_h,
+ #{config => #{type => {file,"./log.log"}}}}]'
</code>
<p>An example of how to replace the standard handler with a disk_log handler
- at startup can be found in the manual of
- <seealso marker="logger_disk_log_h"><c>logger_disk_log_h</c></seealso>.</p>
+ at startup is found in the
+ <seealso marker="logger_disk_log_h"><c>logger_disk_log_h</c></seealso>
+ manual.</p>
</description>
<funcs>
@@ -128,6 +119,12 @@ erl -kernel logger_dest '{file,"./erl.log"}'
</funcs>
+ <section>
+ <title>See Also</title>
+ <p><seealso marker="logger"><c>logger(3)</c></seealso>,
+ <seealso marker="logger_disk_log_h">
+ <c>logger_disk_log_h(3)</c></seealso></p>
+ </section>
</erlref>
diff --git a/lib/kernel/doc/src/net_kernel.xml b/lib/kernel/doc/src/net_kernel.xml
index a30d28d55a..d3bd7365e2 100644
--- a/lib/kernel/doc/src/net_kernel.xml
+++ b/lib/kernel/doc/src/net_kernel.xml
@@ -102,8 +102,10 @@ $ <input>erl -sname foobar</input></pre>
<fsummary>Establish a connection to a node.</fsummary>
<desc>
<p>Establishes a connection to <c><anno>Node</anno></c>. Returns
- <c>true</c> if successful, <c>false</c> if not, and <c>ignored</c>
- if the local node is not alive.</p>
+ <c>true</c> if a connection was established or was already
+ established or if <c><anno>Node</anno></c> is the local node
+ itself. Returns <c>false</c> if the connection attempt failed, and
+ <c>ignored</c> if the local node is not alive.</p>
</desc>
</func>
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index 09844f1502..5884f93878 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,325 @@
</header>
<p>This document describes the changes made to the Kernel application.</p>
+<section><title>Kernel 6.0</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Clarify the documentation of <c>rpc:multicall/5</c>.
+ </p>
+ <p>
+ Own Id: OTP-10551</p>
+ </item>
+ <item>
+ <p>
+ The DNS resolver when getting econnrefused from a server
+ retained an invalid socket so look up towards the next
+ server(s) also failed.</p>
+ <p>
+ Own Id: OTP-13133 Aux Id: PR-1557 </p>
+ </item>
+ <item>
+ <p>
+ No resolver backend returns V4Mapped IPv6 addresses any
+ more. This was inconsistent before, some did, some did
+ not. To facilitate working with such addresses a new
+ function <c>inet:ipv4_mapped_ipv6_address/1</c> has been
+ added.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-13761 Aux Id: ERL-503 </p>
+ </item>
+ <item>
+ <p>
+ The type specifications for <c>file:posix/0</c> and
+ <c>inet:posix/0</c> have been updated according to which
+ errors file and socket operations should be able to
+ return.</p>
+ <p>
+ Own Id: OTP-14019 Aux Id: ERL-550 </p>
+ </item>
+ <item>
+ <p>
+ Fix name resolving in IPv6 only environments when doing
+ the initial distributed connection.</p>
+ <p>
+ Own Id: OTP-14501</p>
+ </item>
+ <item>
+ <p> File operations used to accept <seealso
+ marker="kernel:file#type-name_all">filenames</seealso>
+ containing null characters (integer value zero). This
+ caused the name to be truncated and in some cases
+ arguments to primitive operations to be mixed up.
+ Filenames containing null characters inside the filename
+ are now <em>rejected</em> and will cause primitive file
+ operations to fail. </p> <p> Also environment variable
+ operations used to accept <seealso
+ marker="kernel:os#type-env_var_name">names</seealso> and
+ <seealso
+ marker="kernel:os#type-env_var_value">values</seealso> of
+ environment variables containing null characters (integer
+ value zero). This caused operations to silently produce
+ erroneous results. Environment variable names and values
+ containing null characters inside the name or value are
+ now <em>rejected</em> and will cause environment variable
+ operations to fail. </p> <p>Primitive environment
+ variable operations also used to accept the <c>$=</c>
+ character in environment variable names causing various
+ problems. <c>$=</c> characters in environment variable
+ names are now also <em>rejected</em>. </p> <p>Also
+ <seealso
+ marker="kernel:os#cmd/1"><c>os:cmd/1</c></seealso> now
+ reject null characters inside its <seealso
+ marker="kernel:os#type-os_command">command</seealso>.
+ </p> <p><seealso
+ marker="erts:erlang#open_port/2"><c>erlang:open_port/2</c></seealso>
+ will also reject null characters inside the port name
+ from now on.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14543 Aux Id: ERL-370 </p>
+ </item>
+ <item>
+ <p><c>os:putenv</c> and <c>os:getenv</c> no longer access
+ the process environment directly and instead work on a
+ thread-safe emulation. The only observable difference is
+ that it's <em>not</em> kept in sync with libc
+ <c>getenv(3)</c> / <c>putenv(3)</c>, so those who relied
+ on that behavior in drivers or NIFs will need to add
+ manual synchronization.</p> <p>On Windows this means that
+ you can no longer resolve DLL dependencies by modifying
+ the <c>PATH</c> just before loading the driver/NIF. To
+ make this less of a problem, the emulator now adds the
+ target DLL's folder to the DLL search path.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14666</p>
+ </item>
+ <item>
+ <p>
+ Fixed connection tick toward primitive hidden nodes
+ (erl_interface) that could cause faulty tick timeout in
+ rare cases when payload data is sent to hidden node but
+ not received.</p>
+ <p>
+ Own Id: OTP-14681</p>
+ </item>
+ <item>
+ <p>
+ Make group react immediately on an EXIT-signal from shell
+ in e.g ssh.</p>
+ <p>
+ Own Id: OTP-14991 Aux Id: PR1705 </p>
+ </item>
+ <item>
+ <p>
+ Calls to <c>gen_tcp:send/2</c> on closed sockets now
+ returns <c>{error, closed}</c> instead of
+ <c>{error,enotconn}</c>.</p>
+ <p>
+ Own Id: OTP-15001</p>
+ </item>
+ <item>
+ <p>
+ The <c>included_applications</c> key are no longer
+ duplicated as application environment variable. Earlier,
+ the included applications could be read both with
+ <c>application:get[_all]_env(...)</c> and
+ <c>application:get[_all]_key(...)</c> functions. Now, it
+ can only be read with
+ <c>application:get[_all]_key(...)</c>.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15071</p>
+ </item>
+ <item>
+ <p>Owner and group changes through
+ <c>file:write_file_info</c>, <c>file:change_owner</c>,
+ and <c>file:change_group</c> will no longer report
+ success on permission errors.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15118</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>A new logging API is added to Erlang/OTP, see the
+ <seealso
+ marker="kernel:logger"><c>logger(3)</c></seealso> manual
+ page, and section <seealso
+ marker="kernel:logger_chapter">Logging</seealso> in the
+ Kernel User's Guide.</p>
+ <p>Calls to <c>error_logger</c> are automatically
+ redirected to the new API, and legacy error logger event
+ handlers can still be used. It is, however, recommended
+ to use the Logger API directly when writing new code.</p>
+ <p>Notice the following potential incompatibilities:</p>
+ <list> <item><p>Kernel configuration parameters
+ <c>error_logger</c> still works, but is overruled if the
+ default handler's output destination is configured with
+ Kernel configuration parameter <c>logger</c>.</p> <p>In
+ general, parameters for configuring error logger are
+ overwritten by new parameters for configuring
+ Logger.</p></item> <item><p>The concept of SASL error
+ logging is deprecated, meaning that by default the SASL
+ application does not affect which log events are
+ logged.</p> <p>By default, supervisor reports and crash
+ reports are logged by the default Logger handler started
+ by Kernel, and end up at the same destination (terminal
+ or file) as other standard log event from Erlang/OTP.</p>
+ <p>Progress reports are not logged by default, but can be
+ enabled by setting the primary log level to info, for
+ example with the Kernel configuration parameter
+ <c>logger_level</c>.</p> <p>To obtain backwards
+ compatibility with the SASL error logging functionality
+ from earlier releases, set Kernel configuration parameter
+ <c>logger_sasl_compatible</c> to <c>true</c>. This
+ prevents the default Logger handler from logging any
+ supervisor-, crash-, or progress reports. Instead, SASL
+ adds a separate Logger handler during application start,
+ which takes care of these log events. The SASL
+ configuration parameters <c>sasl_error_logger</c> and
+ <c>sasl_errlog_type</c> specify the destination (terminal
+ or file) and severity level to log for these
+ events.</p></item></list>
+ <p>
+ Since Logger is new in Erlang/OTP 21.0, we do reserve the
+ right to introduce changes to the Logger API and
+ functionality in patches following this release. These
+ changes might or might not be backwards compatible with
+ the initial version.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-13295</p>
+ </item>
+ <item>
+ <p>
+ The function <c>inet:i/0</c> has been documented.</p>
+ <p>
+ Own Id: OTP-13713 Aux Id: PR-1645 </p>
+ </item>
+ <item>
+ <p>
+ Typespecs for <c>netns</c> and <c>bind_to_device</c>
+ options have been added to <c>gen_tcp</c>, <c>gen_udp</c>
+ and <c>gen_sctp</c> functions.</p>
+ <p>
+ Own Id: OTP-14359 Aux Id: PR-1816 </p>
+ </item>
+ <item>
+ <p>
+ New functionality for implementation of alternative
+ carriers for the Erlang distribution has been introduced.
+ This mainly consists of support for usage of distribution
+ controller processes (previously only ports could be used
+ as distribution controllers). For more information see
+ <seealso marker="erts:alt_dist#distribution_module">ERTS
+ User's Guide ➜ How to implement an Alternative Carrier
+ for the Erlang Distribution ➜ Distribution
+ Module</seealso>.</p>
+ <p>
+ Own Id: OTP-14459</p>
+ </item>
+ <item>
+ <p><c>seq_trace</c> labels may now be any erlang
+ term.</p>
+ <p>
+ Own Id: OTP-14899</p>
+ </item>
+ <item>
+ <p>
+ The SSL distribution protocol <c>-proto inet_tls</c> has
+ stopped setting the SSL option
+ <c>server_name_indication</c>. New verify funs for client
+ and server in <c>inet_tls_dist</c> has been added, not
+ documented yet, that checks node name if present in peer
+ certificate. Usage is still also yet to be documented.</p>
+ <p>
+ Own Id: OTP-14969 Aux Id: OTP-14465, ERL-598 </p>
+ </item>
+ <item>
+ <p>
+ Changed timeout of <c>gen_server</c> calls to <c>auth</c>
+ server from default 5 seconds to <c>infinity</c>.</p>
+ <p>
+ Own Id: OTP-15009 Aux Id: ERL-601 </p>
+ </item>
+ <item>
+ <p>The callback module passed as <c>-epmd_module</c> to
+ erl has been expanded to be able to do name and port
+ resolving.</p> <p>Documentation has also been added in
+ the <seealso
+ marker="kernel:erl_epmd"><c>erl_epmd</c></seealso>
+ reference manual and ERTS User's Guide <seealso
+ marker="erts:alt_disco">How to Implement an Alternative
+ Service Discovery for Erlang Distribution</seealso>.</p>
+ <p>
+ Own Id: OTP-15086 Aux Id: PR-1694 </p>
+ </item>
+ <item>
+ <p>
+ Included config file specified with relative path in
+ sys.config are now first searched for relative to the
+ directory of sys.config itself. If not found, it is also
+ searched for relative to the current working directory.
+ The latter is for backwards compatibility.</p>
+ <p>
+ Own Id: OTP-15137 Aux Id: PR-1838 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 5.4.3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Non semantic change in dist_util.erl to silence dialyzer
+ warning.</p>
+ <p>
+ Own Id: OTP-15170</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 5.4.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix some potential buggy behavior in how ticks are sent
+ on inter node distribution connections. Tick is now sent
+ to c-node even if there are unsent buffered data, as
+ c-nodes need ticks in order to send reply ticks. The
+ amount of sent data was calculated wrongly when ticks
+ where suppressed due to unsent buffered data.</p>
+ <p>
+ Own Id: OTP-15162 Aux Id: ERIERL-191 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Kernel 5.4.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/kernel/doc/src/os.xml b/lib/kernel/doc/src/os.xml
index ef416ed233..c95e615c6b 100644
--- a/lib/kernel/doc/src/os.xml
+++ b/lib/kernel/doc/src/os.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/part.xml b/lib/kernel/doc/src/part.xml
index 68eb4530e2..fa7e92835f 100644
--- a/lib/kernel/doc/src/part.xml
+++ b/lib/kernel/doc/src/part.xml
@@ -4,7 +4,7 @@
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -22,17 +22,14 @@
</legalnotice>
- <title>Logger User's Guide</title>
+ <title>Kernel User's Guide</title>
<prepared>OTP Team</prepared>
<docno></docno>
- <date>2017-12-01</date>
- <rev>0.1</rev>
+ <date>2018-06-06</date>
<file>part.xml</file>
</header>
<description>
- <p>The System Architecture Support Libraries SASL application
- provides support for alarm handling, release handling, and
- related functions.</p>
+ <p></p>
</description>
<xi:include href="introduction_chapter.xml"/>
<xi:include href="logger_chapter.xml"/>
diff --git a/lib/kernel/doc/src/ref_man.xml b/lib/kernel/doc/src/ref_man.xml
index c06914d23d..d3b947527f 100644
--- a/lib/kernel/doc/src/ref_man.xml
+++ b/lib/kernel/doc/src/ref_man.xml
@@ -4,7 +4,7 @@
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,12 +32,15 @@
</description>
<xi:include href="kernel_app.xml"/>
+ <xi:include href="app.xml"/>
<xi:include href="application.xml"/>
<xi:include href="auth.xml"/>
<xi:include href="code.xml"/>
+ <xi:include href="config.xml"/>
<xi:include href="disk_log.xml"/>
<xi:include href="erl_boot_server.xml"/>
<xi:include href="erl_ddll.xml"/>
+ <xi:include href="erl_epmd.xml"/>
<xi:include href="erl_prim_loader_stub.xml"/>
<xi:include href="erlang_stub.xml"/>
<xi:include href="error_handler.xml"/>
@@ -66,6 +69,4 @@
<xi:include href="user.xml"/>
<xi:include href="wrap_log_reader.xml"/>
<xi:include href="zlib_stub.xml"/>
- <xi:include href="app.xml"/>
- <xi:include href="config.xml"/>
</application>
diff --git a/lib/kernel/doc/src/seq_trace.xml b/lib/kernel/doc/src/seq_trace.xml
index 69eb12a8a0..1a4a74419a 100644
--- a/lib/kernel/doc/src/seq_trace.xml
+++ b/lib/kernel/doc/src/seq_trace.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1998</year><year>2017</year>
+ <year>1998</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/specs.xml b/lib/kernel/doc/src/specs.xml
index bcc422930e..b8c25ca53b 100644
--- a/lib/kernel/doc/src/specs.xml
+++ b/lib/kernel/doc/src/specs.xml
@@ -6,6 +6,7 @@
<xi:include href="../specs/specs_disk_log.xml"/>
<xi:include href="../specs/specs_erl_boot_server.xml"/>
<xi:include href="../specs/specs_erl_ddll.xml"/>
+ <xi:include href="../specs/specs_erl_epmd.xml"/>
<xi:include href="../specs/specs_erl_prim_loader_stub.xml"/>
<xi:include href="../specs/specs_erlang_stub.xml"/>
<xi:include href="../specs/specs_error_handler.xml"/>
diff --git a/lib/kernel/include/dist.hrl b/lib/kernel/include/dist.hrl
index 6baaa35d72..003852f1b0 100644
--- a/lib/kernel/include/dist.hrl
+++ b/lib/kernel/include/dist.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/include/dist_util.hrl b/lib/kernel/include/dist_util.hrl
index eeb0f8dd43..56f775f060 100644
--- a/lib/kernel/include/dist_util.hrl
+++ b/lib/kernel/include/dist_util.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/include/logger.hrl b/lib/kernel/include/logger.hrl
index 2143ccd297..b09977e0f2 100644
--- a/lib/kernel/include/logger.hrl
+++ b/lib/kernel/include/logger.hrl
@@ -32,6 +32,10 @@
-define(LOG_DEBUG(A,B),?DO_LOG(debug,[A,B])).
-define(LOG_DEBUG(A,B,C),?DO_LOG(debug,[A,B,C])).
+-define(LOG(L,A),?DO_LOG(L,[A])).
+-define(LOG(L,A,B),?DO_LOG(L,[A,B])).
+-define(LOG(L,A,B,C),?DO_LOG(L,[A,B,C])).
+
-define(LOCATION,#{mfa=>{?MODULE,?FUNCTION_NAME,?FUNCTION_ARITY},
line=>?LINE,
file=>?FILE}).
diff --git a/lib/kernel/src/Makefile b/lib/kernel/src/Makefile
index eeb8c6ab2f..57f17defc8 100644
--- a/lib/kernel/src/Makefile
+++ b/lib/kernel/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2017. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -112,13 +112,14 @@ MODULES = \
logger \
logger_backend \
logger_config \
- logger_std_h \
+ logger_handler_watcher \
+ logger_std_h \
logger_disk_log_h \
logger_h_common \
logger_filters \
logger_formatter \
logger_server \
- logger_simple \
+ logger_simple_h \
logger_sup \
net \
net_adm \
@@ -279,7 +280,7 @@ $(EBIN)/logger_disk_log_h.beam: logger_h_common.hrl logger_internal.hrl ../inclu
$(EBIN)/logger_filters.beam: logger_internal.hrl ../include/logger.hrl
$(EBIN)/logger_formatter.beam: logger_internal.hrl ../include/logger.hrl
$(EBIN)/logger_server.beam: logger_internal.hrl ../include/logger.hrl
-$(EBIN)/logger_simple.beam: logger_internal.hrl ../include/logger.hrl
+$(EBIN)/logger_simple_h.beam: logger_internal.hrl ../include/logger.hrl
$(EBIN)/logger_std_h.beam: logger_h_common.hrl logger_internal.hrl ../include/logger.hrl ../include/file.hrl
$(EBIN)/logger_h_common.beam: logger_h_common.hrl logger_internal.hrl ../include/logger.hrl
$(EBIN)/net_kernel.beam: ../include/net_address.hrl
diff --git a/lib/kernel/src/application_controller.erl b/lib/kernel/src/application_controller.erl
index b9cb722575..a074d2e74b 100644
--- a/lib/kernel/src/application_controller.erl
+++ b/lib/kernel/src/application_controller.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1272,9 +1272,7 @@ load(S, {ApplData, ApplEnv, IncApps, Descr, Id, Vsn, Apps}) ->
NewEnv = merge_app_env(ApplEnv, ConfEnv),
CmdLineEnv = get_cmd_env(Name),
NewEnv2 = merge_app_env(NewEnv, CmdLineEnv),
- NewEnv3 = keyreplaceadd(included_applications, 1, NewEnv2,
- {included_applications, IncApps}),
- add_env(Name, NewEnv3),
+ add_env(Name, NewEnv2),
Appl = #appl{name = Name, descr = Descr, id = Id, vsn = Vsn,
appl_data = ApplData, inc_apps = IncApps, apps = Apps},
ets:insert(ac_tab, {{loaded, Name}, Appl}),
@@ -1292,7 +1290,7 @@ load(S, {ApplData, ApplEnv, IncApps, Descr, Id, Vsn, Apps}) ->
{ok, NewS}.
unload(AppName, S) ->
- {ok, IncApps} = get_env(AppName, included_applications),
+ {ok, IncApps} = get_key(AppName, included_applications),
del_env(AppName),
ets:delete(ac_tab, {loaded, AppName}),
foldl(fun(App, S1) ->
@@ -1583,13 +1581,9 @@ do_change_appl({ok, {ApplData, Env, IncApps, Descr, Id, Vsn, Apps}},
CmdLineEnv = get_cmd_env(AppName),
NewEnv2 = merge_app_env(NewEnv1, CmdLineEnv),
- %% included_apps is made into an env parameter as well
- NewEnv3 = keyreplaceadd(included_applications, 1, NewEnv2,
- {included_applications, IncApps}),
-
%% Update ets table with new application env
del_env(AppName),
- add_env(AppName, NewEnv3),
+ add_env(AppName, NewEnv2),
OldAppl#appl{appl_data=ApplData,
descr=Descr,
@@ -1820,8 +1814,9 @@ check_conf() ->
%% Therefore read and merge contents.
if
BFName =:= "sys" ->
+ DName = filename:dirname(FName),
{ok, SysEnv, Errors} =
- check_conf_sys(NewEnv),
+ check_conf_sys(NewEnv, [], [], DName),
%% Report first error, if any, and
%% terminate
@@ -1843,20 +1838,31 @@ check_conf() ->
end.
check_conf_sys(Env) ->
- check_conf_sys(Env, [], []).
+ check_conf_sys(Env, [], [], []).
-check_conf_sys([File|T], SysEnv, Errors) when is_list(File) ->
+check_conf_sys([File|T], SysEnv, Errors, DName) when is_list(File),is_list(DName) ->
BFName = filename:basename(File, ".config"),
FName = filename:join(filename:dirname(File), BFName ++ ".config"),
- case load_file(FName) of
+ LName = case filename:pathtype(FName) of
+ relative when (DName =/= []) ->
+ % Check if relative to sys.config dir otherwise use legacy mode,
+ % i.e relative to cwd.
+ RName = filename:join(DName, FName),
+ case erl_prim_loader:read_file_info(RName) of
+ {ok, _} -> RName ;
+ error -> FName
+ end;
+ _ -> FName
+ end,
+ case load_file(LName) of
{ok, NewEnv} ->
- check_conf_sys(T, merge_env(SysEnv, NewEnv), Errors);
+ check_conf_sys(T, merge_env(SysEnv, NewEnv), Errors, DName);
{error, {Line, _Mod, Str}} ->
- check_conf_sys(T, SysEnv, [{error, {FName, Line, Str}}|Errors])
+ check_conf_sys(T, SysEnv, [{error, {LName, Line, Str}}|Errors], DName)
end;
-check_conf_sys([Tuple|T], SysEnv, Errors) ->
- check_conf_sys(T, merge_env(SysEnv, [Tuple]), Errors);
-check_conf_sys([], SysEnv, Errors) ->
+check_conf_sys([Tuple|T], SysEnv, Errors, DName) ->
+ check_conf_sys(T, merge_env(SysEnv, [Tuple]), Errors, DName);
+check_conf_sys([], SysEnv, Errors, _) ->
{ok, SysEnv, lists:reverse(Errors)}.
load_file(File) ->
@@ -1920,19 +1926,19 @@ info_started(Name, Node) ->
?LOG_INFO(#{label=>{application_controller,progress},
report=>[{application, Name},
{started_at, Node}]},
- #{domain=>[beam,erlang,otp,sasl],
+ #{domain=>[otp,sasl],
report_cb=>fun logger:format_otp_report/1,
logger_formatter=>#{title=>"PROGRESS REPORT"},
error_logger=>#{tag=>info_report,type=>progress}}).
info_exited(Name, Reason, Type) ->
- ?LOG_INFO(#{label=>{application_controller,exit},
- report=>[{application, Name},
- {exited, Reason},
- {type, Type}]},
- #{domain=>[beam,erlang,otp],
- report_cb=>fun logger:format_otp_report/1,
- error_logger=>#{tag=>info_report,type=>std_info}}).
+ ?LOG_NOTICE(#{label=>{application_controller,exit},
+ report=>[{application, Name},
+ {exited, Reason},
+ {type, Type}]},
+ #{domain=>[otp],
+ report_cb=>fun logger:format_otp_report/1,
+ error_logger=>#{tag=>info_report,type=>std_info}}).
%%-----------------------------------------------------------------
%% Reply to all processes waiting this application to be started.
@@ -2019,5 +2025,5 @@ to_string(Term) ->
true ->
Term;
false ->
- lists:flatten(io_lib:format("~134217728p", [Term]))
+ lists:flatten(io_lib:format("~0p", [Term]))
end.
diff --git a/lib/kernel/src/application_master.erl b/lib/kernel/src/application_master.erl
index 5da2b0b06c..8697143dfb 100644
--- a/lib/kernel/src/application_master.erl
+++ b/lib/kernel/src/application_master.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -118,6 +118,10 @@ init(Parent, Starter, ApplData, Type) ->
link(Parent),
process_flag(trap_exit, true),
OldGleader = group_leader(),
+ %% We become the group leader, but forward all I/O to OldGleader.
+ %% This is just a way to identify processes that belong to the
+ %% application. Used for example to find ourselves from any
+ %% process, or, reciprocally, to kill them all when we terminate.
group_leader(self(), self()),
%% Insert ourselves as master for the process. This ensures that
%% the processes in the application can use get_env/1 at startup.
diff --git a/lib/kernel/src/auth.erl b/lib/kernel/src/auth.erl
index a2116d8e8a..4d18daf9e4 100644
--- a/lib/kernel/src/auth.erl
+++ b/lib/kernel/src/auth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl
index f143a49d2f..7faef93609 100644
--- a/lib/kernel/src/code.erl
+++ b/lib/kernel/src/code.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -630,7 +630,7 @@ do_par_recv(N, Good, Bad) ->
call(Req) ->
code_server:call(Req).
--spec start_link() -> {'ok', pid()} | {'error', 'crash'}.
+-spec start_link() -> {'ok', pid()}.
start_link() ->
do_start().
diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl
index bbfa2a995d..1b4a67ecb7 100644
--- a/lib/kernel/src/code_server.erl
+++ b/lib/kernel/src/code_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1437,7 +1437,7 @@ error_msg(Format, Args) ->
logger ! {log,error,Format,Args,
#{pid=>self(),
gl=>group_leader(),
- time=>erlang:monotonic_time(microsecond),
+ time=>erlang:system_time(microsecond),
error_logger=>#{tag=>error}}},
ok.
@@ -1446,7 +1446,7 @@ info_msg(Format, Args) ->
logger ! {log,info,Format,Args,
#{pid=>self(),
gl=>group_leader(),
- time=>erlang:monotonic_time(microsecond),
+ time=>erlang:system_time(microsecond),
error_logger=>#{tag=>info_msg}}},
ok.
diff --git a/lib/kernel/src/disk_log_1.erl b/lib/kernel/src/disk_log_1.erl
index b456b53d20..41ef33c613 100644
--- a/lib/kernel/src/disk_log_1.erl
+++ b/lib/kernel/src/disk_log_1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl
index f96bc88913..b7e8868911 100644
--- a/lib/kernel/src/erl_epmd.erl
+++ b/lib/kernel/src/erl_epmd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,10 +29,20 @@
-define(port_please_failure2(Term), noop).
-endif.
+-ifndef(erlang_daemon_port).
+-define(erlang_daemon_port, 4369).
+-endif.
+-ifndef(epmd_dist_high).
+-define(epmd_dist_high, 4370).
+-endif.
+-ifndef(epmd_dist_low).
+-define(epmd_dist_low, 4370).
+-endif.
+
%% External exports
-export([start/0, start_link/0, stop/0, port_please/2,
port_please/3, names/0, names/1,
- register_node/2, register_node/3, open/0, open/1, open/2]).
+ register_node/2, register_node/3, address_please/3, open/0, open/1, open/2]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -53,7 +63,7 @@
start() ->
gen_server:start({local, erl_epmd}, ?MODULE, [], []).
-
+-spec start_link() -> {ok, pid()} | ignore | {error,term()}.
start_link() ->
gen_server:start_link({local, erl_epmd}, ?MODULE, [], []).
@@ -66,9 +76,22 @@ stop() ->
%% return {port, P, Version} | noport
%%
+-spec port_please(Name, Host) -> {ok, Port, Version} | noport when
+ Name :: string(),
+ Host :: inet:ip_address(),
+ Port :: non_neg_integer(),
+ Version :: non_neg_integer().
+
port_please(Node, Host) ->
port_please(Node, Host, infinity).
+-spec port_please(Name, Host, Timeout) -> {ok, Port, Version} | noport when
+ Name :: string(),
+ Host :: inet:ip_address(),
+ Timeout :: non_neg_integer() | infinity,
+ Port :: non_neg_integer(),
+ Version :: non_neg_integer().
+
port_please(Node,HostName, Timeout) when is_atom(HostName) ->
port_please1(Node,atom_to_list(HostName), Timeout);
port_please(Node,HostName, Timeout) when is_list(HostName) ->
@@ -92,10 +115,21 @@ port_please1(Node,HostName, Timeout) ->
Else
end.
+-spec names() -> {ok, [{Name, Port}]} | {error, Reason} when
+ Name :: string(),
+ Port :: non_neg_integer(),
+ Reason :: address | file:posix().
+
names() ->
{ok, H} = inet:gethostname(),
names(H).
+-spec names(Host) -> {ok, [{Name, Port}]} | {error, Reason} when
+ Host :: atom() | string() | inet:ip_address(),
+ Name :: string(),
+ Port :: non_neg_integer(),
+ Reason :: address | file:posix().
+
names(HostName) when is_atom(HostName); is_list(HostName) ->
case inet:gethostbyname(HostName) of
{ok,{hostent, _Name, _ , _Af, _Size, [EpmdAddr | _]}} ->
@@ -106,9 +140,22 @@ names(HostName) when is_atom(HostName); is_list(HostName) ->
names(EpmdAddr) ->
get_names(EpmdAddr).
+-spec register_node(Name, Port) -> Result when
+ Name :: string(),
+ Port :: non_neg_integer(),
+ Creation :: non_neg_integer(),
+ Result :: {ok, Creation} | {error, already_registered} | term().
register_node(Name, PortNo) ->
- register_node(Name, PortNo, inet).
+ register_node(Name, PortNo, inet).
+
+-spec register_node(Name, Port, Driver) -> Result when
+ Name :: string(),
+ Port :: non_neg_integer(),
+ Driver :: inet_tcp | inet6_tcp | inet | inet6,
+ Creation :: non_neg_integer(),
+ Result :: {ok, Creation} | {error, already_registered} | term().
+
register_node(Name, PortNo, inet_tcp) ->
register_node(Name, PortNo, inet);
register_node(Name, PortNo, inet6_tcp) ->
@@ -116,6 +163,17 @@ register_node(Name, PortNo, inet6_tcp) ->
register_node(Name, PortNo, Family) ->
gen_server:call(erl_epmd, {register, Name, PortNo, Family}, infinity).
+-spec address_please(Name, Host, AddressFamily) -> Success | {error, term()} when
+ Name :: string(),
+ Host :: string() | inet:ip_address(),
+ AddressFamily :: inet | inet6,
+ Port :: non_neg_integer(),
+ Version :: non_neg_integer(),
+ Success :: {ok, inet:ip_address()} | {ok, inet:ip_address(), Port, Version}.
+
+address_please(_Name, Host, AddressFamily) ->
+ inet:getaddr(Host, AddressFamily).
+
%%%----------------------------------------------------------------------
%%% Callback functions from gen_server
%%%----------------------------------------------------------------------
diff --git a/lib/kernel/src/erl_signal_handler.erl b/lib/kernel/src/erl_signal_handler.erl
index b76c2a217a..5be905d8ae 100644
--- a/lib/kernel/src/erl_signal_handler.erl
+++ b/lib/kernel/src/erl_signal_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. 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/lib/kernel/src/error_handler.erl b/lib/kernel/src/error_handler.erl
index a9582c6225..a89ef83261 100644
--- a/lib/kernel/src/error_handler.erl
+++ b/lib/kernel/src/error_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/src/error_logger.erl b/lib/kernel/src/error_logger.erl
index 47d0ca5ea3..ad8c937882 100644
--- a/lib/kernel/src/error_logger.erl
+++ b/lib/kernel/src/error_logger.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,7 +32,7 @@
which_report_handlers/0]).
%% logger callbacks
--export([adding_handler/2, removing_handler/2, log/2]).
+-export([adding_handler/1, removing_handler/1, log/2]).
-export([get_format_depth/0, limit_term/1]).
@@ -74,8 +74,8 @@ start() ->
type => worker,
modules => dynamic},
case supervisor:start_child(logger_sup, ErrorLogger) of
- {ok,_} ->
- ok;
+ {ok,Pid} ->
+ ok = logger_handler_watcher:register_handler(?MODULE,Pid);
Error ->
Error
end;
@@ -95,15 +95,20 @@ start_link() ->
%%% Stop the event manager
-spec stop() -> ok.
stop() ->
- _ = supervisor:terminate_child(logger_sup,?MODULE),
- _ = supervisor:delete_child(logger_sup,?MODULE),
- ok.
+ case whereis(?MODULE) of
+ undefined ->
+ ok;
+ _Pid ->
+ _ = gen_event:stop(?MODULE,{shutdown,stopped},infinity),
+ _ = supervisor:delete_child(logger_sup,?MODULE),
+ ok
+ end.
%%%-----------------------------------------------------------------
%%% Callbacks for logger
--spec adding_handler(logger:handler_id(),logger:config()) ->
- {ok,logger:config()} | {error,term()}.
-adding_handler(?MODULE,Config) ->
+-spec adding_handler(logger:handler_config()) ->
+ {ok,logger:handler_config()} | {error,term()}.
+adding_handler(#{id:=?MODULE}=Config) ->
case start() of
ok ->
{ok,Config};
@@ -111,12 +116,12 @@ adding_handler(?MODULE,Config) ->
Error
end.
--spec removing_handler(logger:handler_id(),logger:config()) -> ok.
-removing_handler(?MODULE,_Config) ->
+-spec removing_handler(logger:handler_config()) -> ok.
+removing_handler(#{id:=?MODULE}) ->
stop(),
ok.
--spec log(logger:log(),logger:config()) -> ok.
+-spec log(logger:log_event(),logger:handler_config()) -> ok.
log(#{level:=Level,msg:=Msg,meta:=Meta},_Config) ->
do_log(Level,Msg,Meta).
@@ -169,16 +174,25 @@ do_log(_Level,_Msg,_Meta) ->
-spec notify(logger:level(), msg_tag(), any(), any(), map()) -> 'ok'.
notify(Level,Tag0,FormatOrType0,ArgsOrReport,#{pid:=Pid0,gl:=GL,?MODULE:=My}) ->
- Tag = fix_warning_tag(Level,Tag0),
+ {Tag,FormatOrType} = maybe_map_warnings(Level,Tag0,FormatOrType0),
Pid = case maps:get(emulator,My,false) of
true -> emulator;
_ -> Pid0
end,
- FormatOrType = fix_warning_type(Level,FormatOrType0),
gen_event:notify(?MODULE,{Tag,GL,{Pid,FormatOrType,ArgsOrReport}}).
-%% This is to fix the case when the client has explicitly added the
-%% error logger tag and type in metadata, and not checked the warning map.
+%% For backwards compatibility with really old even handlers, check
+%% the warning map and update tag and type.
+maybe_map_warnings(warning,Tag,FormatOrType) ->
+ case error_logger:warning_map() of
+ warning ->
+ {Tag,FormatOrType};
+ Level ->
+ {fix_warning_tag(Level,Tag),fix_warning_type(Level,FormatOrType)}
+ end;
+maybe_map_warnings(_,Tag,FormatOrType) ->
+ {Tag,FormatOrType}.
+
fix_warning_tag(error,warning_msg) -> error;
fix_warning_tag(error,warning_report) -> error_report;
fix_warning_tag(info,warning_msg) -> info_msg;
@@ -263,29 +277,10 @@ warning_report(Report) ->
Report :: report().
warning_report(Type, Report) ->
- Level = error_logger:warning_map(),
- {Tag, NType} = case Level of
- info ->
- if
- Type =:= std_warning ->
- {info_report, std_info};
- true ->
- {info_report, Type}
- end;
- warning ->
- {warning_report, Type};
- error ->
- if
- Type =:= std_warning ->
- {error_report, std_error};
- true ->
- {error_report, Type}
- end
- end,
- logger:log(Level,
+ logger:log(warning,
#{label=>{?MODULE,warning_report},
report=>Report},
- meta(Tag,NType)).
+ meta(warning_report,Type)).
%%-----------------------------------------------------------------
%% This function provides similar functions as error_msg for
@@ -304,20 +299,11 @@ warning_msg(Format) ->
Data :: list().
warning_msg(Format, Args) ->
- Level = error_logger:warning_map(),
- Tag = case Level of
- warning ->
- warning_msg;
- info ->
- info_msg;
- error ->
- error
- end,
- logger:log(Level,
+ logger:log(warning,
#{label=>{?MODULE,warning_msg},
format=>Format,
args=>Args},
- meta(Tag)).
+ meta(warning_msg)).
%%-----------------------------------------------------------------
%% This function should be used for information reports. Events
@@ -336,7 +322,7 @@ info_report(Report) ->
Report :: report().
info_report(Type, Report) ->
- logger:log(info,
+ logger:log(notice,
#{label=>{?MODULE,info_report},
report=>Report},
meta(info_report,Type)).
@@ -357,7 +343,7 @@ info_msg(Format) ->
Data :: list().
info_msg(Format, Args) ->
- logger:log(info,
+ logger:log(notice,
#{label=>{?MODULE,info_msg},
format=>Format,
args=>Args},
@@ -377,7 +363,7 @@ error_info(Error) ->
false -> {"~p",[Error]}
end,
MyMeta = #{tag=>info,type=>Error},
- logger:log(info, Format, Args, #{?MODULE=>MyMeta,domain=>[Error]}).
+ logger:log(notice, Format, Args, #{?MODULE=>MyMeta,domain=>[Error]}).
%%-----------------------------------------------------------------
%% Create metadata
@@ -529,18 +515,38 @@ logfile(filename) ->
Flag :: boolean().
tty(true) ->
- case lists:member(error_logger_tty_h, which_report_handlers()) of
- false ->
- add_report_handler(error_logger_tty_h, []);
- true ->
- ignore
- end,
+ _ = case lists:member(error_logger_tty_h, which_report_handlers()) of
+ false ->
+ case logger:get_handler_config(default) of
+ {ok,#{module:=logger_std_h,config:=#{type:=standard_io}}} ->
+ logger:remove_handler_filter(default,
+ error_logger_tty_false);
+ _ ->
+ logger:add_handler(error_logger_tty_true,logger_std_h,
+ #{filter_default=>stop,
+ filters=>?DEFAULT_HANDLER_FILTERS(
+ [otp]),
+ formatter=>{?DEFAULT_FORMATTER,
+ ?DEFAULT_FORMAT_CONFIG},
+ config=>#{type=>standard_io}})
+ end;
+ true ->
+ ok
+ end,
ok;
tty(false) ->
- delete_report_handler(error_logger_tty_h).
+ delete_report_handler(error_logger_tty_h),
+ _ = logger:remove_handler(error_logger_tty_true),
+ _ = case logger:get_handler_config(default) of
+ {ok,#{module:=logger_std_h,config:=#{type:=standard_io}}} ->
+ logger:add_handler_filter(default,error_logger_tty_false,
+ {fun(_,_) -> stop end, ok});
+ _ ->
+ ok
+ end,
+ ok.
%%%-----------------------------------------------------------------
-
-spec limit_term(term()) -> term().
limit_term(Term) ->
@@ -552,4 +558,11 @@ limit_term(Term) ->
-spec get_format_depth() -> 'unlimited' | pos_integer().
get_format_depth() ->
- logger:get_format_depth().
+ case application:get_env(kernel, error_logger_format_depth) of
+ {ok, Depth} when is_integer(Depth) ->
+ max(10, Depth);
+ {ok, unlimited} ->
+ unlimited;
+ undefined ->
+ unlimited
+ end.
diff --git a/lib/kernel/src/erts_debug.erl b/lib/kernel/src/erts_debug.erl
index 1270de4144..c4d276f9e8 100644
--- a/lib/kernel/src/erts_debug.erl
+++ b/lib/kernel/src/erts_debug.erl
@@ -36,7 +36,8 @@
map_info/1, same/2, set_internal_state/2,
size_shared/1, copy_shared/1, dirty_cpu/2, dirty_io/2, dirty/3,
lcnt_control/1, lcnt_control/2, lcnt_collect/0, lcnt_clear/0,
- lc_graph/0, lc_graph_to_dot/2, lc_graph_merge/2]).
+ lc_graph/0, lc_graph_to_dot/2, lc_graph_merge/2,
+ alloc_blocks_size/1]).
-spec breakpoint(MFA, Flag) -> non_neg_integer() when
MFA :: {Module :: module(),
@@ -495,3 +496,58 @@ lcg_print_locks(Out, [LastLock]) ->
lcg_print_locks(Out, [Lock | Rest]) ->
io:format(Out, "~w,\n", [Lock]),
lcg_print_locks(Out, Rest).
+
+
+%% Returns the amount of memory allocated by the given allocator type.
+-spec alloc_blocks_size(Type) -> non_neg_integer() | undefined when
+ Type :: atom().
+
+alloc_blocks_size(Type) ->
+ Allocs = erlang:system_info(alloc_util_allocators),
+ Sizes = erlang:system_info({allocator_sizes, Allocs}),
+ alloc_blocks_size_1(Sizes, Type, 0).
+
+alloc_blocks_size_1([], _Type, 0) ->
+ undefined;
+alloc_blocks_size_1([{_Type, false} | Rest], Type, Acc) ->
+ alloc_blocks_size_1(Rest, Type, Acc);
+alloc_blocks_size_1([{Type, Instances} | Rest], Type, Acc0) ->
+ F = fun ({instance, _, L}, Acc) ->
+ MBCSPool = case lists:keyfind(mbcs_pool, 1, L) of
+ {_, Pool} -> Pool;
+ false -> []
+ end,
+ {_,MBCS} = lists:keyfind(mbcs, 1, L),
+ {_,SBCS} = lists:keyfind(sbcs, 1, L),
+ Acc +
+ sum_block_sizes(MBCSPool) +
+ sum_block_sizes(MBCS) +
+ sum_block_sizes(SBCS)
+ end,
+ alloc_blocks_size_1(Rest, Type, lists:foldl(F, Acc0, Instances));
+alloc_blocks_size_1([{_Type, Instances} | Rest], Type, Acc0) ->
+ F = fun ({instance, _, L}, Acc) ->
+ Acc + sum_foreign_sizes(Type, L)
+ end,
+ alloc_blocks_size_1(Rest, Type, lists:foldl(F, Acc0, Instances));
+alloc_blocks_size_1([], _Type, Acc) ->
+ Acc.
+
+sum_foreign_sizes(Type, L) ->
+ case lists:keyfind(mbcs_pool, 1, L) of
+ {_,Pool} ->
+ {_,ForeignBlocks} = lists:keyfind(foreign_blocks, 1, Pool),
+ case lists:keyfind(Type, 1, ForeignBlocks) of
+ {_,TypeSizes} -> sum_block_sizes(TypeSizes);
+ false -> 0
+ end;
+ _ ->
+ 0
+ end.
+
+sum_block_sizes(Blocks) ->
+ lists:foldl(
+ fun({blocks_size, Sz,_,_}, Sz0) -> Sz0+Sz;
+ ({blocks_size, Sz}, Sz0) -> Sz0+Sz;
+ (_, Sz) -> Sz
+ end, 0, Blocks).
diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl
index 57d8fc7a15..1d4e37196c 100644
--- a/lib/kernel/src/file.erl
+++ b/lib/kernel/src/file.erl
@@ -69,7 +69,7 @@
%% Types that can be used from other modules -- alphabetically ordered.
-export_type([date_time/0, fd/0, file_info/0, filename/0, filename_all/0,
- io_device/0, name/0, name_all/0, posix/0]).
+ io_device/0, mode/0, name/0, name_all/0, posix/0]).
%%% Includes and defines
-include("file_int.hrl").
diff --git a/lib/kernel/src/file_server.erl b/lib/kernel/src/file_server.erl
index ecc1ffbdd6..29eaa23375 100644
--- a/lib/kernel/src/file_server.erl
+++ b/lib/kernel/src/file_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -73,7 +73,7 @@ stop() ->
%% {stop, Reason}
%%----------------------------------------------------------------------
--spec init([]) -> {'ok', state()} | {'stop', term()}.
+-spec init([]) -> {'ok', state()}.
init([]) ->
process_flag(trap_exit, true),
@@ -225,7 +225,7 @@ handle_cast(Msg, State) ->
%%----------------------------------------------------------------------
-spec handle_info(term(), state()) ->
- {'noreply', state()} | {'stop', 'normal', state()}.
+ {'noreply', state()}.
handle_info({'EXIT', Pid, _Reason}, State) when is_pid(Pid) ->
ets:delete(?FILE_IO_SERVER_TABLE, Pid),
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index a6aa0edd15..bf795ee9c6 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -118,6 +118,8 @@ open() ->
| inet:address_family()
| {port,Port}
| {type,SockType}
+ | {netns, file:filename_all()}
+ | {bind_to_device, binary()}
| option(),
IP :: inet:ip_address() | any | loopback,
Port :: inet:port_number(),
diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl
index ac61dbc792..c61411e814 100644
--- a/lib/kernel/src/gen_tcp.erl
+++ b/lib/kernel/src/gen_tcp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -102,6 +102,8 @@
inet:address_family() |
{port, inet:port_number()} |
{tcp_module, module()} |
+ {netns, file:filename_all()} |
+ {bind_to_device, binary()} |
option().
-type listen_option() ::
{ip, inet:socket_address()} |
@@ -111,6 +113,8 @@
{port, inet:port_number()} |
{backlog, B :: non_neg_integer()} |
{tcp_module, module()} |
+ {netns, file:filename_all()} |
+ {bind_to_device, binary()} |
option().
-type socket() :: port().
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index 3121544719..44eef9f3c5 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -97,6 +97,8 @@ open(Port) ->
| {ifaddr, inet:socket_address()}
| inet:address_family()
| {port, inet:port_number()}
+ | {netns, file:filename_all()}
+ | {bind_to_device, binary()}
| option(),
Socket :: socket(),
Reason :: inet:posix().
diff --git a/lib/kernel/src/group.erl b/lib/kernel/src/group.erl
index 2c0518ccad..5625ae6eb7 100644
--- a/lib/kernel/src/group.erl
+++ b/lib/kernel/src/group.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/src/inet_config.erl b/lib/kernel/src/inet_config.erl
index 9f76360b8b..e771461b65 100644
--- a/lib/kernel/src/inet_config.erl
+++ b/lib/kernel/src/inet_config.erl
@@ -98,7 +98,7 @@ init() ->
{win32,WinType} ->
win32_load_from_registry(WinType);
_ ->
- error("can not read win32 system registry~n", [])
+ error("cannot read win32 system registry~n", [])
end
end, CfgFiles),
diff --git a/lib/kernel/src/inet_dns.erl b/lib/kernel/src/inet_dns.erl
index f1f58bc872..6c98d2aab7 100644
--- a/lib/kernel/src/inet_dns.erl
+++ b/lib/kernel/src/inet_dns.erl
@@ -699,7 +699,7 @@ encode_labels(Bin, Comp0, Pos, [L|Ls]=Labels)
none ->
Comp = if Pos < (3 bsl 14) ->
%% Just in case - compression
- %% pointers can not reach further
+ %% pointers cannot reach further
gb_trees:insert(Labels, Pos, Comp0);
true -> Comp0
end,
diff --git a/lib/kernel/src/inet_tcp_dist.erl b/lib/kernel/src/inet_tcp_dist.erl
index e3fdb1bb22..d1701afdaa 100644
--- a/lib/kernel/src/inet_tcp_dist.erl
+++ b/lib/kernel/src/inet_tcp_dist.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -283,73 +283,22 @@ do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
?trace("~p~n",[{inet_tcp_dist,self(),setup,Node}]),
[Name, Address] = splitnode(Driver, Node, LongOrShortNames),
AddressFamily = Driver:family(),
- case inet:getaddr(Address, AddressFamily) of
+ ErlEpmd = net_kernel:epmd_module(),
+ {ARMod, ARFun} = get_address_resolver(ErlEpmd),
+ Timer = dist_util:start_timer(SetupTime),
+ case ARMod:ARFun(Name, Address, AddressFamily) of
+ {ok, Ip, TcpPort, Version} ->
+ ?trace("address_please(~p) -> version ~p~n",
+ [Node,Version]),
+ do_setup_connect(Driver, Kernel, Node, Address, AddressFamily,
+ Ip, TcpPort, Version, Type, MyNode, Timer);
{ok, Ip} ->
- Timer = dist_util:start_timer(SetupTime),
- ErlEpmd = net_kernel:epmd_module(),
case ErlEpmd:port_please(Name, Ip) of
{port, TcpPort, Version} ->
?trace("port_please(~p) -> version ~p~n",
[Node,Version]),
- dist_util:reset_timer(Timer),
- case
- Driver:connect(
- Ip, TcpPort,
- connect_options([{active, false}, {packet, 2}]))
- of
- {ok, Socket} ->
- HSData = #hs_data{
- kernel_pid = Kernel,
- other_node = Node,
- this_node = MyNode,
- socket = Socket,
- timer = Timer,
- this_flags = 0,
- other_version = Version,
- f_send = fun Driver:send/2,
- f_recv = fun Driver:recv/3,
- f_setopts_pre_nodeup =
- fun(S) ->
- inet:setopts
- (S,
- [{active, false},
- {packet, 4},
- nodelay()])
- end,
- f_setopts_post_nodeup =
- fun(S) ->
- inet:setopts
- (S,
- [{active, true},
- {deliver, port},
- {packet, 4},
- nodelay()])
- end,
-
- f_getll = fun inet:getll/1,
- f_address =
- fun(_,_) ->
- #net_address{
- address = {Ip,TcpPort},
- host = Address,
- protocol = tcp,
- family = AddressFamily}
- end,
- mf_tick = fun(S) -> ?MODULE:tick(Driver, S) end,
- mf_getstat = fun ?MODULE:getstat/1,
- request_type = Type,
- mf_setopts = fun ?MODULE:setopts/2,
- mf_getopts = fun ?MODULE:getopts/2
- },
- dist_util:handshake_we_started(HSData);
- _ ->
- %% Other Node may have closed since
- %% port_please !
- ?trace("other node (~p) "
- "closed since port_please.~n",
- [Node]),
- ?shutdown(Node)
- end;
+ do_setup_connect(Driver, Kernel, Node, Address, AddressFamily,
+ Ip, TcpPort, Version, Type, MyNode, Timer);
_ ->
?trace("port_please (~p) "
"failed.~n", [Node]),
@@ -361,6 +310,71 @@ do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
?shutdown(Node)
end.
+%%
+%% Actual setup of connection
+%%
+do_setup_connect(Driver, Kernel, Node, Address, AddressFamily,
+ Ip, TcpPort, Version, Type, MyNode, Timer) ->
+ dist_util:reset_timer(Timer),
+ case
+ Driver:connect(
+ Ip, TcpPort,
+ connect_options([{active, false}, {packet, 2}]))
+ of
+ {ok, Socket} ->
+ HSData = #hs_data{
+ kernel_pid = Kernel,
+ other_node = Node,
+ this_node = MyNode,
+ socket = Socket,
+ timer = Timer,
+ this_flags = 0,
+ other_version = Version,
+ f_send = fun Driver:send/2,
+ f_recv = fun Driver:recv/3,
+ f_setopts_pre_nodeup =
+ fun(S) ->
+ inet:setopts
+ (S,
+ [{active, false},
+ {packet, 4},
+ nodelay()])
+ end,
+ f_setopts_post_nodeup =
+ fun(S) ->
+ inet:setopts
+ (S,
+ [{active, true},
+ {deliver, port},
+ {packet, 4},
+ nodelay()])
+ end,
+
+ f_getll = fun inet:getll/1,
+ f_address =
+ fun(_,_) ->
+ #net_address{
+ address = {Ip,TcpPort},
+ host = Address,
+ protocol = tcp,
+ family = AddressFamily}
+ end,
+ mf_tick = fun(S) -> ?MODULE:tick(Driver, S) end,
+ mf_getstat = fun ?MODULE:getstat/1,
+ request_type = Type,
+ mf_setopts = fun ?MODULE:setopts/2,
+ mf_getopts = fun ?MODULE:getopts/2
+ },
+ dist_util:handshake_we_started(HSData);
+ _ ->
+ %% Other Node may have closed since
+ %% discovery !
+ ?trace("other node (~p) "
+ "closed since discovery (port_please).~n",
+ [Node]),
+ ?shutdown(Node)
+ end.
+
connect_options(Opts) ->
case application:get_env(kernel, inet_dist_connect_options) of
{ok,ConnectOpts} ->
@@ -430,6 +444,16 @@ get_tcp_address(Driver, Socket) ->
}.
%% ------------------------------------------------------------
+%% Determine if EPMD module supports address resolving. Default
+%% is to use inet:getaddr/2.
+%% ------------------------------------------------------------
+get_address_resolver(EpmdModule) ->
+ case erlang:function_exported(EpmdModule, address_please, 3) of
+ true -> {EpmdModule, address_please};
+ _ -> {inet, getaddr}
+ end.
+
+%% ------------------------------------------------------------
%% Do only accept new connection attempts from nodes at our
%% own LAN, if the check_ip environment parameter is true.
%% ------------------------------------------------------------
diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src
index afffcd156e..4933eae76f 100644
--- a/lib/kernel/src/kernel.app.src
+++ b/lib/kernel/src/kernel.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -67,8 +67,9 @@
logger_filters,
logger_formatter,
logger_h_common,
+ logger_handler_watcher,
logger_server,
- logger_simple,
+ logger_simple_h,
logger_std_h,
logger_sup,
net,
@@ -129,6 +130,7 @@
kernel_refc,
kernel_sup,
logger,
+ logger_handler_watcher,
logger_sup,
net_kernel,
net_sup,
@@ -140,7 +142,9 @@
inet_db,
pg2]},
{applications, []},
- {env, []},
+ {env, [{logger_level, notice},
+ {logger_sasl_compatible, false}
+ ]},
{mod, {kernel, []}},
{runtime_dependencies, ["erts-10.0", "stdlib-3.5", "sasl-3.0"]}
]
diff --git a/lib/kernel/src/kernel.erl b/lib/kernel/src/kernel.erl
index ae982c1741..c68d04e279 100644
--- a/lib/kernel/src/kernel.erl
+++ b/lib/kernel/src/kernel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,17 +30,13 @@
%%% Callback functions for the kernel application.
%%%-----------------------------------------------------------------
start(_, []) ->
+ %% Setup the logger and configure the kernel logger environment
+ ok = logger:internal_init_logger(),
case supervisor:start_link({local, kernel_sup}, kernel, []) of
{ok, Pid} ->
ok = erl_signal_handler:start(),
- %% add error handler
- case logger:setup_standard_handler() of
- ok -> {ok, Pid, []};
- Error ->
- %% Not necessary since the node will crash anyway:
- exit(Pid, shutdown),
- Error
- end;
+ ok = logger:add_handlers(kernel),
+ {ok, Pid, []};
Error -> Error
end.
@@ -147,7 +143,7 @@ init([]) ->
case init:get_argument(mode) of
{ok, [["minimal"]]} ->
{ok, {SupFlags,
- [Code, File, StdError, User, Config, RefC, SafeSup, LoggerSup]}};
+ [Code, File, StdError, User, LoggerSup, Config, RefC, SafeSup]}};
_ ->
Rpc = #{id => rex,
start => {rpc, start_link, []},
diff --git a/lib/kernel/src/kernel_config.erl b/lib/kernel/src/kernel_config.erl
index c5ff1887c2..691a266c2d 100644
--- a/lib/kernel/src/kernel_config.erl
+++ b/lib/kernel/src/kernel_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/src/kernel_refc.erl b/lib/kernel/src/kernel_refc.erl
index 05076dc885..8e04ff99d8 100644
--- a/lib/kernel/src/kernel_refc.erl
+++ b/lib/kernel/src/kernel_refc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -44,7 +44,7 @@ scheduler_wall_time(Bool) ->
%% Callback functions from gen_server
%%-----------------------------------------------------------------
--spec init([]) -> {'ok', map()} | {'stop', term()}.
+-spec init([]) -> {'ok', map()}.
init([]) ->
resource(scheduler_wall_time, false),
diff --git a/lib/kernel/src/logger.erl b/lib/kernel/src/logger.erl
index 98a9937111..0020fe220b 100644
--- a/lib/kernel/src/logger.erl
+++ b/lib/kernel/src/logger.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,20 +35,27 @@
%% Configuration
-export([add_handler/3, remove_handler/1,
- add_logger_filter/2, add_handler_filter/3,
- remove_logger_filter/1, remove_handler_filter/2,
- set_module_level/2, reset_module_level/1,
- set_logger_config/1, set_logger_config/2,
+ add_primary_filter/2, add_handler_filter/3,
+ remove_primary_filter/1, remove_handler_filter/2,
+ set_module_level/2,
+ unset_module_level/1, unset_module_level/0,
+ set_application_level/2, unset_application_level/1,
+ get_module_level/0, get_module_level/1,
+ set_primary_config/1, set_primary_config/2,
set_handler_config/2, set_handler_config/3,
- get_logger_config/0, get_handler_config/1]).
+ update_primary_config/1, update_handler_config/2,
+ update_formatter_config/2, update_formatter_config/3,
+ get_primary_config/0, get_handler_config/1,
+ get_handler_config/0, get_handler_ids/0, get_config/0,
+ add_handlers/1]).
+
+%% Private configuration
+-export([internal_init_logger/0]).
%% Misc
-export([compare_levels/2]).
-export([set_process_metadata/1, update_process_metadata/1,
unset_process_metadata/0, get_process_metadata/0]).
--export([i/0, i/1]).
--export([setup_standard_handler/0, replace_simple_handler/3]).
--export([limit_term/1, get_format_depth/0, get_max_size/0, get_utc_config/0]).
%% Basic report formatting
-export([format_report/1, format_otp_report/1]).
@@ -60,14 +67,19 @@
%%%-----------------------------------------------------------------
%%% Types
--type log() :: #{level:=level(),
- msg:={io:format(),[term()]} |
- {report,report()} |
- {string,unicode:chardata()},
- meta:=metadata()}.
+-type log_event() :: #{level:=level(),
+ msg:={io:format(),[term()]} |
+ {report,report()} |
+ {string,unicode:chardata()},
+ meta:=metadata()}.
-type level() :: emergency | alert | critical | error |
warning | notice | info | debug.
-type report() :: map() | [{atom(),term()}].
+-type report_cb() :: fun((report()) -> {io:format(),[term()]}) |
+ fun((report(),report_cb_config()) -> unicode:chardata()).
+-type report_cb_config() :: #{encoding := unicode:encoding(),
+ depth := pos_integer() | unlimited,
+ chars_limit := pos_integer() | unlimited}.
-type msg_fun() :: fun((term()) -> {io:format(),[term()]} |
report() |
unicode:chardata()).
@@ -77,24 +89,49 @@
mfa => {module(),atom(),non_neg_integer()},
file => file:filename(),
line => non_neg_integer(),
- term() => term()}.
+ domain => [atom()],
+ report_cb => report_cb(),
+ atom() => term()}.
-type location() :: #{mfa := {module(),atom(),non_neg_integer()},
file := file:filename(),
line := non_neg_integer()}.
-type handler_id() :: atom().
-type filter_id() :: atom().
--type filter() :: {fun((log(),filter_arg()) -> filter_return()),filter_arg()}.
+-type filter() :: {fun((log_event(),filter_arg()) ->
+ filter_return()),filter_arg()}.
-type filter_arg() :: term().
--type filter_return() :: stop | ignore | log().
--type config() :: #{level => level(),
- filter_default => log | stop,
- filters => [{filter_id(),filter()}],
- formatter => {module(),term()},
- term() => term()}.
+-type filter_return() :: stop | ignore | log_event().
+-type primary_config() :: #{level => level() | all | none,
+ filter_default => log | stop,
+ filters => [{filter_id(),filter()}]}.
+-type handler_config() :: #{id => handler_id(),
+ config => term(),
+ level => level() | all | none,
+ module => module(),
+ filter_default => log | stop,
+ filters => [{filter_id(),filter()}],
+ formatter => {module(),formatter_config()}}.
-type timestamp() :: integer().
-
--export_type([log/0,level/0,report/0,msg_fun/0,metadata/0,config/0,handler_id/0,
- filter_id/0,filter/0,filter_arg/0,filter_return/0]).
+-type formatter_config() :: #{atom() => term()}.
+
+-type config_handler() :: {handler, handler_id(), module(), handler_config()}.
+
+-export_type([log_event/0,
+ level/0,
+ report/0,
+ report_cb/0,
+ report_cb_config/0,
+ msg_fun/0,
+ metadata/0,
+ primary_config/0,
+ handler_config/0,
+ handler_id/0,
+ filter_id/0,
+ filter/0,
+ filter_arg/0,
+ filter_return/0,
+ config_handler/0,
+ formatter_config/0]).
%%%-----------------------------------------------------------------
%%% API
@@ -296,11 +333,11 @@ internal_log(Level,Term) when is_atom(Level) ->
%%%-----------------------------------------------------------------
%%% Configuration
--spec add_logger_filter(FilterId,Filter) -> ok | {error,term()} when
+-spec add_primary_filter(FilterId,Filter) -> ok | {error,term()} when
FilterId :: filter_id(),
Filter :: filter().
-add_logger_filter(FilterId,Filter) ->
- logger_server:add_filter(logger,{FilterId,Filter}).
+add_primary_filter(FilterId,Filter) ->
+ logger_server:add_filter(primary,{FilterId,Filter}).
-spec add_handler_filter(HandlerId,FilterId,Filter) -> ok | {error,term()} when
HandlerId :: handler_id(),
@@ -310,10 +347,10 @@ add_handler_filter(HandlerId,FilterId,Filter) ->
logger_server:add_filter(HandlerId,{FilterId,Filter}).
--spec remove_logger_filter(FilterId) -> ok | {error,term()} when
+-spec remove_primary_filter(FilterId) -> ok | {error,term()} when
FilterId :: filter_id().
-remove_logger_filter(FilterId) ->
- logger_server:remove_filter(logger,FilterId).
+remove_primary_filter(FilterId) ->
+ logger_server:remove_filter(primary,FilterId).
-spec remove_handler_filter(HandlerId,FilterId) -> ok | {error,term()} when
HandlerId :: handler_id(),
@@ -324,7 +361,7 @@ remove_handler_filter(HandlerId,FilterId) ->
-spec add_handler(HandlerId,Module,Config) -> ok | {error,term()} when
HandlerId :: handler_id(),
Module :: module(),
- Config :: config().
+ Config :: handler_config().
add_handler(HandlerId,Module,Config) ->
logger_server:add_handler(HandlerId,Module,Config).
@@ -333,52 +370,161 @@ add_handler(HandlerId,Module,Config) ->
remove_handler(HandlerId) ->
logger_server:remove_handler(HandlerId).
--spec set_logger_config(Key,Value) -> ok | {error,term()} when
- Key :: atom(),
- Value :: term().
-set_logger_config(Key,Value) ->
- logger_server:set_config(logger,Key,Value).
-
--spec set_logger_config(Config) -> ok | {error,term()} when
- Config :: config().
-set_logger_config(Config) ->
- logger_server:set_config(logger,Config).
-
--spec set_handler_config(HandlerId,Key,Value) -> ok | {error,term()} when
+-spec set_primary_config(level,Level) -> ok | {error,term()} when
+ Level :: level() | all | none;
+ (filter_default,FilterDefault) -> ok | {error,term()} when
+ FilterDefault :: log | stop;
+ (filters,Filters) -> ok | {error,term()} when
+ Filters :: [{filter_id(),filter()}].
+set_primary_config(Key,Value) ->
+ logger_server:set_config(primary,Key,Value).
+
+-spec set_primary_config(Config) -> ok | {error,term()} when
+ Config :: primary_config().
+set_primary_config(Config) ->
+ logger_server:set_config(primary,Config).
+
+-spec set_handler_config(HandlerId,level,Level) -> Return when
HandlerId :: handler_id(),
- Key :: atom(),
- Value :: term().
+ Level :: level() | all | none,
+ Return :: ok | {error,term()};
+ (HandlerId,filter_default,FilterDefault) -> Return when
+ HandlerId :: handler_id(),
+ FilterDefault :: log | stop,
+ Return :: ok | {error,term()};
+ (HandlerId,filters,Filters) -> Return when
+ HandlerId :: handler_id(),
+ Filters :: [{filter_id(),filter()}],
+ Return :: ok | {error,term()};
+ (HandlerId,formatter,Formatter) -> Return when
+ HandlerId :: handler_id(),
+ Formatter :: {module(), formatter_config()},
+ Return :: ok | {error,term()};
+ (HandlerId,config,Config) -> Return when
+ HandlerId :: handler_id(),
+ Config :: term(),
+ Return :: ok | {error,term()}.
set_handler_config(HandlerId,Key,Value) ->
logger_server:set_config(HandlerId,Key,Value).
-spec set_handler_config(HandlerId,Config) -> ok | {error,term()} when
HandlerId :: handler_id(),
- Config :: config().
+ Config :: handler_config().
set_handler_config(HandlerId,Config) ->
logger_server:set_config(HandlerId,Config).
--spec get_logger_config() -> {ok,Config} when
- Config :: config().
-get_logger_config() ->
- logger_config:get(?LOGGER_TABLE,logger).
+-spec update_primary_config(Config) -> ok | {error,term()} when
+ Config :: primary_config().
+update_primary_config(Config) ->
+ logger_server:update_config(primary,Config).
--spec get_handler_config(HandlerId) -> {ok,{Module,Config}} | {error,term()} when
+-spec update_handler_config(HandlerId,Config) -> ok | {error,term()} when
HandlerId :: handler_id(),
- Module :: module(),
- Config :: config().
+ Config :: handler_config().
+update_handler_config(HandlerId,Config) ->
+ logger_server:update_config(HandlerId,Config).
+
+-spec get_primary_config() -> Config when
+ Config :: primary_config().
+get_primary_config() ->
+ {ok,Config} = logger_config:get(?LOGGER_TABLE,primary),
+ maps:remove(handlers,Config).
+
+-spec get_handler_config(HandlerId) -> {ok,Config} | {error,term()} when
+ HandlerId :: handler_id(),
+ Config :: handler_config().
get_handler_config(HandlerId) ->
- logger_config:get(?LOGGER_TABLE,HandlerId).
+ case logger_config:get(?LOGGER_TABLE,HandlerId) of
+ {ok,{_,Config}} ->
+ {ok,Config};
+ Error ->
+ Error
+ end.
--spec set_module_level(Module,Level) -> ok | {error,term()} when
- Module :: module(),
- Level :: level().
-set_module_level(Module,Level) ->
- logger_server:set_module_level(Module,Level).
+-spec get_handler_config() -> [Config] when
+ Config :: handler_config().
+get_handler_config() ->
+ [begin
+ {ok,Config} = get_handler_config(HandlerId),
+ Config
+ end || HandlerId <- get_handler_ids()].
--spec reset_module_level(Module) -> ok | {error,term()} when
- Module :: module().
-reset_module_level(Module) ->
- logger_server:reset_module_level(Module).
+-spec get_handler_ids() -> [HandlerId] when
+ HandlerId :: handler_id().
+get_handler_ids() ->
+ {ok,#{handlers:=HandlerIds}} = logger_config:get(?LOGGER_TABLE,primary),
+ HandlerIds.
+
+-spec update_formatter_config(HandlerId,FormatterConfig) ->
+ ok | {error,term()} when
+ HandlerId :: handler_id(),
+ FormatterConfig :: formatter_config().
+update_formatter_config(HandlerId,FormatterConfig) ->
+ logger_server:update_formatter_config(HandlerId,FormatterConfig).
+
+-spec update_formatter_config(HandlerId,Key,Value) ->
+ ok | {error,term()} when
+ HandlerId :: handler_id(),
+ Key :: atom(),
+ Value :: term().
+update_formatter_config(HandlerId,Key,Value) ->
+ logger_server:update_formatter_config(HandlerId,#{Key=>Value}).
+
+-spec set_module_level(Modules,Level) -> ok | {error,term()} when
+ Modules :: [module()] | module(),
+ Level :: level() | all | none.
+set_module_level(Module,Level) when is_atom(Module) ->
+ set_module_level([Module],Level);
+set_module_level(Modules,Level) ->
+ logger_server:set_module_level(Modules,Level).
+
+-spec unset_module_level(Modules) -> ok when
+ Modules :: [module()] | module().
+unset_module_level(Module) when is_atom(Module) ->
+ unset_module_level([Module]);
+unset_module_level(Modules) ->
+ logger_server:unset_module_level(Modules).
+
+-spec unset_module_level() -> ok.
+unset_module_level() ->
+ logger_server:unset_module_level().
+
+-spec set_application_level(Application,Level) -> ok | {error, not_loaded} when
+ Application :: atom(),
+ Level :: level() | all | none.
+set_application_level(App,Level) ->
+ case application:get_key(App, modules) of
+ {ok, Modules} ->
+ set_module_level(Modules, Level);
+ undefined ->
+ {error, {not_loaded, App}}
+ end.
+
+-spec unset_application_level(Application) -> ok | {error, not_loaded} when
+ Application :: atom().
+unset_application_level(App) ->
+ case application:get_key(App, modules) of
+ {ok, Modules} ->
+ unset_module_level(Modules);
+ undefined ->
+ {error, {not_loaded, App}}
+ end.
+
+-spec get_module_level(Modules) -> [{Module,Level}] when
+ Modules :: [Module] | Module,
+ Module :: module(),
+ Level :: level() | all | none.
+get_module_level(Module) when is_atom(Module) ->
+ get_module_level([Module]);
+get_module_level(Modules) when is_list(Modules) ->
+ [{M,L} || {M,L} <- get_module_level(),
+ lists:member(M,Modules)].
+
+-spec get_module_level() -> [{Module,Level}] when
+ Module :: module(),
+ Level :: level() | all | none.
+get_module_level() ->
+ logger_config:get_module_level(?LOGGER_TABLE).
%%%-----------------------------------------------------------------
%%% Misc
@@ -427,297 +573,220 @@ unset_process_metadata() ->
_ = erase(?LOGGER_META_KEY),
ok.
--spec i() -> #{logger=>config(),
- handlers=>[{handler_id(),module(),config()}],
- module_levels=>[{module(),level()}]}.
-i() ->
- i(term).
-
--spec i(term) -> #{logger=>config(),
- handlers=>[{handler_id(),module(),config()}],
- module_levels=>[{module(),level()}]};
- (print) -> ok;
- (string) -> iolist().
-i(_Action = print) ->
- io:put_chars(i(string));
-i(_Action = string) ->
- #{logger := #{level := Level, handlers := Handlers,
- filters := Filters, filter_default := FilterDefault},
- handlers := HandlerConfigs,
- module_levels := Modules} = i(term),
- [io_lib:format("Current logger configuration:~n", []),
- io_lib:format(" Level: ~p~n",[Level]),
- io_lib:format(" Filter Default: ~p~n", [FilterDefault]),
- io_lib:format(" Filters: ~n", []),
- print_filters(4, Filters),
- io_lib:format(" Handlers: ~n", []),
- print_handlers([C || {Id, _, _} = C <- HandlerConfigs,
- lists:member(Id, Handlers)]),
- io_lib:format(" Level set per module: ~n", []),
- print_module_levels(Modules)
- ];
-i(_Action = term) ->
- {Logger, Handlers, Modules} = logger_config:get(tid()),
- #{logger=>Logger,
- handlers=>Handlers,
- module_levels=>Modules}.
-
-print_filters(Indent, {Id, {Fun, Config}}) ->
- io_lib:format("~sId: ~p~n"
- "~s Fun: ~p~n"
- "~s Config: ~p~n",[Indent, Id, Indent, Fun, Indent, Config]);
-print_filters(Indent, Filters) ->
- IndentStr = io_lib:format("~.*s",[Indent, ""]),
- lists:map(fun(Filter) ->print_filters(IndentStr, Filter) end, Filters).
-
-
-print_handlers({Id,Module,
- #{level := Level,
- filters := Filters, filter_default := FilterDefault,
- formatter := {FormatterModule,FormatterConfig}} = Config}) ->
- MyKeys = [filter_default, filters, formatter, level, id],
- UnhandledConfig = maps:filter(fun(Key, _) ->
- not lists:member(Key, MyKeys)
- end, Config),
- Unhandled = lists:map(fun({Key, Value}) ->
- io_lib:format(" ~p: ~p~n",[Key, Value])
- end, maps:to_list(UnhandledConfig)),
- io_lib:format(" Id: ~p~n"
- " Module: ~p~n"
- " Level: ~p~n"
- " Formatter:~n"
- " Module: ~p~n"
- " Config: ~p~n"
- " Filter Default: ~p~n"
- " Filters:~n~s"
- " Handler Config:~n"
- "~s"
- "",[Id, Module, Level, FormatterModule, FormatterConfig,
- FilterDefault, print_filters(8, Filters), Unhandled]);
-print_handlers(Handlers) ->
- lists:map(fun print_handlers/1, Handlers).
-
-print_module_levels({Module,Level}) ->
- io_lib:format(" Module: ~p~n"
- " Level: ~p~n",
- [Module,Level]);
-print_module_levels(ModuleLevels) ->
- lists:map(fun print_module_levels/1, ModuleLevels).
-
--spec setup_standard_handler() -> ok | {error,term()}.
-setup_standard_handler() ->
- case get_logger_type() of
- {ok,silent} ->
- Level = get_logger_level(),
- ok = set_logger_config(level,Level),
- remove_handler(logger_simple);
- {ok,Type} ->
- Level = get_logger_level(),
- ok = set_logger_config(level,Level),
- Filters = get_logger_filters(),
- setup_standard_handler(Type,#{level=>Level,
- filter_default=>stop,
- filters=>Filters});
- Error ->
- Error
+-spec get_config() -> #{primary=>primary_config(),
+ handlers=>[handler_config()],
+ module_levels=>[{module(),level() | all | none}]}.
+get_config() ->
+ #{primary=>get_primary_config(),
+ handlers=>get_handler_config(),
+ module_levels=>lists:keysort(1,get_module_level())}.
+
+-spec internal_init_logger() -> ok | {error,term()}.
+%% This function is responsible for config of the logger
+%% This is done before add_handlers because we want the
+%% logger settings to take effect before the kernel supervisor
+%% tree is started.
+internal_init_logger() ->
+ try
+ ok = logger:set_primary_config(level, get_logger_level()),
+ ok = logger:set_primary_config(filter_default, get_primary_filter_default()),
+
+ [case logger:add_primary_filter(Id, Filter) of
+ ok -> ok;
+ {error, Reason} -> throw(Reason)
+ end || {Id, Filter} <- get_primary_filters()],
+
+ _ = [[case logger:set_module_level(Module, Level) of
+ ok -> ok;
+ {error, Reason} -> throw(Reason)
+ end || Module <- Modules]
+ || {module_level, Level, Modules} <- get_logger_env()],
+
+ case logger:set_handler_config(simple,filters,
+ get_default_handler_filters()) of
+ ok -> ok;
+ {error,{not_found,simple}} -> ok
+ end,
+
+ init_kernel_handlers()
+ catch throw:Reason ->
+ ?LOG_ERROR("Invalid logger config: ~p", [Reason]),
+ {error, {bad_config, {kernel, Reason}}}
end.
--spec setup_standard_handler(Type,Config) -> ok | {error,term()} when
- Type :: tty | standard_io | standard_error | {file,File} |
- {file,File,Modes} | {disk_log,LogOpts} | false,
- File :: file:filename(),
- Modes :: [term()], % [file:mode()], or more specific?
- Config :: config(),
- LogOpts :: map().
-setup_standard_handler(false,#{level:=Level,filters:=Filters}) ->
- case set_handler_config(logger_simple,level,Level) of
- ok ->
- set_handler_config(logger_simple,filters,Filters);
- Error ->
- Error
- end;
-setup_standard_handler(Type,Config) ->
- {Module,TypeConfig} = get_type_config(Type),
- replace_simple_handler(?STANDARD_HANDLER,
- Module,
- maps:merge(Config,TypeConfig)).
-
--spec replace_simple_handler(Id,Module,Config) -> ok | {error,term()} when
- Id :: handler_id(),
- Module :: module(),
- Config :: config().
-replace_simple_handler(Id,Module,Config) ->
- _ = code:ensure_loaded(Module),
- DoBuffer = erlang:function_exported(Module,swap_buffer,2),
- case add_handler(Id,Module,Config#{wait_for_buffer=>DoBuffer}) of
- ok ->
- if DoBuffer ->
- {ok,Buffered} = logger_simple:get_buffer(),
- _ = remove_handler(logger_simple),
- Module:swap_buffer(?STANDARD_HANDLER,Buffered);
- true ->
- _ = remove_handler(logger_simple),
- ok
- end,
- ok;
- Error ->
- Error
+-spec init_kernel_handlers() -> ok | {error,term()}.
+%% Setup the kernel environment variables to be correct
+%% The actual handlers are started by a call to add_handlers.
+init_kernel_handlers() ->
+ try
+ case get_logger_type() of
+ {ok,silent} ->
+ ok = logger:remove_handler(simple);
+ {ok,false} ->
+ ok;
+ {ok,Type} ->
+ init_default_config(Type)
+ end
+ catch throw:Reason ->
+ ?LOG_ERROR("Invalid default handler config: ~p", [Reason]),
+ {error, {bad_config, {kernel, Reason}}}
+ end.
+
+-spec add_handlers(Application) -> ok | {error,term()} when
+ Application :: atom();
+ (HandlerConfig) -> ok | {error,term()} when
+ HandlerConfig :: [config_handler()].
+%% This function is responsible for resolving the handler config
+%% and then starting the correct handlers. This is done after the
+%% kernel supervisor tree has been started as it needs the logger_sup.
+add_handlers(App) when is_atom(App) ->
+ add_handlers(application:get_env(App, logger, []));
+add_handlers(HandlerConfig) ->
+ try
+ check_logger_config(HandlerConfig),
+ DefaultAdded =
+ lists:foldl(
+ fun({handler, default = Id, Module, Config}, _)
+ when not is_map_key(filters, Config) ->
+ %% The default handler should have a couple of extra filters
+ %% set on it by default.
+ DefConfig = #{ filter_default => stop,
+ filters => get_default_handler_filters()},
+ setup_handler(Id, Module, maps:merge(DefConfig,Config)),
+ true;
+ ({handler, Id, Module, Config}, Default) ->
+ setup_handler(Id, Module, Config),
+ Default orelse Id == default;
+ (_, Default) -> Default
+ end, false, HandlerConfig),
+ %% If a default handler was added we try to remove the simple_logger
+ %% If the simple logger exists it will replay its log events
+ %% to the handler(s) added in the fold above.
+ _ = [case logger:remove_handler(simple) of
+ ok -> ok;
+ {error,{not_found,simple}} -> ok
+ end || DefaultAdded],
+ ok
+ catch throw:Reason ->
+ ?LOG_ERROR("Invalid logger handler config: ~p", [Reason]),
+ {error, {bad_config, {handler, Reason}}}
end.
+setup_handler(Id, Module, Config) ->
+ case logger:add_handler(Id, Module, Config) of
+ ok -> ok;
+ {error, Reason} -> throw(Reason)
+ end.
+
+check_logger_config(_) ->
+ ok.
+
+-spec get_logger_type() -> {ok, standard_io | false | silent |
+ {file, file:name_all()} |
+ {file, file:name_all(), [file:mode()]}}.
get_logger_type() ->
- Type0 =
- case application:get_env(kernel, logger_dest) of
- undefined ->
- application:get_env(kernel, error_logger);
- T ->
- T
- end,
- case Type0 of
+ case application:get_env(kernel, error_logger) of
{ok, tty} ->
- {ok, tty};
+ {ok, standard_io};
{ok, {file, File}} when is_list(File) ->
{ok, {file, File}};
{ok, {file, File, Modes}} when is_list(File), is_list(Modes) ->
{ok, {file, File, Modes}};
- {ok, {disk_log, File}} when is_list(File) ->
- {ok, {disk_log, get_disk_log_config(File)}};
{ok, false} ->
{ok, false};
{ok, silent} ->
{ok, silent};
undefined ->
- {ok, tty}; % default value
+ case lists:member({handler,default,undefined}, get_logger_env()) of
+ true ->
+ {ok, false};
+ false ->
+ {ok, standard_io} % default value
+ end;
{ok, Bad} ->
- {error,{bad_config, {kernel, {logger_dest, Bad}}}}
+ throw({error_logger, Bad})
end.
-get_disk_log_config(File) ->
- Config1 =
- case application:get_env(kernel,logger_disk_log_maxfiles) of
- undefined -> #{};
- {ok,MF} -> #{max_no_files=>MF}
- end,
- Config2 =
- case application:get_env(kernel,logger_disk_log_maxbytes) of
- undefined -> Config1;
- {ok,MB} -> Config1#{max_no_bytes=>MB}
- end,
- Config3 =
- case application:get_env(kernel,logger_disk_log_type) of
- undefined -> Config2;
- {ok,T} -> Config1#{type=>T}
- end,
- Config3#{file=>File}.
-
get_logger_level() ->
- case application:get_env(kernel,logger_level) of
- undefined -> info;
- {ok,Level} when ?IS_LEVEL(Level) -> Level
+ case application:get_env(kernel,logger_level,info) of
+ Level when ?IS_LEVEL(Level); Level=:=all; Level=:=none ->
+ Level;
+ Level ->
+ throw({logger_level, Level})
end.
-get_logger_filters() ->
- case application:get_env(kernel, logger_sasl_compatible, false) of
- true ->
- ?DEFAULT_HANDLER_FILTERS([beam,erlang,otp]);
+get_primary_filter_default() ->
+ case lists:keyfind(filters,1,get_logger_env()) of
+ {filters,Default,_} ->
+ Default;
false ->
- Extra =
- case application:get_env(kernel, logger_log_progress, false) of
- true ->
- [];
- false ->
- [{stop_progress,
- {fun logger_filters:progress/2,stop}}]
- end,
- Extra ++ ?DEFAULT_HANDLER_FILTERS([beam,erlang,otp,sasl])
- end.
-
-get_type_config({disk_log,LogOpts}) ->
- {logger_disk_log_h,#{disk_log_opts=>LogOpts}};
-get_type_config(tty) ->
- %% This is only for backwards compatibility with error_logger and
- %% old kernel and sasl environment variables
- get_type_config(standard_io);
-get_type_config(Type) when Type==standard_io;
- Type==standard_error;
- element(1,Type)==file ->
- {logger_std_h,#{logger_std_h=>#{type=>Type}}};
-get_type_config(Type) ->
- {error,{illegal_logger_type,Type}}.
-
-%%%-----------------------------------------------------------------
--spec limit_term(term()) -> term().
-
-limit_term(Term) ->
- try get_format_depth() of
- unlimited -> Term;
- D -> io_lib:limit_term(Term, D)
- catch error:badarg ->
- %% This could happen during system termination, after
- %% application_controller process is dead.
- unlimited
+ log
end.
--spec get_format_depth() -> 'unlimited' | pos_integer().
-
-get_format_depth() ->
- Depth =
- case application:get_env(kernel, logger_format_depth) of
- {ok, D} when is_integer(D) ->
- D;
- undefined ->
- case application:get_env(kernel, error_logger_format_depth) of
- {ok, D} when is_integer(D) ->
- D;
- undefined ->
- unlimited
- end
+get_primary_filters() ->
+ lists:foldl(
+ fun({filters, _, Filters}, _Acc) ->
+ Filters;
+ (_, Acc) ->
+ Acc
+ end, [], get_logger_env()).
+
+%% This function looks at the kernel logger environment
+%% and updates it so that the correct logger is configured
+init_default_config(Type) when Type==standard_io;
+ Type==standard_error;
+ element(1,Type)==file ->
+ Env = get_logger_env(),
+ DefaultFormatter = #{formatter=>{?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}},
+ DefaultConfig = DefaultFormatter#{config=>#{type=>Type}},
+ NewLoggerEnv =
+ case lists:keyfind(default, 2, Env) of
+ {handler, default, Module, Config} ->
+ lists:map(
+ fun({handler, default, logger_std_h, _}) ->
+ %% Only want to add the logger_std_h config
+ %% if not configured by user AND the default
+ %% handler is still the logger_std_h.
+ {handler, default, Module, maps:merge(DefaultConfig,Config)};
+ ({handler, default, logger_disk_log_h, _}) ->
+ %% Add default formatter. The point of this
+ %% is to get the expected formatter config
+ %% for the default handler, since this
+ %% differs from the default values that
+ %% logger_formatter itself adds.
+ {handler, default, logger_disk_log_h, maps:merge(DefaultFormatter,Config)};
+ (Other) ->
+ Other
+ end, Env);
+ _ ->
+ %% Nothing has been configured, use default
+ [{handler, default, logger_std_h, DefaultConfig} | Env]
end,
- max(10, Depth).
+ application:set_env(kernel, logger, NewLoggerEnv, [{timeout,infinity}]);
+init_default_config(Type) ->
+ throw({illegal_logger_type,Type}).
--spec get_max_size() -> 'unlimited' | pos_integer().
-
-get_max_size() ->
- case application:get_env(kernel, logger_max_size) of
- {ok, Size} when is_integer(Size) ->
- max(50, Size);
- undefined ->
- unlimited
+get_default_handler_filters() ->
+ case application:get_env(kernel, logger_sasl_compatible, false) of
+ true ->
+ ?DEFAULT_HANDLER_FILTERS([otp]);
+ false ->
+ ?DEFAULT_HANDLER_FILTERS([otp,sasl])
end.
--spec get_utc_config() -> boolean().
-
-get_utc_config() ->
- %% Kernel's logger_utc configuration overrides SASL utc_log, which
- %% in turn overrides stdlib config - in order to have uniform
- %% timestamps in log messages
- case application:get_env(kernel, logger_utc) of
- {ok, Val} -> Val;
- undefined ->
- case application:get_env(sasl, utc_log) of
- {ok, Val} -> Val;
- undefined ->
- case application:get_env(stdlib, utc_log) of
- {ok, Val} -> Val;
- undefined -> false
- end
- end
- end.
+get_logger_env() ->
+ application:get_env(kernel, logger, []).
%%%-----------------------------------------------------------------
%%% Internal
-do_log(warning,Msg,Meta) ->
- do_log_1(error_logger:warning_map(),Msg,Meta);
-do_log(Level,Msg,Meta) ->
- do_log_1(Level,Msg,Meta).
-
-do_log_1(Level,Msg,#{mfa:={Module,_,_}}=Meta) ->
+do_log(Level,Msg,#{mfa:={Module,_,_}}=Meta) ->
case logger_config:allow(?LOGGER_TABLE,Level,Module) of
true ->
log_allowed(#{},Level,Msg,Meta);
false ->
ok
end;
-do_log_1(Level,Msg,Meta) ->
+do_log(Level,Msg,Meta) ->
case logger_config:allow(?LOGGER_TABLE,Level) of
true ->
log_allowed(#{},Level,Msg,Meta);
@@ -819,7 +888,7 @@ proc_meta() ->
default(pid) -> self();
default(gl) -> group_leader();
-default(time) -> erlang:monotonic_time(microsecond).
+default(time) -> erlang:system_time(microsecond).
%% Remove everything upto and including this module from the stacktrace
filter_stacktrace(Module,[{Module,_,_,_}|_]) ->
diff --git a/lib/kernel/src/logger_backend.erl b/lib/kernel/src/logger_backend.erl
index d9f5aa6faf..4d7bd6b2a0 100644
--- a/lib/kernel/src/logger_backend.erl
+++ b/lib/kernel/src/logger_backend.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -28,9 +28,9 @@
%%%-----------------------------------------------------------------
%%% The default logger backend
log_allowed(Log, Tid) ->
- {ok,Config} = logger_config:get(Tid,logger),
+ {ok,Config} = logger_config:get(Tid,primary),
Filters = maps:get(filters,Config,[]),
- case apply_filters(logger,Log,Filters,Config) of
+ case apply_filters(primary,Log,Filters,Config) of
stop ->
ok;
Log1 ->
@@ -58,7 +58,7 @@ call_handlers(#{level:=Level}=Log,[Id|Handlers],Tid) ->
debug,
[{logger,removed_failing_handler},
{handler,{Id,Module}},
- {log,Log1},
+ {log_event,Log1},
{config,Config1},
{reason,{C,R,filter_stacktrace(S)}}]);
{error,{not_found,_}} ->
@@ -122,7 +122,7 @@ handle_filter_failed({Id,_}=Filter,Owner,Log,Reason) ->
[{logger,removed_failing_filter},
{filter,Filter},
{owner,Owner},
- {log,Log},
+ {log_event,Log},
{reason,Reason}]);
_ ->
ok
diff --git a/lib/kernel/src/logger_config.erl b/lib/kernel/src/logger_config.erl
index 799aea9617..55427dce5a 100644
--- a/lib/kernel/src/logger_config.erl
+++ b/lib/kernel/src/logger_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,14 +24,14 @@
allow/2,allow/3,
get/2, get/3, get/1,
create/3, create/4, set/3,
- set_module_level/3,reset_module_level/2,
- cache_module_level/2,
+ set_module_level/3,unset_module_level/2,
+ get_module_level/1,cache_module_level/2,
level_to_int/1]).
-include("logger_internal.hrl").
new(Name) ->
- _ = ets:new(Name,[set,protected,named_table]),
+ _ = ets:new(Name,[set,protected,named_table,{write_concurrency,true}]),
ets:whereis(Name).
delete(Tid,Id) ->
@@ -54,7 +54,7 @@ allow(Tid,Level,Module) ->
end.
allow(Tid,Level) ->
- GlobalLevelInt = ets:lookup_element(Tid,?LOGGER_KEY,2),
+ GlobalLevelInt = ets:lookup_element(Tid,?PRIMARY_KEY,2),
level_to_int(Level) =< GlobalLevelInt.
exist(Tid,What) ->
@@ -71,7 +71,7 @@ get(Tid,What) ->
end.
get(Tid,What,Level) ->
- MS = [{{table_key(What),'$1','$2'}, % logger config
+ MS = [{{table_key(What),'$1','$2'}, % primary config
[{'>=','$1',level_to_int(Level)}],
['$2']},
{{table_key(What),'$1','$2','$3'}, % handler config
@@ -94,7 +94,7 @@ set(Tid,What,Config) ->
%% Should do this only if the level has actually changed. Possibly
%% overwrite instead of delete?
case What of
- logger ->
+ primary ->
_ = ets:select_delete(Tid,[{{'_',{'$1',cached}},
[{'=/=','$1',LevelInt}],
[true]}]),
@@ -105,27 +105,38 @@ set(Tid,What,Config) ->
ets:update_element(Tid,table_key(What),[{2,LevelInt},{3,Config}]),
ok.
-set_module_level(Tid,Module,Level) ->
- ets:insert(Tid,{Module,level_to_int(Level)}),
+set_module_level(Tid,Modules,Level) ->
+ LevelInt = level_to_int(Level),
+ [ets:insert(Tid,{Module,LevelInt}) || Module <- Modules],
ok.
-reset_module_level(Tid,Module) ->
- ets:delete(Tid,Module), % should possibley overwrite instead of delete?
+%% should possibly overwrite instead of delete?
+unset_module_level(Tid,all) ->
+ MS = [{{'$1','$2'},[{is_atom,'$1'},{is_integer,'$2'}],[true]}],
+ _ = ets:select_delete(Tid,MS),
+ ok;
+unset_module_level(Tid,Modules) ->
+ [ets:delete(Tid,Module) || Module <- Modules],
ok.
+get_module_level(Tid) ->
+ MS = [{{'$1','$2'},[{is_atom,'$1'},{is_integer,'$2'}],[{{'$1','$2'}}]}],
+ Modules = ets:select(Tid,MS),
+ lists:sort([{M,int_to_level(L)} || {M,L} <- Modules]).
+
cache_module_level(Tid,Module) ->
- GlobalLevelInt = ets:lookup_element(Tid,?LOGGER_KEY,2),
+ GlobalLevelInt = ets:lookup_element(Tid,?PRIMARY_KEY,2),
ets:insert_new(Tid,{Module,{GlobalLevelInt,cached}}),
ok.
get(Tid) ->
- {ok,Logger} = get(Tid,logger),
+ {ok,Primary} = get(Tid,primary),
HMS = [{{table_key('$1'),'_','$2','$3'},[],[{{'$1','$3','$2'}}]}],
Handlers = ets:select(Tid,HMS),
- MMS = [{{'$1','$2'},[{is_atom,'$1'},{is_integer,'$2'}],[{{'$1','$2'}}]}],
- Modules = ets:select(Tid,MMS),
- {Logger,Handlers,[{M,int_to_level(L)} || {M,L} <- Modules]}.
+ Modules = get_module_level(Tid),
+ {Primary,Handlers,Modules}.
+level_to_int(none) -> ?LOG_NONE;
level_to_int(emergency) -> ?EMERGENCY;
level_to_int(alert) -> ?ALERT;
level_to_int(critical) -> ?CRITICAL;
@@ -133,8 +144,10 @@ level_to_int(error) -> ?ERROR;
level_to_int(warning) -> ?WARNING;
level_to_int(notice) -> ?NOTICE;
level_to_int(info) -> ?INFO;
-level_to_int(debug) -> ?DEBUG.
+level_to_int(debug) -> ?DEBUG;
+level_to_int(all) -> ?LOG_ALL.
+int_to_level(?LOG_NONE) -> none;
int_to_level(?EMERGENCY) -> emergency;
int_to_level(?ALERT) -> alert;
int_to_level(?CRITICAL) -> critical;
@@ -142,10 +155,11 @@ int_to_level(?ERROR) -> error;
int_to_level(?WARNING) -> warning;
int_to_level(?NOTICE) -> notice;
int_to_level(?INFO) -> info;
-int_to_level(?DEBUG) -> debug.
+int_to_level(?DEBUG) -> debug;
+int_to_level(?LOG_ALL) -> all.
%%%-----------------------------------------------------------------
%%% Internal
-table_key(logger) -> ?LOGGER_KEY;
+table_key(primary) -> ?PRIMARY_KEY;
table_key(HandlerId) -> {?HANDLER_KEY,HandlerId}.
diff --git a/lib/kernel/src/logger_disk_log_h.erl b/lib/kernel/src/logger_disk_log_h.erl
index 0150fa781a..e56531c3cb 100644
--- a/lib/kernel/src/logger_disk_log_h.erl
+++ b/lib/kernel/src/logger_disk_log_h.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,16 +26,17 @@
-include("logger_h_common.hrl").
%%% API
--export([start_link/3, info/1, disk_log_sync/1, reset/1]).
+-export([start_link/3, info/1, filesync/1, reset/1]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
%% logger callbacks
--export([log/2,
- adding_handler/2, removing_handler/2,
- changing_config/3, swap_buffer/2]).
+-export([log/2, adding_handler/1, removing_handler/1, changing_config/2]).
+
+%% handler internal
+-export([log_handler_info/4]).
%%%===================================================================
%%% API
@@ -47,7 +48,7 @@
%%% handler process gets added (as a result of calling add/3).
-spec start_link(Name, Config, HandlerState) -> {ok,Pid} | {error,Reason} when
Name :: atom(),
- Config :: logger:config(),
+ Config :: logger:handler_config(),
HandlerState :: map(),
Pid :: pid(),
Reason :: term().
@@ -57,18 +58,19 @@ start_link(Name, Config, HandlerState) ->
%%%-----------------------------------------------------------------
%%%
--spec disk_log_sync(Name) -> ok | {error,Reason} when
+-spec filesync(Name) -> ok | {error,Reason} when
Name :: atom(),
Reason :: handler_busy | {badarg,term()}.
-disk_log_sync(Name) when is_atom(Name) ->
+filesync(Name) when is_atom(Name) ->
try
- gen_server:call(Name, disk_log_sync, ?DEFAULT_CALL_TIMEOUT)
+ gen_server:call(?name_to_reg_name(?MODULE,Name),
+ disk_log_sync, ?DEFAULT_CALL_TIMEOUT)
catch
_:{timeout,_} -> {error,handler_busy}
end;
-disk_log_sync(Name) ->
- {error,{badarg,{disk_log_sync,[Name]}}}.
+filesync(Name) ->
+ {error,{badarg,{filesync,[Name]}}}.
%%%-----------------------------------------------------------------
%%%
@@ -79,7 +81,8 @@ disk_log_sync(Name) ->
info(Name) when is_atom(Name) ->
try
- gen_server:call(Name, info, ?DEFAULT_CALL_TIMEOUT)
+ gen_server:call(?name_to_reg_name(?MODULE,Name),
+ info, ?DEFAULT_CALL_TIMEOUT)
catch
_:{timeout,_} -> {error,handler_busy}
end;
@@ -94,7 +97,8 @@ info(Name) ->
reset(Name) when is_atom(Name) ->
try
- gen_server:call(Name, reset, ?DEFAULT_CALL_TIMEOUT)
+ gen_server:call(?name_to_reg_name(?MODULE,Name),
+ reset, ?DEFAULT_CALL_TIMEOUT)
catch
_:{timeout,_} -> {error,handler_busy}
end;
@@ -108,27 +112,20 @@ reset(Name) ->
%%%-----------------------------------------------------------------
%%% Handler being added
-adding_handler(Name, Config) ->
- case check_config(adding, Name, Config) of
+adding_handler(#{id:=Name}=Config) ->
+ case check_config(adding, Config) of
{ok, Config1} ->
%% create initial handler state by merging defaults with config
- HConfig = maps:get(?MODULE, Config1, #{}),
+ HConfig = maps:get(config, Config1, #{}),
HState = maps:merge(get_init_state(), HConfig),
case logger_h_common:overload_levels_ok(HState) of
true ->
- case start(Name, Config1, HState) of
- ok ->
- %% Make sure wait_for_buffer is not stored, so we
- %% won't hang and wait for buffer on a restart
- {ok, maps:remove(wait_for_buffer,Config1)};
- Error ->
- Error
- end;
+ start(Name, Config1, HState);
false ->
- #{toggle_sync_qlen := TSQL,
- drop_new_reqs_qlen := DNRQL,
- flush_reqs_qlen := FRQL} = HState,
- {error,{invalid_levels,{TSQL,DNRQL,FRQL}}}
+ #{sync_mode_qlen := SMQL,
+ drop_mode_qlen := DMQL,
+ flush_qlen := FQL} = HState,
+ {error,{invalid_levels,{SMQL,DMQL,FQL}}}
end;
Error ->
Error
@@ -136,176 +133,184 @@ adding_handler(Name, Config) ->
%%%-----------------------------------------------------------------
%%% Updating handler config
-changing_config(Name,
- OldConfig=#{id:=Id, disk_log_opts:=DLOpts},
- NewConfig=#{id:=Id, disk_log_opts:=DLOpts}) ->
- case check_config(changing, Name, NewConfig) of
- Result = {ok,NewConfig1} ->
- try gen_server:call(Name, {change_config,OldConfig,NewConfig1},
+changing_config(OldConfig = #{id:=Name, config:=OldHConfig},
+ NewConfig = #{id:=Name, config:=NewHConfig}) ->
+ #{type:=Type, file:=File, max_no_files:=MaxFs,
+ max_no_bytes:=MaxBytes} = OldHConfig,
+ case NewHConfig of
+ #{type:=Type, file:=File, max_no_files:=MaxFs,
+ max_no_bytes:=MaxBytes} ->
+ changing_config1(OldConfig, NewConfig);
+ _ ->
+ {error,{illegal_config_change,OldConfig,NewConfig}}
+ end;
+changing_config(OldConfig, NewConfig) ->
+ {error,{illegal_config_change,OldConfig,NewConfig}}.
+
+changing_config1(OldConfig=#{config:=OldHConfig}, NewConfig) ->
+ case check_config(changing, NewConfig) of
+ {ok,NewConfig1 = #{config:=NewHConfig}} ->
+ #{handler_pid:=HPid,
+ mode_tab:=ModeTab} = OldHConfig,
+ NewHConfig1 = NewHConfig#{handler_pid=>HPid,
+ mode_tab=>ModeTab},
+ NewConfig2 = NewConfig1#{config=>NewHConfig1},
+ try gen_server:call(HPid, {change_config,OldConfig,NewConfig2},
?DEFAULT_CALL_TIMEOUT) of
- ok -> Result;
+ ok -> {ok,NewConfig2};
HError -> HError
catch
_:{timeout,_} -> {error,handler_busy}
end;
Error ->
Error
- end;
-changing_config(_Name, OldConfig, NewConfig) ->
- {error,{illegal_config_change,OldConfig,NewConfig}}.
+ end.
-check_config(adding, Name, Config0) ->
- %% Merge in defaults on top level
- Config = maps:merge(#{id => Name}, Config0),
- %% Merge in defaults on handler level
- LogOpts0 = maps:get(disk_log_opts, Config, #{}),
- LogOpts = merge_default_logopts(Name, LogOpts0),
- case check_log_opts(maps:to_list(LogOpts)) of
+check_config(adding, #{id:=Name}=Config) ->
+ %% merge handler specific config data
+ HConfig = merge_default_logopts(Name, maps:get(config, Config, #{})),
+ case check_h_config(maps:to_list(HConfig)) of
ok ->
- MyConfig = maps:get(?MODULE, Config, #{}),
- case check_my_config(maps:to_list(MyConfig)) of
- ok ->
- {ok,Config#{disk_log_opts=>LogOpts,
- ?MODULE=>MyConfig}};
- Error ->
- Error
- end;
+ {ok,Config#{config=>HConfig}};
Error ->
Error
end;
-check_config(changing, _Name, Config) ->
- MyConfig = maps:get(?MODULE, Config, #{}),
- case check_my_config(maps:to_list(MyConfig)) of
+check_config(changing, Config) ->
+ HConfig = maps:get(config, Config, #{}),
+ case check_h_config(maps:to_list(HConfig)) of
ok -> {ok,Config};
Error -> Error
end.
-merge_default_logopts(Name, LogOpts) ->
- Type = maps:get(type, LogOpts, wrap),
+merge_default_logopts(Name, HConfig) ->
+ Type = maps:get(type, HConfig, wrap),
{DefaultNoFiles,DefaultNoBytes} =
case Type of
halt -> {undefined,infinity};
_wrap -> {10,1048576}
end,
{ok,Dir} = file:get_cwd(),
- Default = #{file => filename:join(Dir,Name),
- max_no_files => DefaultNoFiles,
- max_no_bytes => DefaultNoBytes,
- type => Type},
- maps:merge(Default,LogOpts).
-
-check_log_opts([{file,File}|Opts]) when is_list(File) ->
- check_log_opts(Opts);
-check_log_opts([{max_no_files,undefined}|Opts]) ->
- check_log_opts(Opts);
-check_log_opts([{max_no_files,N}|Opts]) when is_integer(N), N>0 ->
- check_log_opts(Opts);
-check_log_opts([{max_no_bytes,infinity}|Opts]) ->
- check_log_opts(Opts);
-check_log_opts([{max_no_bytes,N}|Opts]) when is_integer(N), N>0 ->
- check_log_opts(Opts);
-check_log_opts([{type,Type}|Opts]) when Type==wrap; Type==halt ->
- check_log_opts(Opts);
-check_log_opts([Invalid|_]) ->
- {error,{invalid_config,disk_log_opt,Invalid}};
-check_log_opts([]) ->
- ok.
-
-check_my_config([Other | Config]) ->
+ Defaults = #{file => filename:join(Dir,Name),
+ max_no_files => DefaultNoFiles,
+ max_no_bytes => DefaultNoBytes,
+ type => Type},
+ maps:merge(Defaults, HConfig).
+
+check_h_config([{file,File}|Config]) when is_list(File) ->
+ check_h_config(Config);
+check_h_config([{max_no_files,undefined}|Config]) ->
+ check_h_config(Config);
+check_h_config([{max_no_files,N}|Config]) when is_integer(N), N>0 ->
+ check_h_config(Config);
+check_h_config([{max_no_bytes,infinity}|Config]) ->
+ check_h_config(Config);
+check_h_config([{max_no_bytes,N}|Config]) when is_integer(N), N>0 ->
+ check_h_config(Config);
+check_h_config([{type,Type}|Config]) when Type==wrap; Type==halt ->
+ check_h_config(Config);
+check_h_config([Other | Config]) ->
case logger_h_common:check_common_config(Other) of
valid ->
- check_my_config(Config);
+ check_h_config(Config);
invalid ->
{error,{invalid_config,?MODULE,Other}}
end;
-check_my_config([]) ->
+check_h_config([]) ->
ok.
%%%-----------------------------------------------------------------
%%% Handler being removed
-removing_handler(Name, _Config) ->
+removing_handler(#{id:=Name}) ->
stop(Name).
%%%-----------------------------------------------------------------
-%%% Get buffer when swapping from simple handler
-swap_buffer(Name,Buffer) ->
- case whereis(Name) of
- undefined ->
- ok;
- _ ->
- Name ! {buffer,Buffer}
- end.
-
-%%%-----------------------------------------------------------------
%%% Log a string or report
--spec log(Log, Config) -> ok | dropped when
- Log :: logger:log(),
- Config :: logger:config().
-
-log(Log,Config=#{id:=Name}) ->
- %% if the handler has crashed, we must drop this request
+-spec log(LogEvent, Config) -> ok | dropped when
+ LogEvent :: logger:log_event(),
+ Config :: logger:handler_config().
+
+log(LogEvent, Config = #{id := Name,
+ config := #{handler_pid := HPid,
+ mode_tab := ModeTab}}) ->
+ %% if the handler has crashed, we must drop this event
%% and hope the handler restarts so we can try again
- true = is_pid(whereis(Name)),
- Bin = logger_h_common:log_to_binary(Log,Config),
- logger_h_common:call_cast_or_drop(Name, Bin).
-
+ true = is_process_alive(HPid),
+ Bin = logger_h_common:log_to_binary(LogEvent, Config),
+ logger_h_common:call_cast_or_drop(Name, HPid, ModeTab, Bin).
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
-init([Name, Config = #{disk_log_opts := LogOpts},
+init([Name,
+ Config = #{config := HConfig = #{file:=File,
+ type:=Type,
+ max_no_bytes:=MNB,
+ max_no_files:=MNF}},
State = #{dl_sync_int := DLSyncInt}]) ->
- register(Name, self()),
+
+ RegName = ?name_to_reg_name(?MODULE,Name),
+ register(RegName, self()),
process_flag(trap_exit, true),
process_flag(message_queue_data, off_heap),
?init_test_hooks(),
?start_observation(Name),
-
- case open_disk_log(Name, LogOpts) of
+
+ LogOpts = #{file=>File, type=>Type, max_no_bytes=>MNB, max_no_files=>MNF},
+ case open_disk_log(Name, File, Type, MNB, MNF) of
ok ->
- catch ets:new(Name, [public, named_table]),
- ?set_mode(Name, async),
- proc_lib:init_ack({ok,self()}),
- T0 = ?timestamp(),
- State1 =
- ?merge_with_stats(State#{id => Name,
- mode => async,
- dl_sync => DLSyncInt,
- log_opts => LogOpts,
- last_qlen => 0,
- last_log_ts => T0,
- burst_win_ts => T0,
- burst_msg_count => 0,
- prev_log_result => ok,
- prev_sync_result => ok,
- prev_disk_log_info => undefined}),
- gen_server:cast(self(), {repeated_disk_log_sync,T0}),
- enter_loop(Config, State1);
+ try ets:new(Name, [public]) of
+ ModeTab ->
+ ?set_mode(ModeTab, async),
+ T0 = ?timestamp(),
+ State1 =
+ ?merge_with_stats(State#{
+ id => Name,
+ mode_tab => ModeTab,
+ mode => async,
+ dl_sync => DLSyncInt,
+ log_opts => LogOpts,
+ last_qlen => 0,
+ last_log_ts => T0,
+ burst_win_ts => T0,
+ burst_msg_count => 0,
+ last_op => sync,
+ prev_log_result => ok,
+ prev_sync_result => ok,
+ prev_disk_log_info => undefined}),
+ Config1 =
+ Config#{config => HConfig#{handler_pid => self(),
+ mode_tab => ModeTab}},
+ proc_lib:init_ack({ok,self(),Config1}),
+ gen_server:cast(self(), repeated_disk_log_sync),
+ case logger_h_common:unset_restart_flag(Name, ?MODULE) of
+ true ->
+ %% inform about restart
+ gen_server:cast(self(), {log_handler_info,
+ "Handler ~p restarted",
+ [Name]});
+ false ->
+ %% initial start
+ ok
+ end,
+ enter_loop(Config1, State1)
+ catch
+ _:Error ->
+ unregister(RegName),
+ logger_h_common:error_notify({open_disk_log,Name,Error}),
+ proc_lib:init_ack(Error)
+ end;
Error ->
+ unregister(RegName),
logger_h_common:error_notify({open_disk_log,Name,Error}),
proc_lib:init_ack(Error)
end.
-enter_loop(#{wait_for_buffer:=true}=Config,State) ->
- State1 =
- receive
- {buffer,Buffer} ->
- lists:foldl(
- fun(Log,S) ->
- Bin = logger_h_common:log_to_binary(Log,Config),
- {_,S1} = do_log(Bin,cast,S),
- S1
- end,
- State,
- Buffer)
- end,
- gen_server:enter_loop(?MODULE,[],State1);
enter_loop(_Config,State) ->
gen_server:enter_loop(?MODULE,[],State).
-%% This is the synchronous log request.
+%% This is the synchronous log event.
handle_call({log, Bin}, _From, State) ->
{Result,State1} = do_log(Bin, call, State),
%% Result == ok | dropped
@@ -316,12 +321,11 @@ handle_call(disk_log_sync, _From, State = #{id := Name}) ->
{reply, Result, State1};
handle_call({change_config,_OldConfig,NewConfig}, _From,
- State = #{filesync_repeat_interval := FSyncInt0,
- last_log_ts := LastLogTS}) ->
- HConfig = maps:get(?MODULE, NewConfig, #{}),
- State1 = #{toggle_sync_qlen := TSQL,
- drop_new_reqs_qlen := DNRQL,
- flush_reqs_qlen := FRQL} = maps:merge(State, HConfig),
+ State = #{filesync_repeat_interval := FSyncInt0}) ->
+ HConfig = maps:get(config, NewConfig, #{}),
+ State1 = #{sync_mode_qlen := SMQL,
+ drop_mode_qlen := DMQL,
+ flush_qlen := FQL} = maps:merge(State, HConfig),
case logger_h_common:overload_levels_ok(State1) of
true ->
_ =
@@ -338,12 +342,11 @@ handle_call({change_config,_OldConfig,NewConfig}, _From,
_ = logger_h_common:cancel_timer(maps:get(rep_sync_tref,
State,
undefined)),
- _ = gen_server:cast(self(), {repeated_disk_log_sync,
- LastLogTS})
- end,
+ _ = gen_server:cast(self(), repeated_disk_log_sync)
+ end,
{reply, ok, State1};
false ->
- {reply, {error,{invalid_levels,{TSQL,DNRQL,FRQL}}}, State}
+ {reply, {error,{invalid_levels,{SMQL,DMQL,FQL}}}, State}
end;
handle_call(info, _From, State) ->
@@ -361,33 +364,36 @@ handle_call(stop, _From, State) ->
{stop, {shutdown,stopped}, ok, State}.
-%% This is the asynchronous log request.
+%% This is the asynchronous log event.
handle_cast({log, Bin}, State) ->
{_,State1} = do_log(Bin, cast, State),
{noreply, State1};
+handle_cast({log_handler_info, Format, Args}, State = #{id:=Name}) ->
+ log_handler_info(Name, Format, Args, State),
+ {noreply, State};
+
%% If FILESYNC_REPEAT_INTERVAL is set to a millisec value, this
%% clause gets called repeatedly by the handler. In order to
%% guarantee that a filesync *always* happens after the last log
-%% request, the repeat operation must be active!
-handle_cast({repeated_disk_log_sync,LastLogTS0},
+%% event, the repeat operation must be active!
+handle_cast(repeated_disk_log_sync,
State = #{id := Name,
filesync_repeat_interval := FSyncInt,
- last_log_ts := LastLogTS1}) ->
+ last_op := LastOp}) ->
State1 =
if is_integer(FSyncInt) ->
%% only do filesync if something has been
%% written since last time we checked
- NewState = if LastLogTS1 == LastLogTS0 ->
+ NewState = if LastOp == sync ->
State;
true ->
disk_log_sync(Name, State)
end,
{ok,TRef} =
timer:apply_after(FSyncInt, gen_server,cast,
- [self(),
- {repeated_disk_log_sync,LastLogTS1}]),
- NewState#{rep_sync_tref => TRef};
+ [self(),repeated_disk_log_sync]),
+ NewState#{rep_sync_tref => TRef, last_op => sync};
true ->
State
end,
@@ -423,6 +429,7 @@ terminate(Reason, State = #{id := Name}) ->
_ = logger_h_common:cancel_timer(maps:get(rep_sync_tref, State,
undefined)),
_ = close_disk_log(Name, normal),
+ unregister(?name_to_reg_name(?MODULE, Name)),
logger_h_common:stop_or_restart(Name, Reason, State).
code_change(_OldVsn, State, _Extra) ->
@@ -434,19 +441,19 @@ code_change(_OldVsn, State, _Extra) ->
%%%-----------------------------------------------------------------
%%%
get_init_state() ->
- #{toggle_sync_qlen => ?TOGGLE_SYNC_QLEN,
- drop_new_reqs_qlen => ?DROP_NEW_REQS_QLEN,
- flush_reqs_qlen => ?FLUSH_REQS_QLEN,
- enable_burst_limit => ?ENABLE_BURST_LIMIT,
- burst_limit_size => ?BURST_LIMIT_SIZE,
- burst_window_time => ?BURST_WINDOW_TIME,
- enable_kill_overloaded => ?ENABLE_KILL_OVERLOADED,
- handler_overloaded_qlen => ?HANDLER_OVERLOADED_QLEN,
- handler_overloaded_mem => ?HANDLER_OVERLOADED_MEM,
- handler_restart_after => ?HANDLER_RESTART_AFTER,
- dl_sync_int => ?CONTROLLER_SYNC_INTERVAL,
- filesync_ok_qlen => ?FILESYNC_OK_QLEN,
- filesync_repeat_interval => ?FILESYNC_REPEAT_INTERVAL}.
+ #{sync_mode_qlen => ?SYNC_MODE_QLEN,
+ drop_mode_qlen => ?DROP_MODE_QLEN,
+ flush_qlen => ?FLUSH_QLEN,
+ burst_limit_enable => ?BURST_LIMIT_ENABLE,
+ burst_limit_max_count => ?BURST_LIMIT_MAX_COUNT,
+ burst_limit_window_time => ?BURST_LIMIT_WINDOW_TIME,
+ overload_kill_enable => ?OVERLOAD_KILL_ENABLE,
+ overload_kill_qlen => ?OVERLOAD_KILL_QLEN,
+ overload_kill_mem_size => ?OVERLOAD_KILL_MEM_SIZE,
+ overload_kill_restart_after => ?OVERLOAD_KILL_RESTART_AFTER,
+ dl_sync_int => ?CONTROLLER_SYNC_INTERVAL,
+ filesync_ok_qlen => ?FILESYNC_OK_QLEN,
+ filesync_repeat_interval => ?FILESYNC_REPEAT_INTERVAL}.
%%%-----------------------------------------------------------------
%%% Add a disk_log handler to the logger.
@@ -454,22 +461,21 @@ get_init_state() ->
%%% exist if the handler is registered with logger (and should not
%%% exist if the handler is not registered).
%%%
-%%% Config is the logger:config() map containing a sub map with any of
-%%% the following associations:
+%%% Config is the logger:handler_config() map. Handler specific parameters
+%%% should be provided with a sub map associated with a key named
+%%% 'config', e.g:
%%%
-%%% Config = #{disk_log_opts => #{file => file:filename(),
-%%% max_no_bytes => integer(),
-%%% max_no_files => integer(),
-%%% type => wrap | halt}}.
+%%% Config = #{config => #{sync_mode_qlen => 50}
%%%
-%%% This map will be merged with the logger configuration data for
-%%% the disk_log LogName. If type == halt, then max_no_files is
-%%% ignored.
+%%% The 'config' sub map will also contain parameters for configuring
+%%% the disk_log:
%%%
-%%% Handler specific config should be provided with a sub map associated
-%%% with a key named the same as this module, e.g:
+%%% Config = #{config => #{file => file:filename(),
+%%% max_no_bytes => integer(),
+%%% max_no_files => integer(),
+%%% type => wrap | halt}}.
%%%
-%%% Config = #{logger_disk_log_h => #{toggle_sync_qlen => 50}
+%%% If type == halt, then max_no_files is ignored.
%%%
%%% The disk_log handler process is linked to logger_sup, which is
%%% part of the kernel application's supervision tree.
@@ -482,8 +488,9 @@ start(Name, Config, HandlerState) ->
type => worker,
modules => [?MODULE]},
case supervisor:start_child(logger_sup, LoggerDLH) of
- {ok,_} ->
- ok;
+ {ok,Pid,Config1} ->
+ ok = logger_handler_watcher:register_handler(Name,Pid),
+ {ok,Config1};
Error ->
Error
end.
@@ -491,17 +498,20 @@ start(Name, Config, HandlerState) ->
%%%-----------------------------------------------------------------
%%% Stop and remove the handler.
stop(Name) ->
- case whereis(Name) of
+ case whereis(?name_to_reg_name(?MODULE,Name)) of
undefined ->
ok;
- _ ->
+ Pid ->
%% We don't want to do supervisor:terminate_child here
%% since we need to distinguish this explicit stop from a
%% system termination in order to avoid circular attempts
%% at removing the handler (implying deadlocks and
%% timeouts).
- _ = gen_server:call(Name,stop),
- _ = supervisor:delete_child(logger_sup, Name),
+ %% And we don't need to do supervisor:delete_child, since
+ %% the restart type is temporary, which means that the
+ %% child specification is automatically removed from the
+ %% supervisor when the process dies.
+ _ = gen_server:call(Pid, stop),
ok
end.
@@ -511,21 +521,31 @@ stop(Name) ->
if C == 0 -> Interval;
true -> C-1 end).
-%% check for overload between every request (and set Mode to async,
+%% check for overload between every event (and set Mode to async,
%% sync or drop accordingly), but never flush the whole mailbox
-%% before LogWindowSize requests have been handled
-do_log(Bin, CallOrCast, State = #{id:=Name, mode := _Mode0}) ->
+%% before LogWindowSize events have been handled
+do_log(Bin, CallOrCast, State = #{id:=Name, mode := Mode0}) ->
T1 = ?timestamp(),
%% check if the handler is getting overloaded, or if it's
%% recovering from overload (the check must be done for each
- %% request to react quickly to large bursts of requests and
+ %% event to react quickly to large bursts of events and
%% to ensure that the handler can never end up in drop mode
%% with an empty mailbox, which would stop operation)
{Mode1,QLen,Mem,State1} = logger_h_common:check_load(State),
+ if (Mode1 == drop) andalso (Mode0 =/= drop) ->
+ log_handler_info(Name, "Handler ~p switched to drop mode",
+ [Name], State);
+ (Mode0 == drop) andalso ((Mode1 == async) orelse (Mode1 == sync)) ->
+ log_handler_info(Name, "Handler ~p switched to ~w mode",
+ [Name,Mode1], State);
+ true ->
+ ok
+ end,
+
%% kill the handler if it can't keep up with the load
- logger_h_common:kill_if_choked(Name, QLen, Mem, State),
+ logger_h_common:kill_if_choked(Name, QLen, Mem, ?MODULE, State),
if Mode1 == flush ->
flush(Name, QLen, T1, State1);
@@ -535,10 +555,14 @@ do_log(Bin, CallOrCast, State = #{id:=Name, mode := _Mode0}) ->
%% this function is called by do_log/3 after an overload check
%% has been performed, where QLen > FlushQLen
-flush(Name, _QLen0, T1, State=#{last_log_ts := _T0}) ->
+flush(Name, _QLen0, T1, State=#{last_log_ts := _T0, mode_tab := ModeTab}) ->
%% flush messages in the mailbox (a limited number in
%% order to not cause long delays)
- _NewFlushed = logger_h_common:flush_log_requests(?FLUSH_MAX_N),
+ NewFlushed = logger_h_common:flush_log_events(?FLUSH_MAX_N),
+
+ %% write info in log about flushed messages
+ log_handler_info(Name, "Handler ~p flushed ~w log events",
+ [Name,NewFlushed], State),
%% because of the receive loop when flushing messages, the
%% handler will be scheduled out often and the mailbox could
@@ -546,26 +570,27 @@ flush(Name, _QLen0, T1, State=#{last_log_ts := _T0}) ->
{_,_QLen1} = process_info(self(), message_queue_len),
?observe(Name,{max_qlen,_QLen1}),
- %% Add 1 for the current log request
- ?observe(Name,{flushed,_NewFlushed+1}),
+ %% Add 1 for the current log event
+ ?observe(Name,{flushed,NewFlushed+1}),
State1 = ?update_max_time(?diff_time(T1,_T0),State),
- {dropped,?update_other(flushed,FLUSHED,_NewFlushed,
- State1#{mode => ?set_mode(Name,async),
+ {dropped,?update_other(flushed,FLUSHED,NewFlushed,
+ State1#{mode => ?set_mode(ModeTab,async),
last_qlen => 0,
last_log_ts => T1})}.
%% this function is called to write to disk_log
write(Name, Mode, T1, Bin, _CallOrCast,
- State = #{dl_sync := DLSync,
+ State = #{mode_tab := ModeTab,
+ dl_sync := DLSync,
dl_sync_int := DLSyncInt,
last_qlen := LastQLen,
last_log_ts := T0}) ->
%% check if we need to limit the number of writes
- %% during a burst of log requests
+ %% during a burst of log events
{DoWrite,BurstWinT,BurstMsgCount} = logger_h_common:limit_burst(State),
- %% only send a synhrounous request to the disk_log process
+ %% only send a synhrounous event to the disk_log process
%% every DLSyncInt time, to give the handler time between
%% writes so it can keep up with incoming messages
{Status,LastQLen1,State1} =
@@ -583,18 +608,18 @@ write(Name, Mode, T1, Bin, _CallOrCast,
{dropped, LastQLen, State}
end,
- %% Check if the time since the previous log request is long enough -
+ %% Check if the time since the previous log event is long enough -
%% and the queue length small enough - to assume the mailbox has
%% been emptied, and if so, do filesync operation and reset mode to
%% async. Note that this is the best we can do to detect an idle
%% handler without setting a timer after each log call/cast. If the
- %% time between two consecutive log requests is fast and no new
- %% request comes in after the last one, idle state won't be detected!
+ %% time between two consecutive log events is fast and no new
+ %% event comes in after the last one, idle state won't be detected!
Time = ?diff_time(T1,T0),
{Mode1,BurstMsgCount1,State2} =
if (LastQLen1 < ?FILESYNC_OK_QLEN) andalso
(Time > ?IDLE_DETECT_TIME_USEC) ->
- {?change_mode(Name,Mode,async), 0, disk_log_sync(Name,State1)};
+ {?change_mode(ModeTab,Mode,async), 0, disk_log_sync(Name,State1)};
true ->
{Mode, BurstMsgCount,State1}
end,
@@ -612,11 +637,21 @@ write(Name, Mode, T1, Bin, _CallOrCast,
{Status,State4}.
-open_disk_log(Name, LogOpts) ->
- #{file := File,
- max_no_bytes := MaxNoBytes,
- max_no_files := MaxNoFiles,
- type := Type} = LogOpts,
+log_handler_info(Name, Format, Args, State) ->
+ Config =
+ case logger:get_handler_config(Name) of
+ {ok,Conf} -> Conf;
+ _ -> #{formatter=>{?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}}
+ end,
+ Meta = #{time=>erlang:system_time(microsecond)},
+ Bin = logger_h_common:log_to_binary(#{level => notice,
+ msg => {Format,Args},
+ meta => Meta}, Config),
+ _ = disk_log_write(Name, Bin, State),
+ ok.
+
+
+open_disk_log(Name, File, Type, MaxNoBytes, MaxNoFiles) ->
case filelib:ensure_dir(File) of
ok ->
Size =
@@ -649,10 +684,9 @@ close_disk_log(Name, _) ->
ok.
disk_log_write(Name, Bin, State) ->
- Result =
case ?disk_log_blog(Name, Bin) of
ok ->
- ok;
+ State#{prev_log_result => ok, last_op => write};
LogError ->
_ = case maps:get(prev_log_result, State) of
LogError ->
@@ -664,29 +698,26 @@ disk_log_write(Name, Bin, State) ->
LogOpts,
LogError})
end,
- LogError
- end,
- State#{prev_log_result => Result}.
+ State#{prev_log_result => LogError}
+ end.
disk_log_sync(Name, State) ->
- Result =
- case ?disk_log_sync(Name) of
- ok ->
- ok;
- SyncError ->
- _ = case maps:get(prev_sync_result, State) of
- SyncError ->
- %% don't report same error twice
- ok;
- _ ->
- LogOpts = maps:get(log_opts, State),
- logger_h_common:error_notify({Name,sync,
- LogOpts,
- SyncError})
- end,
- SyncError
- end,
- State#{prev_sync_result => Result}.
+ case ?disk_log_sync(Name) of
+ ok ->
+ State#{prev_sync_result => ok, last_op => sync};
+ SyncError ->
+ _ = case maps:get(prev_sync_result, State) of
+ SyncError ->
+ %% don't report same error twice
+ ok;
+ _ ->
+ LogOpts = maps:get(log_opts, State),
+ logger_h_common:error_notify({Name,filesync,
+ LogOpts,
+ SyncError})
+ end,
+ State#{prev_sync_result => SyncError}
+ end.
error_notify_new(Info,Info, _Term) ->
ok;
diff --git a/lib/kernel/src/logger_filters.erl b/lib/kernel/src/logger_filters.erl
index 85928f0fd6..0664c598e1 100644
--- a/lib/kernel/src/logger_filters.erl
+++ b/lib/kernel/src/logger_filters.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,30 +27,31 @@
-include("logger_internal.hrl").
-define(IS_ACTION(A), (A==log orelse A==stop)).
--spec domain(Log,Extra) -> logger:filter_return() when
- Log :: logger:log(),
+-spec domain(LogEvent,Extra) -> logger:filter_return() when
+ LogEvent :: logger:log_event(),
Extra :: {Action,Compare,MatchDomain},
Action :: log | stop,
- Compare :: prefix_of | starts_with | equals | no_domain,
+ Compare :: super | sub | equal | not_equal | undefined,
MatchDomain :: list(atom()).
-domain(#{meta:=Meta}=Log,{Action,Compare,MatchDomain})
+domain(#{meta:=Meta}=LogEvent,{Action,Compare,MatchDomain})
when ?IS_ACTION(Action) andalso
- (Compare==prefix_of orelse
- Compare==starts_with orelse
- Compare==equals orelse
- Compare==no_domain) andalso
+ (Compare==super orelse
+ Compare==sub orelse
+ Compare==equal orelse
+ Compare==not_equal orelse
+ Compare==undefined) andalso
is_list(MatchDomain) ->
- filter_domain(Compare,Meta,MatchDomain,on_match(Action,Log));
-domain(Log,Extra) ->
- erlang:error(badarg,[Log,Extra]).
+ filter_domain(Compare,Meta,MatchDomain,on_match(Action,LogEvent));
+domain(LogEvent,Extra) ->
+ erlang:error(badarg,[LogEvent,Extra]).
--spec level(Log,Extra) -> logger:filter_return() when
- Log :: logger:log(),
+-spec level(LogEvent,Extra) -> logger:filter_return() when
+ LogEvent :: logger:log_event(),
Extra :: {Action,Operator,MatchLevel},
Action :: log | stop,
Operator :: neq | eq | lt | gt | lteq | gteq,
MatchLevel :: logger:level().
-level(#{level:=L1}=Log,{Action,Op,L2})
+level(#{level:=L1}=LogEvent,{Action,Op,L2})
when ?IS_ACTION(Action) andalso
(Op==neq orelse
Op==eq orelse
@@ -59,37 +60,40 @@ level(#{level:=L1}=Log,{Action,Op,L2})
Op==lteq orelse
Op==gteq) andalso
?IS_LEVEL(L2) ->
- filter_level(Op,L1,L2,on_match(Action,Log));
-level(Log,Extra) ->
- erlang:error(badarg,[Log,Extra]).
+ filter_level(Op,L1,L2,on_match(Action,LogEvent));
+level(LogEvent,Extra) ->
+ erlang:error(badarg,[LogEvent,Extra]).
--spec progress(Log,Extra) -> logger:filter_return() when
- Log :: logger:log(),
+-spec progress(LogEvent,Extra) -> logger:filter_return() when
+ LogEvent :: logger:log_event(),
Extra :: log | stop.
-progress(Log,Action) when ?IS_ACTION(Action) ->
- filter_progress(Log,on_match(Action,Log));
-progress(Log,Action) ->
- erlang:error(badarg,[Log,Action]).
+progress(LogEvent,Action) when ?IS_ACTION(Action) ->
+ filter_progress(LogEvent,on_match(Action,LogEvent));
+progress(LogEvent,Action) ->
+ erlang:error(badarg,[LogEvent,Action]).
--spec remote_gl(Log,Extra) -> logger:filter_return() when
- Log :: logger:log(),
+-spec remote_gl(LogEvent,Extra) -> logger:filter_return() when
+ LogEvent :: logger:log_event(),
Extra :: log | stop.
-remote_gl(Log,Action) when ?IS_ACTION(Action) ->
- filter_remote_gl(Log,on_match(Action,Log));
-remote_gl(Log,Action) ->
- erlang:error(badarg,[Log,Action]).
+remote_gl(LogEvent,Action) when ?IS_ACTION(Action) ->
+ filter_remote_gl(LogEvent,on_match(Action,LogEvent));
+remote_gl(LogEvent,Action) ->
+ erlang:error(badarg,[LogEvent,Action]).
%%%-----------------------------------------------------------------
%%% Internal
-filter_domain(prefix_of,#{domain:=Domain},MatchDomain,OnMatch) ->
+filter_domain(super,#{domain:=Domain},MatchDomain,OnMatch) ->
is_prefix(Domain,MatchDomain,OnMatch);
-filter_domain(starts_with,#{domain:=Domain},MatchDomain,OnMatch) ->
+filter_domain(sub,#{domain:=Domain},MatchDomain,OnMatch) ->
is_prefix(MatchDomain,Domain,OnMatch);
-filter_domain(equals,#{domain:=Domain},Domain,OnMatch) ->
+filter_domain(equal,#{domain:=Domain},Domain,OnMatch) ->
OnMatch;
-filter_domain(Action,Meta,_,OnMatch) ->
+filter_domain(not_equal,#{domain:=Domain},MatchDomain,OnMatch)
+ when Domain=/=MatchDomain ->
+ OnMatch;
+filter_domain(Compare,Meta,_,OnMatch) ->
case maps:is_key(domain,Meta) of
- false when Action==no_domain -> OnMatch;
+ false when Compare==undefined; Compare==not_equal -> OnMatch;
_ -> ignore
end.
@@ -119,5 +123,5 @@ filter_remote_gl(#{meta:=#{gl:=GL}},OnMatch) when node(GL)=/=node() ->
filter_remote_gl(_,_) ->
ignore.
-on_match(log,Log) -> Log;
+on_match(log,LogEvent) -> LogEvent;
on_match(stop,_) -> stop.
diff --git a/lib/kernel/src/logger_formatter.erl b/lib/kernel/src/logger_formatter.erl
index 8e954f8d98..b0d4adc14d 100644
--- a/lib/kernel/src/logger_formatter.erl
+++ b/lib/kernel/src/logger_formatter.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -20,25 +20,30 @@
-module(logger_formatter).
-export([format/2]).
+-export([check_config/1]).
-include("logger_internal.hrl").
%%%-----------------------------------------------------------------
%%% Types
--type template() :: [atom()|tuple()|string()].
+-type config() :: #{chars_limit => pos_integer() | unlimited,
+ depth => pos_integer() | unlimited,
+ encoding => unicode:encoding(),
+ legacy_header => boolean(),
+ max_size => pos_integer() | unlimited,
+ report_cb => logger:report_cb(),
+ single_line => boolean(),
+ template => template(),
+ time_designator => byte(),
+ time_offset => integer() | [byte()]}.
+-type template() :: [metakey() | {metakey(),template(),template()} | string()].
+-type metakey() :: atom() | [atom()].
%%%-----------------------------------------------------------------
%%% API
--spec format(Log,Config) -> unicode:chardata() when
- Log :: logger:log(),
- Config :: #{single_line=>boolean(),
- legacy_header=>boolean(),
- report_cb=>fun((logger:report()) -> {io:format(),[term()]}),
- chars_limit=>pos_integer()| unlimited,
- max_size=>pos_integer() | unlimited,
- depth=>pos_integer() | unlimited,
- template=>template(),
- utc=>boolean()}.
+-spec format(LogEvent,Config) -> unicode:chardata() when
+ LogEvent :: logger:log_event(),
+ Config :: config().
format(#{level:=Level,msg:=Msg0,meta:=Meta},Config0)
when is_map(Config0) ->
Config = add_default_config(Config0),
@@ -50,8 +55,8 @@ format(#{level:=Level,msg:=Msg0,meta:=Meta},Config0)
[msg|Rest] -> {true,Rest};
_ ->{false,AT0}
end,
- B = do_format(Level,"",Meta1,BT,Config),
- A = do_format(Level,"",Meta1,AT,Config),
+ B = do_format(Level,Meta1,BT,Config),
+ A = do_format(Level,Meta1,AT,Config),
MsgStr =
if DoMsg ->
Config1 =
@@ -72,7 +77,7 @@ format(#{level:=Level,msg:=Msg0,meta:=Meta},Config0)
%% Trim leading and trailing whitespaces, and replace
%% newlines with ", "
re:replace(string:trim(MsgStr0),",?\r?\n\s*",", ",
- [{return,list},global]);
+ [{return,list},global,unicode]);
_false ->
MsgStr0
end;
@@ -81,105 +86,153 @@ format(#{level:=Level,msg:=Msg0,meta:=Meta},Config0)
end,
truncate(B ++ MsgStr ++ A,maps:get(max_size,Config)).
-do_format(Level,Msg,Data,[level|Format],Config) ->
- [to_string(level,Level,Config)|do_format(Level,Msg,Data,Format,Config)];
-do_format(Level,Msg,Data,[msg|Format],Config) ->
- [Msg|do_format(Level,Msg,Data,Format,Config)];
-do_format(Level,Msg,Data,[Key|Format],Config) when is_atom(Key); is_tuple(Key) ->
- Value = value(Key,Data),
- [to_string(Key,Value,Config)|do_format(Level,Msg,Data,Format,Config)];
-do_format(Level,Msg,Data,[Str|Format],Config) ->
- [Str|do_format(Level,Msg,Data,Format,Config)];
-do_format(_Level,_Msg,_Data,[],_Config) ->
+do_format(Level,Data,[level|Format],Config) ->
+ [to_string(level,Level,Config)|do_format(Level,Data,Format,Config)];
+do_format(Level,Data,[{Key,IfExist,Else}|Format],Config) ->
+ String =
+ case value(Key,Data) of
+ {ok,Value} -> do_format(Level,Data#{Key=>Value},IfExist,Config);
+ error -> do_format(Level,Data,Else,Config)
+ end,
+ [String|do_format(Level,Data,Format,Config)];
+do_format(Level,Data,[Key|Format],Config)
+ when is_atom(Key) orelse
+ (is_list(Key) andalso is_atom(hd(Key))) ->
+ String =
+ case value(Key,Data) of
+ {ok,Value} -> to_string(Key,Value,Config);
+ error -> ""
+ end,
+ [String|do_format(Level,Data,Format,Config)];
+do_format(Level,Data,[Str|Format],Config) ->
+ [Str|do_format(Level,Data,Format,Config)];
+do_format(_Level,_Data,[],_Config) ->
[].
-value(Key,Meta) when is_atom(Key), is_map(Meta) ->
- maps:get(Key,Meta,"");
-value(Key,_) when is_atom(Key) ->
- "";
-value(Keys,Meta) when is_tuple(Keys) ->
- value(tuple_to_list(Keys),Meta);
-value([Key|Keys],Meta) ->
- value(Keys,value(Key,Meta));
+value(Key,Meta) when is_map_key(Key,Meta) ->
+ {ok,maps:get(Key,Meta)};
+value([Key|Keys],Meta) when is_map_key(Key,Meta) ->
+ value(Keys,maps:get(Key,Meta));
value([],Value) ->
- Value.
+ {ok,Value};
+value(_,_) ->
+ error.
to_string(time,Time,Config) ->
format_time(Time,Config);
-to_string(mfa,MFA,_Config) ->
- format_mfa(MFA);
-to_string(_,Value,_Config) ->
- to_string(Value).
+to_string(mfa,MFA,Config) ->
+ format_mfa(MFA,Config);
+to_string(_,Value,Config) ->
+ to_string(Value,Config).
-to_string(X) when is_atom(X) ->
+to_string(X,_) when is_atom(X) ->
atom_to_list(X);
-to_string(X) when is_integer(X) ->
+to_string(X,_) when is_integer(X) ->
integer_to_list(X);
-to_string(X) when is_pid(X) ->
+to_string(X,_) when is_pid(X) ->
pid_to_list(X);
-to_string(X) when is_reference(X) ->
+to_string(X,_) when is_reference(X) ->
ref_to_list(X);
-to_string(X) when is_list(X) ->
- case io_lib:printable_unicode_list(lists:flatten(X)) of
+to_string(X,Config) when is_list(X) ->
+ case printable_list(lists:flatten(X)) of
true -> X;
- _ -> io_lib:format("~tp",[X])
+ _ -> io_lib:format(p(Config),[X])
end;
-to_string(X) ->
- io_lib:format("~tp",[X]).
+to_string(X,Config) ->
+ io_lib:format(p(Config),[X]).
+
+printable_list([]) ->
+ false;
+printable_list(X) ->
+ io_lib:printable_list(X).
format_msg({string,Chardata},Meta,Config) ->
- try unicode:characters_to_list(Chardata)
- catch _:_ -> format_msg({"INVALID STRING: ~tp",[Chardata]},Meta,Config)
- end;
-format_msg({report,_}=Msg,Meta,#{report_cb:=Fun}=Config) when is_function(Fun,1) ->
+ format_msg({s(Config),[Chardata]},Meta,Config);
+format_msg({report,_}=Msg,Meta,#{report_cb:=Fun}=Config)
+ when is_function(Fun,1); is_function(Fun,2) ->
format_msg(Msg,Meta#{report_cb=>Fun},maps:remove(report_cb,Config));
format_msg({report,Report},#{report_cb:=Fun}=Meta,Config) when is_function(Fun,1) ->
try Fun(Report) of
{Format,Args} when is_list(Format), is_list(Args) ->
format_msg({Format,Args},maps:remove(report_cb,Meta),Config);
Other ->
- format_msg({"REPORT_CB ERROR: ~tp; Returned: ~tp",
+ P = p(Config),
+ format_msg({"REPORT_CB/1 ERROR: "++P++"; Returned: "++P,
+ [Report,Other]},Meta,Config)
+ catch C:R:S ->
+ P = p(Config),
+ format_msg({"REPORT_CB/1 CRASH: "++P++"; Reason: "++P,
+ [Report,{C,R,logger:filter_stacktrace(?MODULE,S)}]},
+ Meta,Config)
+ end;
+format_msg({report,Report},#{report_cb:=Fun}=Meta,Config) when is_function(Fun,2) ->
+ try Fun(Report,maps:with([encoding,depth,chars_limit],Config)) of
+ String when ?IS_STRING(String) ->
+ try unicode:characters_to_list(String)
+ catch _:_ ->
+ P = p(Config),
+ format_msg({"REPORT_CB/2 ERROR: "++P++"; Returned: "++P,
+ [Report,String]},Meta,Config)
+ end;
+ Other ->
+ P = p(Config),
+ format_msg({"REPORT_CB/2 ERROR: "++P++"; Returned: "++P,
[Report,Other]},Meta,Config)
- catch C:R ->
- format_msg({"REPORT_CB CRASH: ~tp; Reason: ~tp",
- [Report,{C,R}]},Meta,Config)
+ catch C:R:S ->
+ P = p(Config),
+ format_msg({"REPORT_CB/2 CRASH: "++P++"; Reason: "++P,
+ [Report,{C,R,logger:filter_stacktrace(?MODULE,S)}]},
+ Meta,Config)
end;
format_msg({report,Report},Meta,Config) ->
format_msg({report,Report},
Meta#{report_cb=>fun logger:format_report/1},
Config);
-format_msg(Msg,_Meta,#{depth:=Depth,chars_limit:=CharsLimit}) ->
- limit_size(Msg, Depth, CharsLimit).
-
-limit_size(Msg,Depth,unlimited) ->
- limit_size(Msg,Depth,[]);
-limit_size(Msg,Depth,CharsLimit) when is_integer(CharsLimit) ->
- limit_size(Msg,Depth,[{chars_limit,CharsLimit}]);
-limit_size({Format,Args},unlimited,Opts) when is_list(Opts) ->
- try io_lib:format(Format,Args,Opts)
- catch _:_ ->
- io_lib:format("FORMAT ERROR: ~tp - ~tp",[Format,Args],Opts)
- end;
-limit_size({Format0,Args},Depth,Opts) when is_integer(Depth) ->
+format_msg(Msg,_Meta,#{depth:=Depth,chars_limit:=CharsLimit,
+ encoding:=Enc,single_line:=Single}) ->
+ Opts = chars_limit_to_opts(CharsLimit),
+ format_msg(Msg, Depth, Opts, Enc, Single).
+
+chars_limit_to_opts(unlimited) -> [];
+chars_limit_to_opts(CharsLimit) -> [{chars_limit,CharsLimit}].
+
+format_msg({Format0,Args},Depth,Opts,Enc,Single) ->
try
Format1 = io_lib:scan_format(Format0, Args),
- Format = limit_format(Format1, Depth),
+ Format = reformat(Format1, Depth, Single),
io_lib:build_text(Format,Opts)
- catch _:_ ->
- limit_size({"FORMAT ERROR: ~tp - ~tp",[Format0,Args]},Depth,Opts)
+ catch C:R:S ->
+ P = p(Enc,Single),
+ FormatError = "FORMAT ERROR: "++P++" - "++P,
+ case Format0 of
+ FormatError ->
+ %% already been here - avoid failing cyclically
+ erlang:raise(C,R,S);
+ _ ->
+ format_msg({FormatError,[Format0,Args]},
+ Depth,Opts,Enc,Single)
+ end
end.
-limit_format([#{control_char:=C0}=M0|T], Depth) when C0 =:= $p;
- C0 =:= $w ->
- C = C0 - ($a - $A), %To uppercase.
- #{args:=Args} = M0,
- M = M0#{control_char:=C,args:=Args++[Depth]},
- [M|limit_format(T, Depth)];
-limit_format([H|T], Depth) ->
- [H|limit_format(T, Depth)];
-limit_format([], _) ->
+reformat(Format,unlimited,false) ->
+ Format;
+reformat([#{control_char:=C}=M|T], Depth, true) when C =:= $p ->
+ [limit_depth(M#{width => 0}, Depth)|reformat(T, Depth, true)];
+reformat([#{control_char:=C}=M|T], Depth, true) when C =:= $P ->
+ [M#{width => 0}|reformat(T, Depth, true)];
+reformat([#{control_char:=C}=M|T], Depth, Single) when C =:= $p; C =:= $w ->
+ [limit_depth(M, Depth)|reformat(T, Depth, Single)];
+reformat([H|T], Depth, Single) ->
+ [H|reformat(T, Depth, Single)];
+reformat([], _, _) ->
[].
+limit_depth(M0, unlimited) ->
+ M0;
+limit_depth(#{control_char:=C0, args:=Args}=M0, Depth) ->
+ C = C0 - ($a - $A), %To uppercase.
+ M0#{control_char:=C,args:=Args++[Depth]}.
+
truncate(String,unlimited) ->
String;
truncate(String,Size) ->
@@ -195,53 +248,63 @@ truncate(String,Size) ->
String
end.
-format_time(Timestamp,Config) when is_integer(Timestamp) ->
- {Date,Time,Micro} = timestamp_to_datetimemicro(Timestamp,Config),
- format_time(Date,Time,Micro);
-format_time(Other,_Config) ->
- %% E.g. a string
- to_string(Other).
-
-format_time({Y,M,D},{H,Min,S},Micro) ->
- io_lib:format("~4w-~2..0w-~2..0w ~2w:~2..0w:~2..0w.~6..0w",
- [Y,M,D,H,Min,S,Micro]).
+%% SysTime is the system time in microseconds
+format_time(SysTime,#{time_offset:=Offset,time_designator:=Des})
+ when is_integer(SysTime) ->
+ calendar:system_time_to_rfc3339(SysTime,[{unit,microsecond},
+ {offset,Offset},
+ {time_designator,Des}]).
-%% Assuming this is monotonic time in microseconds
-timestamp_to_datetimemicro(Timestamp,Config) when is_integer(Timestamp) ->
- SysTime = Timestamp + erlang:time_offset(microsecond),
+%% SysTime is the system time in microseconds
+timestamp_to_datetimemicro(SysTime,Config) when is_integer(SysTime) ->
Micro = SysTime rem 1000000,
Sec = SysTime div 1000000,
UniversalTime = erlang:posixtime_to_universaltime(Sec),
- {Date,Time} =
- case Config of
- #{utc:=true} -> UniversalTime;
- _ -> erlang:universaltime_to_localtime(UniversalTime)
+ {{Date,Time},UtcStr} =
+ case offset_to_utc(maps:get(time_offset,Config)) of
+ true -> {UniversalTime,"UTC "};
+ _ -> {erlang:universaltime_to_localtime(UniversalTime),""}
end,
- {Date,Time,Micro}.
+ {Date,Time,Micro,UtcStr}.
-format_mfa({M,F,A}) when is_atom(M), is_atom(F), is_integer(A) ->
+format_mfa({M,F,A},_) when is_atom(M), is_atom(F), is_integer(A) ->
atom_to_list(M)++":"++atom_to_list(F)++"/"++integer_to_list(A);
-format_mfa({M,F,A}) when is_atom(M), is_atom(F), is_list(A) ->
- format_mfa({M,F,length(A)});
-format_mfa(MFA) ->
- to_string(MFA).
+format_mfa({M,F,A},Config) when is_atom(M), is_atom(F), is_list(A) ->
+ format_mfa({M,F,length(A)},Config);
+format_mfa(MFA,Config) ->
+ to_string(MFA,Config).
maybe_add_legacy_header(Level,
#{time:=Timestamp}=Meta,
#{legacy_header:=true}=Config) ->
- #{title:=Title}=MyMeta = add_legacy_title(Level,maps:get(?MODULE,Meta,#{})),
- {{Y,Mo,D},{H,Mi,S},Micro} = timestamp_to_datetimemicro(Timestamp,Config),
- Header = io_lib:format("=~ts==== ~w-~s-~4w::~2..0w:~2..0w:~2..0w.~6..0w ~s===",
- [Title,D,month(Mo),Y,H,Mi,S,Micro,utcstr(Config)]),
+ #{title:=Title}=MyMeta = add_legacy_title(Level,Meta,Config),
+ {{Y,Mo,D},{H,Mi,Sec},Micro,UtcStr} =
+ timestamp_to_datetimemicro(Timestamp,Config),
+ S = s(Config),
+ Header =
+ io_lib:format("="++S++"==== ~w-~s-~4w::~2..0w:~2..0w:~2..0w.~6..0w ~s===",
+ [Title,D,month(Mo),Y,H,Mi,Sec,Micro,UtcStr]),
Meta#{?MODULE=>MyMeta#{header=>Header}};
maybe_add_legacy_header(_,Meta,_) ->
Meta.
-add_legacy_title(_Level,#{title:=_}=MyMeta) ->
+add_legacy_title(_Level,#{?MODULE:=#{title:=_}=MyMeta},_) ->
MyMeta;
-add_legacy_title(Level,MyMeta) ->
- Title = string:uppercase(atom_to_list(Level)) ++ " REPORT",
- MyMeta#{title=>Title}.
+add_legacy_title(Level,Meta,Config) ->
+ case maps:get(?MODULE,Meta,#{}) of
+ #{title:=_}=MyMeta ->
+ MyMeta;
+ MyMeta ->
+ TitleLevel =
+ case (Level=:=notice andalso maps:find(error_logger,Meta)) of
+ {ok,_} ->
+ maps:get(error_logger_notice_header,Config);
+ _ ->
+ Level
+ end,
+ Title = string:uppercase(atom_to_list(TitleLevel)) ++ " REPORT",
+ MyMeta#{title=>Title}
+ end.
month(1) -> "Jan";
month(2) -> "Feb";
@@ -256,20 +319,22 @@ month(10) -> "Oct";
month(11) -> "Nov";
month(12) -> "Dec".
-utcstr(#{utc:=true}) -> "UTC ";
-utcstr(_) -> "".
-
-add_default_config(#{utc:=_}=Config0) ->
+%% Ensure that all valid configuration parameters exist in the final
+%% configuration map
+add_default_config(Config0) ->
Default =
- #{legacy_header=>false,
+ #{chars_limit=>unlimited,
+ encoding=>utf8,
+ error_logger_notice_header=>info,
+ legacy_header=>false,
single_line=>true,
- chars_limit=>unlimited},
- MaxSize = get_max_size(maps:get(max_size,Config0,false)),
- Depth = get_depth(maps:get(depth,Config0,false)),
+ time_designator=>$T},
+ MaxSize = get_max_size(maps:get(max_size,Config0,undefined)),
+ Depth = get_depth(maps:get(depth,Config0,undefined)),
+ Offset = get_offset(maps:get(time_offset,Config0,undefined)),
add_default_template(maps:merge(Default,Config0#{max_size=>MaxSize,
- depth=>Depth}));
-add_default_config(Config) ->
- add_default_config(Config#{utc=>logger:get_utc_config()}).
+ depth=>Depth,
+ time_offset=>Offset})).
add_default_template(#{template:=_}=Config) ->
Config;
@@ -283,12 +348,179 @@ default_template(#{single_line:=true}) ->
default_template(_) ->
?DEFAULT_FORMAT_TEMPLATE.
-get_max_size(false) ->
- logger:get_max_size();
+get_max_size(undefined) ->
+ unlimited;
get_max_size(S) ->
max(10,S).
-get_depth(false) ->
- logger:get_format_depth();
+get_depth(undefined) ->
+ error_logger:get_format_depth();
get_depth(S) ->
max(5,S).
+
+get_offset(undefined) ->
+ utc_to_offset(get_utc_config());
+get_offset(Offset) ->
+ Offset.
+
+utc_to_offset(true) ->
+ "Z";
+utc_to_offset(false) ->
+ "".
+
+get_utc_config() ->
+ %% SASL utc_log overrides stdlib config - in order to have uniform
+ %% timestamps in log messages
+ case application:get_env(sasl, utc_log) of
+ {ok, Val} when is_boolean(Val) -> Val;
+ _ ->
+ case application:get_env(stdlib, utc_log) of
+ {ok, Val} when is_boolean(Val) -> Val;
+ _ -> false
+ end
+ end.
+
+offset_to_utc(Z) when Z=:=0; Z=:="z"; Z=:="Z" ->
+ true;
+offset_to_utc([$+|Tz]) ->
+ case io_lib:fread("~d:~d", Tz) of
+ {ok, [0, 0], []} ->
+ true;
+ _ ->
+ false
+ end;
+offset_to_utc(_) ->
+ false.
+
+-spec check_config(Config) -> ok | {error,term()} when
+ Config :: config().
+check_config(Config) when is_map(Config) ->
+ do_check_config(maps:to_list(Config));
+check_config(Config) ->
+ {error,{invalid_formatter_config,?MODULE,Config}}.
+
+do_check_config([{Type,L}|Config]) when Type == chars_limit;
+ Type == depth;
+ Type == max_size ->
+ case check_limit(L) of
+ ok -> do_check_config(Config);
+ error -> {error,{invalid_formatter_config,?MODULE,{Type,L}}}
+ end;
+do_check_config([{single_line,SL}|Config]) when is_boolean(SL) ->
+ do_check_config(Config);
+do_check_config([{legacy_header,LH}|Config]) when is_boolean(LH) ->
+ do_check_config(Config);
+do_check_config([{error_logger_notice_header,ELNH}|Config]) when ELNH == info;
+ ELNH == notice ->
+ do_check_config(Config);
+do_check_config([{report_cb,RCB}|Config]) when is_function(RCB,1);
+ is_function(RCB,2) ->
+ do_check_config(Config);
+do_check_config([{template,T}|Config]) ->
+ case check_template(T) of
+ ok -> do_check_config(Config);
+ error -> {error,{invalid_formatter_template,?MODULE,T}}
+ end;
+do_check_config([{time_offset,Offset}|Config]) ->
+ case check_offset(Offset) of
+ ok ->
+ do_check_config(Config);
+ error ->
+ {error,{invalid_formatter_config,?MODULE,{time_offset,Offset}}}
+ end;
+do_check_config([{time_designator,Char}|Config]) when Char>=0, Char=<255 ->
+ case io_lib:printable_latin1_list([Char]) of
+ true ->
+ do_check_config(Config);
+ false ->
+ {error,{invalid_formatter_config,?MODULE,{time_designator,Char}}}
+ end;
+do_check_config([C|_]) ->
+ {error,{invalid_formatter_config,?MODULE,C}};
+do_check_config([]) ->
+ ok.
+
+check_limit(L) when is_integer(L), L>0 ->
+ ok;
+check_limit(unlimited) ->
+ ok;
+check_limit(_) ->
+ error.
+
+check_template([Key|T]) when is_atom(Key) ->
+ check_template(T);
+check_template([Key|T]) when is_list(Key), is_atom(hd(Key)) ->
+ case lists:all(fun(X) when is_atom(X) -> true;
+ (_) -> false
+ end,
+ Key) of
+ true ->
+ check_template(T);
+ false ->
+ error
+ end;
+check_template([{Key,IfExist,Else}|T])
+ when is_atom(Key) orelse
+ (is_list(Key) andalso is_atom(hd(Key))) ->
+ case check_template(IfExist) of
+ ok ->
+ case check_template(Else) of
+ ok ->
+ check_template(T);
+ error ->
+ error
+ end;
+ error ->
+ error
+ end;
+check_template([Str|T]) when is_list(Str) ->
+ case io_lib:printable_unicode_list(Str) of
+ true -> check_template(T);
+ false -> error
+ end;
+check_template([]) ->
+ ok;
+check_template(_) ->
+ error.
+
+check_offset(I) when is_integer(I) ->
+ ok;
+check_offset(Tz) when Tz=:=""; Tz=:="Z"; Tz=:="z" ->
+ ok;
+check_offset([Sign|Tz]) when Sign=:=$+; Sign=:=$- ->
+ check_timezone(Tz);
+check_offset(_) ->
+ error.
+
+check_timezone(Tz) ->
+ try io_lib:fread("~d:~d", Tz) of
+ {ok, [_, _], []} ->
+ ok;
+ _ ->
+ error
+ catch _:_ ->
+ error
+ end.
+
+p(#{encoding:=Enc, single_line:=Single}) ->
+ p(Enc,Single).
+
+p(Enc,Single) ->
+ "~"++p_width(Single)++p_char(Enc).
+
+p_width(true) ->
+ "0";
+p_width(false) ->
+ "".
+
+p_char(latin1) ->
+ "p";
+p_char(_) ->
+ "tp".
+
+s(#{encoding:=Enc}) ->
+ s(Enc);
+s(latin1) ->
+ "~s";
+s(_) ->
+ "~ts".
diff --git a/lib/kernel/src/logger_h_common.erl b/lib/kernel/src/logger_h_common.erl
index 7caad366ae..854e5479b9 100644
--- a/lib/kernel/src/logger_h_common.erl
+++ b/lib/kernel/src/logger_h_common.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,13 +24,15 @@
-export([log_to_binary/2,
check_common_config/1,
- call_cast_or_drop/2,
+ call_cast_or_drop/4,
check_load/1,
limit_burst/1,
- kill_if_choked/4,
- flush_log_requests/0,
- flush_log_requests/1,
+ kill_if_choked/5,
+ flush_log_events/0,
+ flush_log_events/1,
handler_exit/2,
+ set_restart_flag/2,
+ unset_restart_flag/2,
cancel_timer/1,
stop_or_restart/3,
overload_levels_ok/1,
@@ -39,9 +41,9 @@
%%%-----------------------------------------------------------------
%%% Covert log data on any form to binary
--spec log_to_binary(Log,Config) -> LogString when
- Log :: logger:log(),
- Config :: logger:config(),
+-spec log_to_binary(LogEvent,Config) -> LogString when
+ LogEvent :: logger:log_event(),
+ Config :: logger:handler_config(),
LogString :: binary().
log_to_binary(#{msg:={report,_},meta:=#{report_cb:=_}}=Log,Config) ->
do_log_to_binary(Log,Config);
@@ -52,13 +54,14 @@ log_to_binary(Log,Config) ->
do_log_to_binary(Log,Config).
do_log_to_binary(Log,Config) ->
- {Formatter,FormatterConfig} = maps:get(formatter,Config),
+ {Formatter,FormatterConfig} =
+ maps:get(formatter,Config,{?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}),
String = try_format(Log,Formatter,FormatterConfig),
try unicode:characters_to_binary(String)
catch _:_ ->
?LOG_INTERNAL(debug,[{formatter_error,Formatter},
{config,FormatterConfig},
- {log,Log},
+ {log_event,Log},
{bad_return_value,String}]),
<<"FORMATTER ERROR: bad_return_value">>
end.
@@ -69,10 +72,10 @@ try_format(Log,Formatter,FormatterConfig) ->
C:R:S ->
?LOG_INTERNAL(debug,[{formatter_crashed,Formatter},
{config,FormatterConfig},
- {log,Log},
+ {log_event,Log},
{reason,
{C,R,logger:filter_stacktrace(?MODULE,S)}}]),
- case {?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG} of
+ case {?DEFAULT_FORMATTER,#{}} of
{Formatter,FormatterConfig} ->
"DEFAULT FORMATTER CRASHED";
{DefaultFormatter,DefaultConfig} ->
@@ -84,29 +87,37 @@ try_format(Log,Formatter,FormatterConfig) ->
%%%-----------------------------------------------------------------
%%% Check that the configuration term is valid
-check_common_config({toggle_sync_qlen,N}) when is_integer(N) ->
+check_common_config({mode_tab,_Tid}) ->
valid;
-check_common_config({drop_new_reqs_qlen,N}) when is_integer(N) ->
+check_common_config({handler_pid,Pid}) when is_pid(Pid) ->
valid;
-check_common_config({flush_reqs_qlen,N}) when is_integer(N) ->
+
+check_common_config({sync_mode_qlen,N}) when is_integer(N) ->
+ valid;
+check_common_config({drop_mode_qlen,N}) when is_integer(N) ->
valid;
-check_common_config({enable_burst_limit,Bool}) when Bool == true;
+check_common_config({flush_qlen,N}) when is_integer(N) ->
+ valid;
+
+check_common_config({burst_limit_enable,Bool}) when Bool == true;
Bool == false ->
valid;
-check_common_config({burst_limit_size,N}) when is_integer(N) ->
+check_common_config({burst_limit_max_count,N}) when is_integer(N) ->
valid;
-check_common_config({burst_window_time,N}) when is_integer(N) ->
+check_common_config({burst_limit_window_time,N}) when is_integer(N) ->
valid;
-check_common_config({enable_kill_overloaded,Bool}) when Bool == true;
- Bool == false ->
+
+check_common_config({overload_kill_enable,Bool}) when Bool == true;
+ Bool == false ->
valid;
-check_common_config({handler_overloaded_qlen,N}) when is_integer(N) ->
+check_common_config({overload_kill_qlen,N}) when is_integer(N) ->
valid;
-check_common_config({handler_overloaded_mem,N}) when is_integer(N) ->
+check_common_config({overload_kill_mem_size,N}) when is_integer(N) ->
valid;
-check_common_config({handler_restart_after,NorA}) when is_integer(NorA);
- NorA == never ->
+check_common_config({overload_kill_restart_after,NorA}) when is_integer(NorA);
+ NorA == infinity ->
valid;
+
check_common_config({filesync_repeat_interval,NorA}) when is_integer(NorA);
NorA == no_repeat ->
valid;
@@ -116,16 +127,16 @@ check_common_config(_) ->
%%%-----------------------------------------------------------------
%%% Overload Protection
-call_cast_or_drop(Name, Bin) ->
- %% If the handler process is getting overloaded, the log request
+call_cast_or_drop(_Name, HandlerPid, ModeTab, Bin) ->
+ %% If the handler process is getting overloaded, the log event
%% will be synchronous instead of asynchronous (slows down the
%% logging tempo of a process doing lots of logging. If the
- %% handler is choked, drop mode is set and no request will be sent.
- try ?get_mode(Name) of
+ %% handler is choked, drop mode is set and no event will be sent.
+ try ?get_mode(ModeTab) of
async ->
- gen_server:cast(Name, {log,Bin});
+ gen_server:cast(HandlerPid, {log,Bin});
sync ->
- try gen_server:call(Name, {log,Bin}, ?DEFAULT_CALL_TIMEOUT) of
+ try gen_server:call(HandlerPid, {log,Bin}, ?DEFAULT_CALL_TIMEOUT) of
%% if return value from call == dropped, the
%% message has been flushed by handler and should
%% therefore not be counted as dropped in stats
@@ -133,62 +144,84 @@ call_cast_or_drop(Name, Bin) ->
dropped -> ok
catch
_:{timeout,_} ->
- ?observe(Name,{dropped,1})
+ ?observe(_Name,{dropped,1})
end;
- drop -> ?observe(Name,{dropped,1})
+ drop ->
+ ?observe(_Name,{dropped,1})
catch
%% if the ETS table doesn't exist (maybe because of a
- %% handler restart), we can only drop the request
- _:_ -> ?observe(Name,{dropped,1})
+ %% handler restart), we can only drop the event
+ _:_ -> ?observe(_Name,{dropped,1})
end,
ok.
handler_exit(_Name, Reason) ->
exit(Reason).
-check_load(State = #{id:=Name, mode := Mode,
- toggle_sync_qlen := ToggleSyncQLen,
- drop_new_reqs_qlen := DropNewQLen,
- flush_reqs_qlen := FlushQLen}) ->
+set_restart_flag(Name, Module) ->
+ Flag = list_to_atom(lists:concat([Module,"_",Name,"_restarting"])),
+ spawn(fun() ->
+ register(Flag, self()),
+ timer:sleep(infinity)
+ end),
+ ok.
+
+unset_restart_flag(Name, Module) ->
+ Flag = list_to_atom(lists:concat([Module,"_",Name,"_restarting"])),
+ case whereis(Flag) of
+ undefined ->
+ false;
+ Pid ->
+ exit(Pid, kill),
+ true
+ end.
+
+check_load(State = #{id:=_Name, mode_tab := ModeTab, mode := Mode,
+ sync_mode_qlen := SyncModeQLen,
+ drop_mode_qlen := DropModeQLen,
+ flush_qlen := FlushQLen}) ->
{_,Mem} = process_info(self(), memory),
- ?observe(Name,{max_mem,Mem}),
- %% make sure the handler process doesn't get scheduled
- %% out between the message_queue_len check below and the
- %% action that follows (flush or write).
+ ?observe(_Name,{max_mem,Mem}),
{_,QLen} = process_info(self(), message_queue_len),
- ?observe(Name,{max_qlen,QLen}),
-
+ ?observe(_Name,{max_qlen,QLen}),
+ %% When the handler process gets scheduled in, it's impossible
+ %% to predict the QLen. We could jump "up" arbitrarily from say
+ %% async to sync, async to drop, sync to flush, etc. However, when
+ %% the handler process manages the log events (without flushing),
+ %% one after the other, we will move "down" from drop to sync and
+ %% from sync to async. This way we don't risk getting stuck in
+ %% drop or sync mode with an empty mailbox.
{Mode1,_NewDrops,_NewFlushes} =
if
QLen >= FlushQLen ->
{flush, 0,1};
- QLen >= DropNewQLen ->
- %% Note that drop mode will force log requests to
+ QLen >= DropModeQLen ->
+ %% Note that drop mode will force log events to
%% be dropped on the client side (never sent get to
%% the handler).
IncDrops = if Mode == drop -> 0; true -> 1 end,
- {?change_mode(Name, Mode, drop), IncDrops,0};
- QLen >= ToggleSyncQLen ->
- {?change_mode(Name, Mode, sync), 0,0};
+ {?change_mode(ModeTab, Mode, drop), IncDrops,0};
+ QLen >= SyncModeQLen ->
+ {?change_mode(ModeTab, Mode, sync), 0,0};
true ->
- {?change_mode(Name, Mode, async), 0,0}
+ {?change_mode(ModeTab, Mode, async), 0,0}
end,
State1 = ?update_other(drops,DROPS,_NewDrops,State),
{Mode1, QLen, Mem,
?update_other(flushes,FLUSHES,_NewFlushes,
State1#{last_qlen => QLen})}.
-limit_burst(#{enable_burst_limit := false}) ->
+limit_burst(#{burst_limit_enable := false}) ->
{true,0,0};
limit_burst(#{burst_win_ts := BurstWinT0,
burst_msg_count := BurstMsgCount,
- burst_window_time := BurstWinTime,
- burst_limit_size := BurstLimitSz}) ->
- if (BurstMsgCount >= BurstLimitSz) ->
+ burst_limit_window_time := BurstLimitWinTime,
+ burst_limit_max_count := BurstLimitMaxCnt}) ->
+ if (BurstMsgCount >= BurstLimitMaxCnt) ->
%% the limit for allowed messages has been reached
BurstWinT1 = ?timestamp(),
case ?diff_time(BurstWinT1,BurstWinT0) of
- BurstCheckTime when BurstCheckTime < (BurstWinTime*1000) ->
+ BurstCheckTime when BurstCheckTime < (BurstLimitWinTime*1000) ->
%% we're still within the burst time frame
{false,BurstWinT0,BurstMsgCount};
_BurstCheckTime ->
@@ -200,38 +233,42 @@ limit_burst(#{burst_win_ts := BurstWinT0,
{true,BurstWinT0,BurstMsgCount+1}
end.
-kill_if_choked(Name, QLen, Mem,
- #{enable_kill_overloaded := KillIfOL,
- handler_overloaded_qlen := HOLQLen,
- handler_overloaded_mem := HOLMem}) ->
+kill_if_choked(Name, QLen, Mem, HandlerMod,
+ State = #{overload_kill_enable := KillIfOL,
+ overload_kill_qlen := OLKillQLen,
+ overload_kill_mem_size := OLKillMem}) ->
if KillIfOL andalso
- ((QLen > HOLQLen) orelse (Mem > HOLMem)) ->
+ ((QLen > OLKillQLen) orelse (Mem > OLKillMem)) ->
+ HandlerMod:log_handler_info(Name,
+ "Handler ~p overloaded and stopping",
+ [Name], State),
+ set_restart_flag(Name, HandlerMod),
handler_exit(Name, {shutdown,{overloaded,Name,QLen,Mem}});
true ->
ok
end.
-flush_log_requests() ->
- flush_log_requests(-1).
+flush_log_events() ->
+ flush_log_events(-1).
-flush_log_requests(Limit) ->
+flush_log_events(Limit) ->
process_flag(priority, high),
- Flushed = flush_log_requests(0, Limit),
+ Flushed = flush_log_events(0, Limit),
process_flag(priority, normal),
Flushed.
-flush_log_requests(Limit, Limit) ->
+flush_log_events(Limit, Limit) ->
Limit;
-flush_log_requests(N, Limit) ->
- %% flush log requests but leave other requests, such as
- %% file/disk_log_sync, info and change_config, so that these
+flush_log_events(N, Limit) ->
+ %% flush log events but leave other events, such as
+ %% filesync, info and change_config, so that these
%% have a chance to be processed even under heavy load
receive
{'$gen_cast',{log,_}} ->
- flush_log_requests(N+1, Limit);
+ flush_log_events(N+1, Limit);
{'$gen_call',{Pid,MRef},{log,_}} ->
Pid ! {MRef, dropped},
- flush_log_requests(N+1, Limit)
+ flush_log_events(N+1, Limit)
after
0 -> N
end.
@@ -241,7 +278,7 @@ cancel_timer(TRef) -> timer:cancel(TRef).
stop_or_restart(Name, {shutdown,Reason={overloaded,_Name,_QLen,_Mem}},
- #{handler_restart_after := RestartAfter}) ->
+ #{overload_kill_restart_after := RestartAfter}) ->
%% If we're terminating because of an overload situation (see
%% logger_h_common:kill_if_choked/4), we need to remove the handler
%% and set a restart timer. A separate process must perform this
@@ -258,7 +295,7 @@ stop_or_restart(Name, {shutdown,Reason={overloaded,_Name,_QLen,_Mem}},
exit(HandlerPid, kill)
end,
case logger:get_handler_config(Name) of
- {ok,{HMod,HConfig}} when is_integer(RestartAfter) ->
+ {ok,#{module:=HMod}=HConfig} when is_integer(RestartAfter) ->
_ = logger:remove_handler(Name),
_ = timer:apply_after(RestartAfter, logger, add_handler,
[Name,HMod,HConfig]);
@@ -272,27 +309,14 @@ stop_or_restart(Name, {shutdown,Reason={overloaded,_Name,_QLen,_Mem}},
end,
spawn(RemoveAndRestart),
ok;
-
-stop_or_restart(Name, shutdown, _State) ->
- %% Probably terminated by supervisor. Remove the handler to avoid
- %% error printouts due to failing handler.
- _ = case logger:get_handler_config(Name) of
- {ok,_} ->
- %% Spawning to avoid deadlock
- spawn(logger,remove_handler,[Name]);
- _ ->
- ok
- end,
- ok;
-
stop_or_restart(_Name, _Reason, _State) ->
ok.
overload_levels_ok(HandlerConfig) ->
- TSQL = maps:get(toggle_sync_qlen, HandlerConfig, ?TOGGLE_SYNC_QLEN),
- DNRQL = maps:get(drop_new_reqs_qlen, HandlerConfig, ?DROP_NEW_REQS_QLEN),
- FRQL = maps:get(flush_reqs_qlen, HandlerConfig, ?FLUSH_REQS_QLEN),
- (TSQL < DNRQL) andalso (DNRQL < FRQL).
+ SMQL = maps:get(sync_mode_qlen, HandlerConfig, ?SYNC_MODE_QLEN),
+ DMQL = maps:get(drop_mode_qlen, HandlerConfig, ?DROP_MODE_QLEN),
+ FQL = maps:get(flush_qlen, HandlerConfig, ?FLUSH_QLEN),
+ (DMQL > 1) andalso (SMQL =< DMQL) andalso (DMQL =< FQL).
error_notify(Term) ->
?internal_log(error, Term).
diff --git a/lib/kernel/src/logger_h_common.hrl b/lib/kernel/src/logger_h_common.hrl
index 89378dbb10..e0a7b6e3ca 100644
--- a/lib/kernel/src/logger_h_common.hrl
+++ b/lib/kernel/src/logger_h_common.hrl
@@ -4,47 +4,47 @@
%%! *** NOTE ***
%%! It's important that:
-%%! TOGGLE_SYNC_QLEN < DROP_NEW_REQS_QLEN < FLUSH_REQS_QLEN
-%%! and that DROP_NEW_REQS_QLEN >= 2.
+%%! SYNC_MODE_QLEN =< DROP_MODE_QLEN =< FLUSH_QLEN
+%%! and that DROP_MODE_QLEN >= 2.
%%! Otherwise the handler could end up in drop mode with no new
%%! log requests to process. This would cause all future requests
%%! to be dropped (no switch to async mode would ever take place).
%% This specifies the message_queue_len value where the log
%% requests switch from asynchronous casts to synchronous calls.
--define(TOGGLE_SYNC_QLEN, 10).
+-define(SYNC_MODE_QLEN, 10).
%% Above this message_queue_len, log requests will be dropped,
%% i.e. no log requests get sent to the handler process.
--define(DROP_NEW_REQS_QLEN, 200).
+-define(DROP_MODE_QLEN, 200).
%% Above this message_queue_len, the handler process will flush
%% its mailbox and only leave this number of messages in it.
--define(FLUSH_REQS_QLEN, 1000).
+-define(FLUSH_QLEN, 1000).
%% Never flush more than this number of messages in one go,
%% or the handler will be unresponsive for seconds (keep this
%% number as large as possible or the mailbox could grow large).
-define(FLUSH_MAX_N, 5000).
-%% BURST_LIMIT is the max number of log requests allowed to be
-%% written within a BURST_WINDOW_TIME time frame.
--define(ENABLE_BURST_LIMIT, true).
--define(BURST_LIMIT_SIZE, 500).
--define(BURST_WINDOW_TIME, 1000).
+%% BURST_LIMIT_MAX_COUNT is the max number of log requests allowed
+%% to be written within a BURST_LIMIT_WINDOW_TIME time frame.
+-define(BURST_LIMIT_ENABLE, true).
+-define(BURST_LIMIT_MAX_COUNT, 500).
+-define(BURST_LIMIT_WINDOW_TIME, 1000).
%% This enables/disables the feature to automatically get the
%% handler terminated if it gets too loaded (and can't keep up).
--define(ENABLE_KILL_OVERLOADED, false).
+-define(OVERLOAD_KILL_ENABLE, false).
%% If the message_queue_len goes above this size even after
%% flushing has been performed, the handler is terminated.
--define(HANDLER_OVERLOADED_QLEN, 20000).
+-define(OVERLOAD_KILL_QLEN, 20000).
%% If the memory usage exceeds this level
--define(HANDLER_OVERLOADED_MEM, 3000000).
+-define(OVERLOAD_KILL_MEM_SIZE, 3000000).
%% This is the default time that the handler will wait before
-%% restarting and accepting new requests. The value 'never'
+%% restarting and accepting new requests. The value 'infinity'
%% disables restarts.
--define(HANDLER_RESTART_AFTER, 5000).
-%%-define(HANDLER_RESTART_AFTER, never).
+-define(OVERLOAD_KILL_RESTART_AFTER, 5000).
+%%-define(OVERLOAD_KILL_RESTART_AFTER, infinity).
%% The handler sends asynchronous write requests to the process
%% controlling the i/o device, but every once in this interval
@@ -77,29 +77,30 @@
-define(DISK_LOG_MAX_NO_BYTES, 1048576).
%%%-----------------------------------------------------------------
+%%% Utility macros
+
+-define(name_to_reg_name(MODULE,Name),
+ list_to_atom(lists:concat([MODULE,"_",Name]))).
+
+%%%-----------------------------------------------------------------
%%% Overload protection macros
-define(timestamp(), erlang:monotonic_time(microsecond)).
--define(get_mode(HandlerName),
- case ets:lookup(HandlerName, mode) of
- [{mode,sync}] ->
- case whereis(HandlerName)==self() of
- true -> async;
- _ -> sync
- end;
+-define(get_mode(Tid),
+ case ets:lookup(Tid, mode) of
[{mode,M}] -> M;
_ -> async
end).
--define(set_mode(HandlerName, M),
- begin ets:insert(HandlerName, {mode,M}), M end).
+-define(set_mode(Tid, M),
+ begin ets:insert(Tid, {mode,M}), M end).
--define(change_mode(HandlerName, M0, M1),
+-define(change_mode(Tid, M0, M1),
if M0 == M1 ->
M0;
true ->
- ets:insert(HandlerName, {mode,M1}),
+ ets:insert(Tid, {mode,M1}),
M1
end).
@@ -124,7 +125,7 @@
%%% slow down execution and therefore should not be include in code
%%% to be officially released.
-%% -define(TEST_HOOKS, true).
+%%-define(TEST_HOOKS, true).
-ifdef(TEST_HOOKS).
-define(TEST_HOOKS_TAB, logger_h_test_hooks).
diff --git a/lib/kernel/src/logger_handler_watcher.erl b/lib/kernel/src/logger_handler_watcher.erl
new file mode 100644
index 0000000000..b75c74c643
--- /dev/null
+++ b/lib/kernel/src/logger_handler_watcher.erl
@@ -0,0 +1,113 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% 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(logger_handler_watcher).
+
+-behaviour(gen_server).
+
+%% API
+-export([start_link/0]).
+-export([register_handler/2]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2]).
+
+-define(SERVER, ?MODULE).
+
+-record(state, {handlers}).
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+
+-spec start_link() -> {ok, Pid :: pid()} |
+ {error, Error :: {already_started, pid()}} |
+ {error, Error :: term()} |
+ ignore.
+start_link() ->
+ gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
+
+-spec register_handler(Id::logger:handler_id(),Pid::pid()) -> ok.
+register_handler(Id,Pid) ->
+ gen_server:call(?SERVER,{register,Id,Pid}).
+
+%%%===================================================================
+%%% gen_server callbacks
+%%%===================================================================
+
+-spec init(Args :: term()) -> {ok, State :: term()} |
+ {ok, State :: term(), Timeout :: timeout()} |
+ {ok, State :: term(), hibernate} |
+ {stop, Reason :: term()} |
+ ignore.
+init([]) ->
+ process_flag(trap_exit, true),
+ {ok, #state{handlers=[]}}.
+
+-spec handle_call(Request :: term(), From :: {pid(), term()}, State :: term()) ->
+ {reply, Reply :: term(), NewState :: term()} |
+ {reply, Reply :: term(), NewState :: term(), Timeout :: timeout()} |
+ {reply, Reply :: term(), NewState :: term(), hibernate} |
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), Timeout :: timeout()} |
+ {noreply, NewState :: term(), hibernate} |
+ {stop, Reason :: term(), Reply :: term(), NewState :: term()} |
+ {stop, Reason :: term(), NewState :: term()}.
+handle_call({register,Id,Pid}, _From, #state{handlers=Hs}=State) ->
+ Ref = erlang:monitor(process,Pid),
+ Hs1 = lists:keystore(Id,1,Hs,{Id,Ref}),
+ {reply, ok, State#state{handlers=Hs1}}.
+
+-spec handle_cast(Request :: term(), State :: term()) ->
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), Timeout :: timeout()} |
+ {noreply, NewState :: term(), hibernate} |
+ {stop, Reason :: term(), NewState :: term()}.
+handle_cast(_Request, State) ->
+ {noreply, State}.
+
+-spec handle_info(Info :: timeout() | term(), State :: term()) ->
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), Timeout :: timeout()} |
+ {noreply, NewState :: term(), hibernate} |
+ {stop, Reason :: normal | term(), NewState :: term()}.
+handle_info({'DOWN',Ref,process,_,shutdown}, #state{handlers=Hs}=State) ->
+ case lists:keytake(Ref,2,Hs) of
+ {value,{Id,Ref},Hs1} ->
+ %% Probably terminated by supervisor. Remove the handler to avoid
+ %% error printouts due to failing handler.
+ _ = case logger:get_handler_config(Id) of
+ {ok,_} ->
+ logger:remove_handler(Id);
+ _ ->
+ ok
+ end,
+ {noreply,State#state{handlers=Hs1}};
+ false ->
+ {noreply, State}
+ end;
+handle_info({'DOWN',Ref,process,_,_OtherReason}, #state{handlers=Hs}=State) ->
+ {noreply,State#state{handlers=lists:keydelete(Ref,2,Hs)}};
+handle_info(_Other,State) ->
+ {noreply,State}.
+
+-spec terminate(Reason :: normal | shutdown | {shutdown, term()} | term(),
+ State :: term()) -> any().
+terminate(_Reason, _State) ->
+ ok.
diff --git a/lib/kernel/src/logger_internal.hrl b/lib/kernel/src/logger_internal.hrl
index 8c0fc2725d..d96a4ac78b 100644
--- a/lib/kernel/src/logger_internal.hrl
+++ b/lib/kernel/src/logger_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,22 +19,20 @@
%%
-include_lib("kernel/include/logger.hrl").
-define(LOGGER_TABLE,logger).
--define(LOGGER_KEY,'$logger_config$').
+-define(PRIMARY_KEY,'$primary_config$').
-define(HANDLER_KEY,'$handler_config$').
-define(LOGGER_META_KEY,'$logger_metadata$').
--define(STANDARD_HANDLER, logger_std_h).
--define(DEFAULT_HANDLER_FILTERS,
- ?DEFAULT_HANDLER_FILTERS([beam,erlang,otp])).
+-define(STANDARD_HANDLER, default).
+-define(DEFAULT_HANDLER_FILTERS,?DEFAULT_HANDLER_FILTERS([otp])).
-define(DEFAULT_HANDLER_FILTERS(Domain),
[{remote_gl,{fun logger_filters:remote_gl/2,stop}},
- {domain,{fun logger_filters:domain/2,{log,prefix_of,Domain}}},
- {no_domain,{fun logger_filters:domain/2,{log,no_domain,[]}}}]).
+ {domain,{fun logger_filters:domain/2,{log,super,Domain}}},
+ {no_domain,{fun logger_filters:domain/2,{log,undefined,[]}}}]).
-define(DEFAULT_FORMATTER,logger_formatter).
-define(DEFAULT_FORMAT_CONFIG,#{legacy_header=>true,
- single_line=>false,
- template=>?DEFAULT_FORMAT_TEMPLATE_HEADER}).
+ single_line=>false}).
-define(DEFAULT_FORMAT_TEMPLATE_HEADER,
- [{logger_formatter,header},"\n",msg,"\n"]).
+ [[logger_formatter,header],"\n",msg,"\n"]).
-define(DEFAULT_FORMAT_TEMPLATE_SINGLE,
[time," ",level,": ",msg,"\n"]).
-define(DEFAULT_FORMAT_TEMPLATE,
@@ -56,14 +54,17 @@
%%%-----------------------------------------------------------------
%%% Levels
%%% Using same as syslog
--define(LEVELS,[emergency,
+-define(LEVELS,[none,
+ emergency,
alert,
critical,
error,
warning,
notice,
info,
- debug]).
+ debug,
+ all]).
+-define(LOG_NONE,-1).
-define(EMERGENCY,0).
-define(ALERT,1).
-define(CRITICAL,2).
@@ -72,6 +73,7 @@
-define(NOTICE,5).
-define(INFO,6).
-define(DEBUG,7).
+-define(LOG_ALL,10).
-define(IS_LEVEL(L),
(L=:=emergency orelse
diff --git a/lib/kernel/src/logger_server.erl b/lib/kernel/src/logger_server.erl
index a7f302ac8f..644fdd5af2 100644
--- a/lib/kernel/src/logger_server.erl
+++ b/lib/kernel/src/logger_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,9 +25,10 @@
-export([start_link/0,
add_handler/3, remove_handler/1,
add_filter/2, remove_filter/2,
- set_module_level/2, reset_module_level/1,
- cache_module_level/1,
- set_config/2, set_config/3]).
+ set_module_level/2, unset_module_level/0,
+ unset_module_level/1, cache_module_level/1,
+ set_config/2, set_config/3, update_config/2,
+ update_formatter_config/2]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -36,8 +37,9 @@
-include("logger_internal.hrl").
-define(SERVER, logger).
+-define(LOGGER_SERVER_TAG, '$logger_cb_process').
--record(state, {tid}).
+-record(state, {tid, async_req, async_req_queue}).
%%%===================================================================
%%% API
@@ -47,23 +49,18 @@ start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
add_handler(Id,Module,Config0) ->
- case sanity_check(logger,handlers,[Id]) of
- ok ->
- try check_mod(Module) of
+ try {check_id(Id),check_mod(Module)} of
+ {ok,ok} ->
+ case sanity_check(Id,Config0) of
ok ->
- case sanity_check(Id,Config0) of
- ok ->
- Default = default_config(Id),
- Config = maps:merge(Default,Config0),
- call({add_handler,Id,Module,Config});
- Error ->
- Error
- end
- catch throw:Error ->
- {error,Error}
- end;
- Error ->
- Error
+ Default = default_config(Id,Module),
+ Config = maps:merge(Default,Config0),
+ call({add_handler,Id,Module,Config});
+ Error ->
+ Error
+ end
+ catch throw:Error ->
+ {error,Error}
end.
remove_handler(HandlerId) ->
@@ -78,144 +75,193 @@ add_filter(Owner,Filter) ->
remove_filter(Owner,FilterId) ->
call({remove_filter,Owner,FilterId}).
-set_module_level(Module,Level) when is_atom(Module) ->
- case sanity_check(logger,level,Level) of
- ok -> call({set_module_level,Module,Level});
- Error -> Error
+set_module_level(Modules,Level) when is_list(Modules) ->
+ case lists:all(fun(M) -> is_atom(M) end,Modules) of
+ true ->
+ case sanity_check(primary,level,Level) of
+ ok -> call({set_module_level,Modules,Level});
+ Error -> Error
+ end;
+ false ->
+ {error,{not_a_list_of_modules,Modules}}
end;
-set_module_level(Module,_) ->
- {error,{not_a_module,Module}}.
+set_module_level(Modules,_) ->
+ {error,{not_a_list_of_modules,Modules}}.
-reset_module_level(Module) when is_atom(Module) ->
- call({reset_module_level,Module});
-reset_module_level(Module) ->
- {error,{not_a_module,Module}}.
+unset_module_level() ->
+ call({unset_module_level,all}).
+
+unset_module_level(Modules) when is_list(Modules) ->
+ case lists:all(fun(M) -> is_atom(M) end,Modules) of
+ true ->
+ call({unset_module_level,Modules});
+ false ->
+ {error,{not_a_list_of_modules,Modules}}
+ end;
+unset_module_level(Modules) ->
+ {error,{not_a_list_of_modules,Modules}}.
cache_module_level(Module) ->
gen_server:cast(?SERVER,{cache_module_level,Module}).
-
set_config(Owner,Key,Value) ->
- case sanity_check(Owner,Key,Value) of
- ok -> call({update_config,Owner,#{Key=>Value}});
- Error -> Error
- end.
+ update_config(Owner,#{Key=>Value}).
-set_config(Owner,Config0) ->
- case sanity_check(Owner,Config0) of
+set_config(Owner,Config) ->
+ case sanity_check(Owner,Config) of
ok ->
- Config = maps:merge(default_config(Owner),Config0),
call({set_config,Owner,Config});
Error ->
Error
end.
+update_config(Owner, Config) ->
+ case sanity_check(Owner,Config) of
+ ok ->
+ call({update_config,Owner,Config});
+ Error ->
+ Error
+ end.
+
+update_formatter_config(HandlerId, FormatterConfig)
+ when is_map(FormatterConfig) ->
+ call({update_formatter_config,HandlerId,FormatterConfig});
+update_formatter_config(_HandlerId, FormatterConfig) ->
+ {error,{invalid_formatter_config,FormatterConfig}}.
+
+
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
init([]) ->
process_flag(trap_exit, true),
+ put(?LOGGER_SERVER_TAG,true),
Tid = logger_config:new(?LOGGER_TABLE),
- LoggerConfig = maps:merge(default_config(logger),
- #{handlers=>[logger_simple]}),
- logger_config:create(Tid,logger,LoggerConfig),
- SimpleConfig0 = maps:merge(default_config(logger_simple),
+ PrimaryConfig = maps:merge(default_config(primary),
+ #{handlers=>[simple]}),
+ logger_config:create(Tid,primary,PrimaryConfig),
+ SimpleConfig0 = maps:merge(default_config(simple,logger_simple_h),
#{filter_default=>stop,
- filters=>?DEFAULT_HANDLER_FILTERS,
- logger_simple=>#{buffer=>true}}),
+ filters=>?DEFAULT_HANDLER_FILTERS}),
%% If this fails, then the node should crash
- {ok,SimpleConfig} =
- logger_simple:adding_handler(logger_simple,SimpleConfig0),
- logger_config:create(Tid,logger_simple,logger_simple,SimpleConfig),
- {ok, #state{tid=Tid}}.
+ {ok,SimpleConfig} = logger_simple_h:adding_handler(SimpleConfig0),
+ logger_config:create(Tid,simple,logger_simple_h,SimpleConfig),
+ {ok, #state{tid=Tid, async_req_queue = queue:new()}}.
-handle_call({add_handler,Id,Module,HConfig}, _From, #state{tid=Tid}=State) ->
- Reply =
- case logger_config:exist(Tid,Id) of
- true ->
- {error,{already_exist,Id}};
- false ->
- %% inform the handler
- case call_h(Module,adding_handler,[Id,HConfig],{ok,HConfig}) of
- {ok,HConfig1} ->
- logger_config:create(Tid,Id,Module,HConfig1),
- {ok,Config} = do_get_config(Tid,logger),
- Handlers = maps:get(handlers,Config,[]),
- do_set_config(Tid,logger,
- Config#{handlers=>[Id|Handlers]}),
- ok;
- {error,HReason} ->
- {error,{handler_not_added,HReason}}
- end
- end,
- {reply,Reply,State};
-handle_call({remove_handler,HandlerId}, _From, #state{tid=Tid}=State) ->
- Reply =
- case logger_config:get(Tid,HandlerId) of
- {ok,{Module,_}} ->
- {ok,Config} = do_get_config(Tid,logger),
- Handlers0 = maps:get(handlers,Config,[]),
- Handlers = lists:delete(HandlerId,Handlers0),
- %% inform the handler
- _ = call_h(Module,removing_handler,[HandlerId,Config],ok),
- do_set_config(Tid,logger,Config#{handlers=>Handlers}),
- logger_config:delete(Tid,HandlerId),
- ok;
- _ ->
- {error,{not_found,HandlerId}}
- end,
- {reply,Reply,State};
+handle_call({add_handler,Id,Module,HConfig}, From, #state{tid=Tid}=State) ->
+ case logger_config:exist(Tid,Id) of
+ true ->
+ {reply,{error,{already_exist,Id}},State};
+ false ->
+ call_h_async(
+ fun() ->
+ %% inform the handler
+ call_h(Module,adding_handler,[HConfig],{ok,HConfig})
+ end,
+ fun({ok,HConfig1}) ->
+ %% We know that the call_h would have loaded the module
+ %% if it existed, so it is safe here to call function_exported
+ %% to find out if this is a valid handler
+ case erlang:function_exported(Module, log, 2) of
+ true ->
+ logger_config:create(Tid,Id,Module,HConfig1),
+ {ok,Config} = do_get_config(Tid,primary),
+ Handlers = maps:get(handlers,Config,[]),
+ do_set_config(Tid,primary,
+ Config#{handlers=>[Id|Handlers]});
+ false ->
+ {error,{invalid_handler,
+ {function_not_exported,
+ {Module,log,2}}}}
+ end;
+ ({error,HReason}) ->
+ {error,{handler_not_added,HReason}}
+ end,From,State)
+ end;
+handle_call({remove_handler,HandlerId}, From, #state{tid=Tid}=State) ->
+ case logger_config:get(Tid,HandlerId) of
+ {ok,{Module,HConfig}} ->
+ {ok,Config} = do_get_config(Tid,primary),
+ Handlers0 = maps:get(handlers,Config,[]),
+ Handlers = lists:delete(HandlerId,Handlers0),
+ call_h_async(
+ fun() ->
+ %% inform the handler
+ call_h(Module,removing_handler,[HConfig],ok)
+ end,
+ fun(_Res) ->
+ do_set_config(Tid,primary,Config#{handlers=>Handlers}),
+ logger_config:delete(Tid,HandlerId),
+ ok
+ end,From,State);
+ _ ->
+ {reply,{error,{not_found,HandlerId}},State}
+ end;
handle_call({add_filter,Id,Filter}, _From,#state{tid=Tid}=State) ->
Reply = do_add_filter(Tid,Id,Filter),
{reply,Reply,State};
handle_call({remove_filter,Id,FilterId}, _From, #state{tid=Tid}=State) ->
Reply = do_remove_filter(Tid,Id,FilterId),
{reply,Reply,State};
-handle_call({update_config,Id,NewConfig}, _From, #state{tid=Tid}=State) ->
- Reply =
- case logger_config:get(Tid,Id) of
- {ok,{Module,OldConfig}} ->
- Config = maps:merge(OldConfig,NewConfig),
- case call_h(Module,changing_config,[Id,OldConfig,Config],
- {ok,Config}) of
- {ok,Config1} ->
- do_set_config(Tid,Id,Config1);
- Error ->
- Error
- end;
- {ok,OldConfig} ->
- Config = maps:merge(OldConfig,NewConfig),
- do_set_config(Tid,Id,Config);
- Error ->
- Error
- end,
- {reply,Reply,State};
-handle_call({set_config,logger,Config}, _From, #state{tid=Tid}=State) ->
- Reply = do_set_config(Tid,logger,Config),
+handle_call({update_config,Id,NewConfig}, From, #state{tid=Tid}=State) ->
+ case logger_config:get(Tid,Id) of
+ {ok,{_Module,OldConfig}} ->
+ Config = maps:merge(OldConfig,NewConfig),
+ handle_call({set_config,Id,Config}, From, State);
+ {ok,OldConfig} ->
+ Config = maps:merge(OldConfig,NewConfig),
+ {reply,do_set_config(Tid,Id,Config),State};
+ Error ->
+ {reply,Error,State}
+ end;
+handle_call({set_config,primary,Config0}, _From, #state{tid=Tid}=State) ->
+ Config = maps:merge(default_config(primary),Config0),
+ {ok,#{handlers:=Handlers}} = logger_config:get(Tid,primary),
+ Reply = do_set_config(Tid,primary,Config#{handlers=>Handlers}),
{reply,Reply,State};
-handle_call({set_config,HandlerId,Config}, _From, #state{tid=Tid}=State) ->
+handle_call({set_config,HandlerId,Config0}, From, #state{tid=Tid}=State) ->
+ case logger_config:get(Tid,HandlerId) of
+ {ok,{Module,OldConfig}} ->
+ Config = maps:merge(default_config(HandlerId,Module),Config0),
+ call_h_async(
+ fun() ->
+ call_h(Module,changing_config,[OldConfig,Config],
+ {ok,Config})
+ end,
+ fun({ok,Config1}) ->
+ do_set_config(Tid,HandlerId,Config1);
+ (Error) ->
+ Error
+ end,From,State);
+ _ ->
+ {reply,{error,{not_found,HandlerId}},State}
+ end;
+handle_call({update_formatter_config,HandlerId,NewFConfig},_From,
+ #state{tid=Tid}=State) ->
Reply =
case logger_config:get(Tid,HandlerId) of
- {ok,{Module,OldConfig}} ->
- case call_h(Module,changing_config,[HandlerId,OldConfig,Config],
- {ok,Config}) of
- {ok,Config1} ->
- do_set_config(Tid,HandlerId,Config1);
- Error ->
- Error
+ {ok,{_Mod,#{formatter:={FMod,OldFConfig}}=Config}} ->
+ try
+ FConfig = maps:merge(OldFConfig,NewFConfig),
+ check_formatter({FMod,FConfig}),
+ do_set_config(Tid,HandlerId,
+ Config#{formatter=>{FMod,FConfig}})
+ catch throw:Reason -> {error,Reason}
end;
_ ->
- {error,{not_found,HandlerId}}
+ {error,{not_found,HandlerId}}
end,
{reply,Reply,State};
-handle_call({set_module_level,Module,Level}, _From, #state{tid=Tid}=State) ->
- Reply = logger_config:set_module_level(Tid,Module,Level),
+handle_call({set_module_level,Modules,Level}, _From, #state{tid=Tid}=State) ->
+ Reply = logger_config:set_module_level(Tid,Modules,Level),
{reply,Reply,State};
-handle_call({reset_module_level,Module}, _From, #state{tid=Tid}=State) ->
- Reply = logger_config:reset_module_level(Tid,Module),
+handle_call({unset_module_level,Modules}, _From, #state{tid=Tid}=State) ->
+ Reply = logger_config:unset_module_level(Tid,Modules),
{reply,Reply,State}.
+handle_cast({async_req_reply,_Ref,_Reply} = Reply,State) ->
+ call_h_reply(Reply,State);
handle_cast({cache_module_level,Module}, #state{tid=Tid}=State) ->
logger_config:cache_module_level(Tid,Module),
{noreply, State}.
@@ -235,11 +281,21 @@ handle_info({log,Level,Report,Meta}, State) ->
handle_info({Ref,_Reply},State) when is_reference(Ref) ->
%% Assuming this is a timed-out gen_server reply - ignoring
{noreply, State};
-handle_info(Unexpected,State) ->
+handle_info({'DOWN',_Ref,_Proc,_Pid,_Reason} = Down,State) ->
+ call_h_reply(Down,State);
+handle_info(Unexpected,State) when element(1,Unexpected) == 'EXIT' ->
+ %% The simple handler will send an 'EXIT' message when it is replaced
+ %% We may as well ignore all 'EXIT' messages that we get
?LOG_INTERNAL(debug,
[{logger,got_unexpected_message},
{process,?SERVER},
{message,Unexpected}]),
+ {noreply,State};
+handle_info(Unexpected,State) ->
+ ?LOG_INTERNAL(info,
+ [{logger,got_unexpected_message},
+ {process,?SERVER},
+ {message,Unexpected}]),
{noreply,State}.
terminate(_Reason, _State) ->
@@ -249,8 +305,11 @@ terminate(_Reason, _State) ->
%%% Internal functions
%%%===================================================================
call(Request) ->
- case whereis(?SERVER) of
- Pid when Pid==self() ->
+ Action = element(1,Request),
+ case get(?LOGGER_SERVER_TAG) of
+ true when
+ Action == add_handler; Action == remove_handler;
+ Action == update_config; Action == set_config ->
{error,{attempting_syncronous_call_to_self,Request}};
_ ->
gen_server:call(?SERVER,Request,?DEFAULT_LOGGER_CALL_TIMEOUT)
@@ -298,16 +357,18 @@ do_set_config(Tid,Id,Config) ->
logger_config:set(Tid,Id,Config),
ok.
-default_config(logger) ->
- #{level=>info,
+default_config(primary) ->
+ #{level=>notice,
filters=>[],
- filter_default=>log,
- handlers=>[]};
-default_config(_) ->
- #{level=>info,
+ filter_default=>log};
+default_config(Id) ->
+ #{id=>Id,
+ level=>all,
filters=>[],
filter_default=>log,
- formatter=>{?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}}.
+ formatter=>{?DEFAULT_FORMATTER,#{}}}.
+default_config(Id,Module) ->
+ (default_config(Id))#{module=>Module}.
sanity_check(Owner,Key,Value) ->
sanity_check_1(Owner,[{Key,Value}]).
@@ -324,8 +385,8 @@ sanity_check_1(Owner,Config) when is_list(Config) ->
catch throw:Error -> {error,Error}
end.
-get_type(logger) ->
- logger;
+get_type(primary) ->
+ primary;
get_type(Id) ->
check_id(Id),
handler.
@@ -333,9 +394,6 @@ get_type(Id) ->
check_config(Owner,[{level,Level}|Config]) ->
check_level(Level),
check_config(Owner,Config);
-check_config(logger,[{handlers,Handlers}|Config]) ->
- check_handlers(Handlers),
- check_config(logger,Config);
check_config(Owner,[{filters,Filters}|Config]) ->
check_filters(Filters),
check_config(Owner,Config);
@@ -345,8 +403,8 @@ check_config(Owner,[{filter_default,FD}|Config]) ->
check_config(handler,[{formatter,Formatter}|Config]) ->
check_formatter(Formatter),
check_config(handler,Config);
-check_config(logger,[C|_]) ->
- throw({invalid_logger_config,C});
+check_config(primary,[C|_]) ->
+ throw({invalid_primary_config,C});
check_config(handler,[{_,_}|Config]) ->
%% Arbitrary config elements are allowed for handlers
check_config(handler,Config);
@@ -373,14 +431,6 @@ check_level(Level) ->
throw({invalid_level,Level})
end.
-check_handlers([Id|Handlers]) ->
- check_id(Id),
- check_handlers(Handlers);
-check_handlers([]) ->
- ok;
-check_handlers(Handlers) ->
- throw({invalid_handlers,Handlers}).
-
check_filters([{Id,{Fun,_Args}}|Filters]) when is_atom(Id), is_function(Fun,2) ->
check_filters(Filters);
check_filters([Filter|_]) ->
@@ -395,40 +445,24 @@ check_filter_default(FD) when FD==stop; FD==log ->
check_filter_default(FD) ->
throw({invalid_filter_default,FD}).
-check_formatter({logger_formatter,Config}) when is_map(Config) ->
- check_logger_formatter_config(maps:to_list(Config));
-check_formatter({logger_formatter,Config}) ->
- throw({invalid_formatter_config,Config});
-check_formatter({Mod,_}) ->
- %% no knowledge of other formatters
- check_mod(Mod);
+check_formatter({Mod,Config}) ->
+ check_mod(Mod),
+ try Mod:check_config(Config) of
+ ok -> ok;
+ {error,Error} -> throw(Error)
+ catch
+ C:R:S ->
+ case {C,R,S} of
+ {error,undef,[{Mod,check_config,[Config],_}|_]} ->
+ ok;
+ _ ->
+ throw({callback_crashed,
+ {C,R,logger:filter_stacktrace(?MODULE,S)}})
+ end
+ end;
check_formatter(Formatter) ->
throw({invalid_formatter,Formatter}).
-
-check_logger_formatter_config([{template,T}|Config]) when is_list(T) ->
- case lists:all(fun(X) when is_atom(X) -> true;
- (X) when is_tuple(X), is_atom(element(1,X)) -> true;
- (X) when is_list(X) -> io_lib:printable_unicode_list(X);
- (_) -> false
- end,
- T) of
- true ->
- check_logger_formatter_config(Config);
- false ->
- throw({invalid_formatter_template,T})
- end;
-check_logger_formatter_config([{legacy_header,LH}|Config]) when is_boolean(LH) ->
- check_logger_formatter_config(Config);
-check_logger_formatter_config([{single_line,SL}|Config]) when is_boolean(SL) ->
- check_logger_formatter_config(Config);
-check_logger_formatter_config([{utc,Utc}|Config]) when is_boolean(Utc) ->
- check_logger_formatter_config(Config);
-check_logger_formatter_config([C|_]) ->
- throw({invalid_formatter_config,C});
-check_logger_formatter_config([]) ->
- ok.
-
call_h(Module, Function, Args, DefRet) ->
%% Not calling code:ensure_loaded + erlang:function_exported here,
%% since in some rare terminal cases, the code_server might not
@@ -440,7 +474,59 @@ call_h(Module, Function, Args, DefRet) ->
{error,undef,[{Module,Function,Args,_}|_]} ->
DefRet;
_ ->
- {error,{callback_crashed,
- {C,R,logger:filter_stacktrace(?MODULE,S)}}}
+ ST = logger:filter_stacktrace(?MODULE,S),
+ ?LOG_INTERNAL(error,
+ [{logger,callback_crashed},
+ {process,?SERVER},
+ {reason,{C,R,ST}}]),
+ {error,{callback_crashed,{C,R,ST}}}
end
end.
+
+%% There are all sort of API functions that can cause deadlocks if called
+%% from the handler callbacks. So we spawn a process that does the request
+%% for the logger_server. There are still APIs that will cause problems,
+%% namely logger:add_handler
+call_h_async(AsyncFun,PostFun,From,#state{ async_req = undefined } = State) ->
+ Parent = self(),
+ {Pid, Ref} = spawn_monitor(
+ fun() ->
+ put(?LOGGER_SERVER_TAG,true),
+ receive Ref -> Ref end,
+ gen_server:cast(Parent, {async_req_reply, Ref, AsyncFun()})
+ end),
+ Pid ! Ref,
+ {noreply,State#state{ async_req = {Ref,PostFun,From} }};
+call_h_async(AsyncFun,PostFun,From,#state{ async_req_queue = Q } = State) ->
+ {noreply,State#state{ async_req_queue = queue:in({AsyncFun,PostFun,From},Q) }}.
+
+call_h_reply({async_req_reply,Ref,Reply},
+ #state{ async_req = {Ref,PostFun,From}, async_req_queue = Q} = State) ->
+ erlang:demonitor(Ref,[flush]),
+ _ = gen_server:reply(From, PostFun(Reply)),
+ {Value,NewQ} = queue:out(Q),
+ NewState = State#state{ async_req = undefined,
+ async_req_queue = NewQ },
+ case Value of
+ {value,{AsyncFun,NPostFun,NFrom}} ->
+ call_h_async(AsyncFun,NPostFun,NFrom,NewState);
+ empty ->
+ {noreply,NewState}
+ end;
+call_h_reply({'DOWN',Ref,_Proc,Pid,Reason}, #state{ async_req = {Ref,_PostFun,_From}} = State) ->
+ %% This clause should only be triggered if someone explicitly sends an exit signal
+ %% to the spawned process. It is only here to make sure that the logger_server does
+ %% not deadlock if that happens.
+ ?LOG_INTERNAL(error,
+ [{logger,process_exited},
+ {process,Pid},
+ {reason,Reason}]),
+ call_h_reply(
+ {async_req_reply,Ref,{error,{logger_process_exited,Pid,Reason}}},
+ State);
+call_h_reply(Unexpected,State) ->
+ ?LOG_INTERNAL(info,
+ [{logger,got_unexpected_message},
+ {process,?SERVER},
+ {message,Unexpected}]),
+ {noreply,State}.
diff --git a/lib/kernel/src/logger_simple.erl b/lib/kernel/src/logger_simple_h.erl
index a1b427b96c..8b51dd8569 100644
--- a/lib/kernel/src/logger_simple.erl
+++ b/lib/kernel/src/logger_simple_h.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -17,40 +17,21 @@
%%
%% %CopyrightEnd%
%%
--module(logger_simple).
+-module(logger_simple_h).
--export([adding_handler/2, removing_handler/2, log/2]).
--export([get_buffer/0]).
+-export([adding_handler/1, removing_handler/1, log/2]).
%% This module implements a simple handler for logger. It is the
%% default used during system start.
%%%-----------------------------------------------------------------
-%%% API
-get_buffer() ->
- case whereis(?MODULE) of
- undefined ->
- {error,noproc};
- Pid ->
- Ref = erlang:monitor(process,Pid),
- Pid ! {get_buffer,self()},
- receive
- {buffer,Buffer} ->
- erlang:demonitor(Ref,[flush]),
- {ok,Buffer};
- {'DOWN',Ref,process,Pid,Reason} ->
- {error,Reason}
- end
- end.
-
-%%%-----------------------------------------------------------------
%%% Logger callback
-adding_handler(?MODULE,Config) ->
+adding_handler(#{id:=simple}=Config) ->
Me = self(),
case whereis(?MODULE) of
undefined ->
- {Pid,Ref} = spawn_opt(fun() -> init(Me,Config) end,
+ {Pid,Ref} = spawn_opt(fun() -> init(Me) end,
[link,monitor,{message_queue_data,off_heap}]),
receive
{'DOWN',Ref,process,Pid,Reason} ->
@@ -63,7 +44,7 @@ adding_handler(?MODULE,Config) ->
{error,{handler_process_name_already_exists,?MODULE}}
end.
-removing_handler(?MODULE,_Config) ->
+removing_handler(#{id:=simple}) ->
case whereis(?MODULE) of
undefined ->
ok;
@@ -89,7 +70,7 @@ log(#{msg:=_,meta:=#{time:=_}}=Log,_Config) ->
do_log(
#{level=>error,
msg=>{report,{error,simple_handler_process_dead}},
- meta=>#{time=>erlang:monotonic_time(microsecond)}}),
+ meta=>#{time=>erlang:system_time(microsecond)}}),
do_log(Log);
_ ->
?MODULE ! {log,Log}
@@ -102,54 +83,50 @@ log(_,_) ->
%%%-----------------------------------------------------------------
%%% Process
-init(Starter,Config) ->
+init(Starter) ->
register(?MODULE,self()),
Starter ! {self(),started},
- BufferSize =
- case Config of
- #{?MODULE:=#{buffer:=true}} ->
- 10;
- _ ->
- infinity
- end,
- loop(#{buffer_size=>BufferSize,dropped=>0,buffer=>[]},infinity).
+ loop(#{buffer_size=>10,dropped=>0,buffer=>[]}).
-loop(Buffer,Timeout) ->
+loop(Buffer) ->
receive
stop ->
- ok;
- {get_buffer,From} ->
- loop(Buffer#{send_to=>From},0);
+ %% We replay the logger messages of there is
+ %% a default handler when the simple handler
+ %% is removed.
+ case logger:get_handler_config(default) of
+ {ok, _} ->
+ replay_buffer(Buffer);
+ _ ->
+ ok
+ end;
{log,#{msg:=_,meta:=#{time:=_}}=Log} ->
do_log(Log),
- loop(update_buffer(Buffer,Log),Timeout);
+ loop(update_buffer(Buffer,Log));
_ ->
%% Unexpected message - flush it!
- loop(Buffer,Timeout)
- after Timeout ->
- #{dropped:=D,buffer:=B,send_to:=Pid} = Buffer,
- LogList = lists:reverse(B) ++ drop_msg(D),
- Pid ! {buffer,LogList},
- loop(Buffer#{buffer_size=>infinity,
- dropped=>0,
- buffer=>[],
- send_to=>false},
- infinity)
+ loop(Buffer)
end.
-update_buffer(#{buffer_size:=infinity}=Buffer,_Log) ->
- Buffer;
update_buffer(#{buffer_size:=0,dropped:=D}=Buffer,_Log) ->
Buffer#{dropped=>D+1};
update_buffer(#{buffer_size:=S,buffer:=B}=Buffer,Log) ->
Buffer#{buffer_size=>S-1,buffer=>[Log|B]}.
+replay_buffer(#{ dropped := D, buffer := Buffer }) ->
+ lists:foreach(
+ fun F(#{msg := {Tag, Msg}} = L) when Tag =:= string; Tag =:= report ->
+ F(L#{ msg := Msg });
+ F(#{ level := Level, msg := Msg, meta := MD}) ->
+ logger:log(Level, Msg, MD)
+ end, lists:reverse(Buffer, drop_msg(D))).
+
drop_msg(0) ->
[];
drop_msg(N) ->
[#{level=>info,
msg=>{"Simple handler buffer full, dropped ~w messages",[N]},
- meta=>#{time=>erlang:monotonic_time(microsecond)}}].
+ meta=>#{time=>erlang:system_time(microsecond)}}].
%%%-----------------------------------------------------------------
%%% Internal
@@ -164,8 +141,7 @@ do_log(#{msg:=Msg,meta:=#{time:=T}}) ->
display_date(T),
display(Msg).
-display_date(Timestamp0) when is_integer(Timestamp0) ->
- Timestamp = Timestamp0 + erlang:time_offset(microsecond),
+display_date(Timestamp) when is_integer(Timestamp) ->
Micro = Timestamp rem 1000000,
Sec = Timestamp div 1000000,
{{Y,Mo,D},{H,Mi,S}} = erlang:universaltime_to_localtime(
diff --git a/lib/kernel/src/logger_std_h.erl b/lib/kernel/src/logger_std_h.erl
index 31edcfea8b..9a2a1443b3 100644
--- a/lib/kernel/src/logger_std_h.erl
+++ b/lib/kernel/src/logger_std_h.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,8 +35,10 @@
terminate/2, code_change/3]).
%% logger callbacks
--export([log/2, adding_handler/2, removing_handler/2,
- changing_config/3, swap_buffer/2]).
+-export([log/2, adding_handler/1, removing_handler/1, changing_config/2]).
+
+%% handler internal
+-export([log_handler_info/4]).
%%%===================================================================
%%% API
@@ -48,7 +50,7 @@
%%% handler process gets added
-spec start_link(Name, Config, HandlerState) -> {ok,Pid} | {error,Reason} when
Name :: atom(),
- Config :: logger:config(),
+ Config :: logger:handler_config(),
HandlerState :: map(),
Pid :: pid(),
Reason :: term().
@@ -64,7 +66,8 @@ start_link(Name, Config, HandlerState) ->
filesync(Name) when is_atom(Name) ->
try
- gen_server:call(Name, filesync, ?DEFAULT_CALL_TIMEOUT)
+ gen_server:call(?name_to_reg_name(?MODULE,Name),
+ filesync, ?DEFAULT_CALL_TIMEOUT)
catch
_:{timeout,_} -> {error,handler_busy}
end;
@@ -80,7 +83,8 @@ filesync(Name) ->
info(Name) when is_atom(Name) ->
try
- gen_server:call(Name, info, ?DEFAULT_CALL_TIMEOUT)
+ gen_server:call(?name_to_reg_name(?MODULE,Name),
+ info, ?DEFAULT_CALL_TIMEOUT)
catch
_:{timeout,_} -> {error,handler_busy}
end;
@@ -95,7 +99,8 @@ info(Name) ->
reset(Name) when is_atom(Name) ->
try
- gen_server:call(Name, reset, ?DEFAULT_CALL_TIMEOUT)
+ gen_server:call(?name_to_reg_name(?MODULE,Name),
+ reset, ?DEFAULT_CALL_TIMEOUT)
catch
_:{timeout,_} -> {error,handler_busy}
end;
@@ -109,27 +114,20 @@ reset(Name) ->
%%%-----------------------------------------------------------------
%%% Handler being added
-adding_handler(Name, Config) ->
- case check_config(adding, Name, Config) of
+adding_handler(#{id:=Name}=Config) ->
+ case check_config(adding, Config) of
{ok, Config1} ->
%% create initial handler state by merging defaults with config
- HConfig = maps:get(?MODULE, Config1, #{}),
+ HConfig = maps:get(config, Config1, #{}),
HState = maps:merge(get_init_state(), HConfig),
case logger_h_common:overload_levels_ok(HState) of
true ->
- case start(Name, Config1, HState) of
- ok ->
- %% Make sure wait_for_buffer is not stored, so we
- %% won't hang and wait for buffer on a restart
- {ok, maps:remove(wait_for_buffer,Config1)};
- Error ->
- Error
- end;
+ start(Name, Config1, HState);
false ->
- #{toggle_sync_qlen := TSQL,
- drop_new_reqs_qlen := DNRQL,
- flush_reqs_qlen := FRQL} = HState,
- {error,{invalid_levels,{TSQL,DNRQL,FRQL}}}
+ #{sync_mode_qlen := SMQL,
+ drop_mode_qlen := DMQL,
+ flush_qlen := FQL} = HState,
+ {error,{invalid_levels,{SMQL,DMQL,FQL}}}
end;
Error ->
Error
@@ -137,25 +135,27 @@ adding_handler(Name, Config) ->
%%%-----------------------------------------------------------------
%%% Updating handler config
-changing_config(Name,
- OldConfig=#{id:=Id, ?MODULE:=#{type:=Type}},
- NewConfig=#{id:=Id}) ->
- MyConfig = maps:get(?MODULE, NewConfig, #{}),
- case maps:get(type, MyConfig, Type) of
+changing_config(OldConfig=#{id:=Name, config:=OldHConfig},
+ NewConfig=#{id:=Name}) ->
+ #{type:=Type, handler_pid:=HPid, mode_tab:=ModeTab} = OldHConfig,
+ NewHConfig = maps:get(config, NewConfig, #{}),
+ case maps:get(type, NewHConfig, Type) of
Type ->
- MyConfig1 = MyConfig#{type=>Type},
- changing_config1(Name, OldConfig,
- NewConfig#{?MODULE=>MyConfig1});
+ NewHConfig1 = NewHConfig#{type=>Type,
+ handler_pid=>HPid,
+ mode_tab=>ModeTab},
+ changing_config1(HPid, OldConfig,
+ NewConfig#{config=>NewHConfig1});
_ ->
{error,{illegal_config_change,OldConfig,NewConfig}}
end;
-changing_config(_Name, OldConfig, NewConfig) ->
+changing_config(OldConfig, NewConfig) ->
{error,{illegal_config_change,OldConfig,NewConfig}}.
-changing_config1(Name, OldConfig, NewConfig) ->
- case check_config(changing, Name, NewConfig) of
+changing_config1(HPid, OldConfig, NewConfig) ->
+ case check_config(changing, NewConfig) of
Result = {ok,NewConfig1} ->
- try gen_server:call(Name, {change_config,OldConfig,NewConfig1},
+ try gen_server:call(HPid, {change_config,OldConfig,NewConfig1},
?DEFAULT_CALL_TIMEOUT) of
ok -> Result;
HError -> HError
@@ -166,80 +166,71 @@ changing_config1(Name, OldConfig, NewConfig) ->
Error
end.
-check_config(adding, Name, Config0) ->
- %% Merge in defaults on top level
- Config = maps:merge(#{id => Name}, Config0),
+check_config(adding, Config) ->
%% Merge in defaults on handler level
- MyConfig0 = maps:get(?MODULE, Config, #{}),
- MyConfig = maps:merge(#{type => standard_io},
- MyConfig0),
- case check_my_config(maps:to_list(MyConfig)) of
+ HConfig0 = maps:get(config, Config, #{}),
+ HConfig = maps:merge(#{type => standard_io},
+ HConfig0),
+ case check_h_config(maps:to_list(HConfig)) of
ok ->
- {ok,Config#{?MODULE=>MyConfig}};
+ {ok,Config#{config=>HConfig}};
Error ->
Error
end;
-check_config(changing, _Name, Config) ->
- MyConfig = maps:get(?MODULE, Config, #{}),
- case check_my_config(maps:to_list(MyConfig)) of
+check_config(changing, Config) ->
+ HConfig = maps:get(config, Config, #{}),
+ case check_h_config(maps:to_list(HConfig)) of
ok -> {ok,Config};
Error -> Error
end.
-check_my_config([{type,Type} | Config]) when Type == standard_io;
- Type == standard_error ->
- check_my_config(Config);
-check_my_config([{type,{file,File}} | Config]) when is_list(File) ->
- check_my_config(Config);
-check_my_config([{type,{file,File,Modes}} | Config]) when is_list(File),
- is_list(Modes) ->
- check_my_config(Config);
-check_my_config([Other | Config]) ->
+check_h_config([{type,Type} | Config]) when Type == standard_io;
+ Type == standard_error ->
+ check_h_config(Config);
+check_h_config([{type,{file,File}} | Config]) when is_list(File) ->
+ check_h_config(Config);
+check_h_config([{type,{file,File,Modes}} | Config]) when is_list(File),
+ is_list(Modes) ->
+ check_h_config(Config);
+check_h_config([Other | Config]) ->
case logger_h_common:check_common_config(Other) of
valid ->
- check_my_config(Config);
+ check_h_config(Config);
invalid ->
{error,{invalid_config,?MODULE,Other}}
end;
-check_my_config([]) ->
+check_h_config([]) ->
ok.
%%%-----------------------------------------------------------------
%%% Handler being removed
-removing_handler(Name,_Config) ->
+removing_handler(#{id:=Name}) ->
stop(Name).
%%%-----------------------------------------------------------------
-%%% Get buffer when swapping from simple handler
-swap_buffer(Name,Buffer) ->
- case whereis(Name) of
- undefined ->
- ok;
- _ ->
- Name ! {buffer,Buffer}
- end.
-
-%%%-----------------------------------------------------------------
%%% Log a string or report
--spec log(Log, Config) -> ok | dropped when
- Log :: logger:log(),
- Config :: logger:config().
-
-log(Log,Config=#{id:=Name}) ->
- %% if the handler has crashed, we must drop this request
+-spec log(LogEvent, Config) -> ok | dropped when
+ LogEvent :: logger:log_event(),
+ Config :: logger:handler_config().
+
+log(LogEvent, Config = #{id := Name,
+ config := #{handler_pid := HPid,
+ mode_tab := ModeTab}}) ->
+ %% if the handler has crashed, we must drop this event
%% and hope the handler restarts so we can try again
- true = is_pid(whereis(Name)),
- Bin = logger_h_common:log_to_binary(Log,Config),
- logger_h_common:call_cast_or_drop(Name, Bin).
+ true = is_process_alive(HPid),
+ Bin = logger_h_common:log_to_binary(LogEvent, Config),
+ logger_h_common:call_cast_or_drop(Name, HPid, ModeTab, Bin).
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
-init([Name, Config,
- State0 = #{type := Type, file_ctrl_sync_int := FileCtrlSyncInt}]) ->
- register(Name, self()),
+init([Name, Config = #{config := HConfig},
+ State0 = #{type := Type, file_ctrl_sync_int := FileCtrlSyncInt}]) ->
+ RegName = ?name_to_reg_name(?MODULE,Name),
+ register(RegName, self()),
process_flag(trap_exit, true),
process_flag(message_queue_data, off_heap),
@@ -248,58 +239,61 @@ init([Name, Config,
case do_init(Name, Type) of
{ok,InitState} ->
- catch ets:new(Name, [public, named_table]),
- ?set_mode(Name, async),
- State = maps:merge(State0, InitState),
- T0 = ?timestamp(),
- State1 =
- ?merge_with_stats(State#{mode => async,
- file_ctrl_sync => FileCtrlSyncInt,
- last_qlen => 0,
- last_log_ts => T0,
- burst_win_ts => T0,
- burst_msg_count => 0}),
- proc_lib:init_ack({ok,self()}),
- gen_server:cast(self(), {repeated_filesync,T0}),
- enter_loop(Config, State1);
+ try ets:new(Name, [public]) of
+ ModeTab ->
+ ?set_mode(ModeTab, async),
+ State = maps:merge(State0, InitState),
+ T0 = ?timestamp(),
+ State1 =
+ ?merge_with_stats(State#{
+ mode_tab => ModeTab,
+ mode => async,
+ file_ctrl_sync => FileCtrlSyncInt,
+ last_qlen => 0,
+ last_log_ts => T0,
+ last_op => sync,
+ burst_win_ts => T0,
+ burst_msg_count => 0}),
+ Config1 =
+ Config#{config => HConfig#{handler_pid => self(),
+ mode_tab => ModeTab}},
+ proc_lib:init_ack({ok,self(),Config1}),
+ gen_server:cast(self(), repeated_filesync),
+ enter_loop(Config1, State1)
+ catch
+ _:Error ->
+ unregister(RegName),
+ logger_h_common:error_notify({init_handler,Name,Error}),
+ proc_lib:init_ack(Error)
+ end;
Error ->
+ unregister(RegName),
logger_h_common:error_notify({init_handler,Name,Error}),
proc_lib:init_ack(Error)
end.
-do_init(Name, Std) when Std=:=standard_io; Std=:=standard_error ->
- case open_log_file(Name, Std) of
- {ok,FileCtrlPid} ->
- {ok,#{id=>Name,type=>Std,file_ctrl_pid=>FileCtrlPid}};
- Error ->
- Error
- end;
-do_init(Name, FileInfo) when is_tuple(FileInfo) ->
- case open_log_file(Name, FileInfo) of
+do_init(Name, Type) ->
+ case open_log_file(Name, Type) of
{ok,FileCtrlPid} ->
- {ok,#{id=>Name,type=>FileInfo,file_ctrl_pid=>FileCtrlPid}};
+ case logger_h_common:unset_restart_flag(Name, ?MODULE) of
+ true ->
+ %% inform about restart
+ gen_server:cast(self(), {log_handler_info,
+ "Handler ~p restarted",
+ [Name]});
+ false ->
+ %% initial start
+ ok
+ end,
+ {ok,#{id=>Name,type=>Type,file_ctrl_pid=>FileCtrlPid}};
Error ->
Error
end.
-enter_loop(#{wait_for_buffer:=true}=Config,State) ->
- State1 =
- receive
- {buffer,Buffer} ->
- lists:foldl(
- fun(Log,S) ->
- Bin = logger_h_common:log_to_binary(Log,Config),
- {_,S1} = do_log(Bin,cast,S),
- S1
- end,
- State,
- Buffer)
- end,
- gen_server:enter_loop(?MODULE,[],State1);
enter_loop(_Config,State) ->
gen_server:enter_loop(?MODULE,[],State).
-%% This is the synchronous log request.
+%% This is the synchronous log event.
handle_call({log, Bin}, _From, State) ->
{Result,State1} = do_log(Bin, call, State),
%% Result == ok | dropped
@@ -310,13 +304,12 @@ handle_call(filesync, _From, State = #{type := Type,
if is_atom(Type) ->
{reply, ok, State};
true ->
- {reply, file_ctrl_filesync_sync(FileCtrlPid), State}
+ {reply, file_ctrl_filesync_sync(FileCtrlPid), State#{last_op=>sync}}
end;
handle_call({change_config,_OldConfig,NewConfig}, _From,
- State = #{filesync_repeat_interval := FSyncInt0,
- last_log_ts := LastLogTS}) ->
- HConfig = maps:get(?MODULE, NewConfig, #{}),
+ State = #{filesync_repeat_interval := FSyncInt0}) ->
+ HConfig = maps:get(config, NewConfig, #{}),
State1 = maps:merge(State, HConfig),
case logger_h_common:overload_levels_ok(State1) of
true ->
@@ -334,15 +327,14 @@ handle_call({change_config,_OldConfig,NewConfig}, _From,
_ = logger_h_common:cancel_timer(maps:get(rep_sync_tref,
State,
undefined)),
- gen_server:cast(self(), {repeated_filesync,
- LastLogTS})
+ gen_server:cast(self(), repeated_filesync)
end,
{reply, ok, State1};
false ->
- #{toggle_sync_qlen := TSQL,
- drop_new_reqs_qlen := DNRQL,
- flush_reqs_qlen := FRQL} = State1,
- {reply, {error,{invalid_levels,{TSQL,DNRQL,FRQL}}}, State}
+ #{sync_mode_qlen := SMQL,
+ drop_mode_qlen := DMQL,
+ flush_qlen := FQL} = State1,
+ {reply, {error,{invalid_levels,{SMQL,DMQL,FQL}}}, State}
end;
handle_call(info, _From, State) ->
@@ -356,33 +348,37 @@ handle_call(reset, _From, State) ->
handle_call(stop, _From, State) ->
{stop, {shutdown,stopped}, ok, State}.
-%% This is the asynchronous log request.
+%% This is the asynchronous log event.
handle_cast({log, Bin}, State) ->
{_,State1} = do_log(Bin, cast, State),
{noreply, State1};
+handle_cast({log_handler_info, Format, Args}, State = #{id:=Name}) ->
+ log_handler_info(Name, Format, Args, State),
+ {noreply, State};
+
%% If FILESYNC_REPEAT_INTERVAL is set to a millisec value, this
%% clause gets called repeatedly by the handler. In order to
%% guarantee that a filesync *always* happens after the last log
-%% request, the repeat operation must be active!
-handle_cast({repeated_filesync,LastLogTS0},
+%% event, the repeat operation must be active!
+handle_cast(repeated_filesync,
State = #{type := Type,
file_ctrl_pid := FileCtrlPid,
filesync_repeat_interval := FSyncInt,
- last_log_ts := LastLogTS1}) ->
+ last_op := LastOp}) ->
State1 =
if not is_atom(Type), is_integer(FSyncInt) ->
%% only do filesync if something has been
%% written since last time we checked
- if LastLogTS1 == LastLogTS0 ->
+ if LastOp == sync ->
ok;
true ->
file_ctrl_filesync_async(FileCtrlPid)
end,
{ok,TRef} =
timer:apply_after(FSyncInt, gen_server,cast,
- [self(),{repeated_filesync,LastLogTS1}]),
- State#{rep_sync_tref => TRef};
+ [self(),repeated_filesync]),
+ State#{rep_sync_tref => TRef, last_op => sync};
true ->
State
end,
@@ -422,6 +418,7 @@ terminate(Reason, State = #{id:=Name, file_ctrl_pid:=FWPid,
false ->
ok
end,
+ unregister(?name_to_reg_name(?MODULE, Name)),
logger_h_common:stop_or_restart(Name, Reason, State).
code_change(_OldVsn, State, _Extra) ->
@@ -434,19 +431,19 @@ code_change(_OldVsn, State, _Extra) ->
%%%-----------------------------------------------------------------
%%%
get_init_state() ->
- #{toggle_sync_qlen => ?TOGGLE_SYNC_QLEN,
- drop_new_reqs_qlen => ?DROP_NEW_REQS_QLEN,
- flush_reqs_qlen => ?FLUSH_REQS_QLEN,
- enable_burst_limit => ?ENABLE_BURST_LIMIT,
- burst_limit_size => ?BURST_LIMIT_SIZE,
- burst_window_time => ?BURST_WINDOW_TIME,
- enable_kill_overloaded => ?ENABLE_KILL_OVERLOADED,
- handler_overloaded_qlen => ?HANDLER_OVERLOADED_QLEN,
- handler_overloaded_mem => ?HANDLER_OVERLOADED_MEM,
- handler_restart_after => ?HANDLER_RESTART_AFTER,
- file_ctrl_sync_int => ?CONTROLLER_SYNC_INTERVAL,
- filesync_ok_qlen => ?FILESYNC_OK_QLEN,
- filesync_repeat_interval => ?FILESYNC_REPEAT_INTERVAL}.
+ #{sync_mode_qlen => ?SYNC_MODE_QLEN,
+ drop_mode_qlen => ?DROP_MODE_QLEN,
+ flush_qlen => ?FLUSH_QLEN,
+ burst_limit_enable => ?BURST_LIMIT_ENABLE,
+ burst_limit_max_count => ?BURST_LIMIT_MAX_COUNT,
+ burst_limit_window_time => ?BURST_LIMIT_WINDOW_TIME,
+ overload_kill_enable => ?OVERLOAD_KILL_ENABLE,
+ overload_kill_qlen => ?OVERLOAD_KILL_QLEN,
+ overload_kill_mem_size => ?OVERLOAD_KILL_MEM_SIZE,
+ overload_kill_restart_after => ?OVERLOAD_KILL_RESTART_AFTER,
+ file_ctrl_sync_int => ?CONTROLLER_SYNC_INTERVAL,
+ filesync_ok_qlen => ?FILESYNC_OK_QLEN,
+ filesync_repeat_interval => ?FILESYNC_REPEAT_INTERVAL}.
%%%-----------------------------------------------------------------
%%% Add a standard handler to the logger.
@@ -455,9 +452,9 @@ get_init_state() ->
%%% exist if the handler is not registered).
%%%
%%% Handler specific config should be provided with a sub map associated
-%%% with a key named the same as this module, e.g:
+%%% with a key named 'config', e.g:
%%%
-%%% Config = #{logger_std_h => #{toggle_sync_qlen => 50}
+%%% Config = #{config => #{sync_mode_qlen => 50}
%%%
%%% The standard handler process is linked to logger_sup, which is
%%% part of the kernel application's supervision tree.
@@ -470,8 +467,9 @@ start(Name, Config, HandlerState) ->
type => worker,
modules => [?MODULE]},
case supervisor:start_child(logger_sup, LoggerStdH) of
- {ok,_Pid} ->
- ok;
+ {ok,Pid,Config1} ->
+ ok = logger_handler_watcher:register_handler(Name,Pid),
+ {ok,Config1};
Error ->
Error
end.
@@ -479,17 +477,20 @@ start(Name, Config, HandlerState) ->
%%%-----------------------------------------------------------------
%%% Stop and remove the handler.
stop(Name) ->
- case whereis(Name) of
+ case whereis(?name_to_reg_name(?MODULE,Name)) of
undefined ->
ok;
- _ ->
+ Pid ->
%% We don't want to do supervisor:terminate_child here
%% since we need to distinguish this explicit stop from a
%% system termination in order to avoid circular attempts
%% at removing the handler (implying deadlocks and
%% timeouts).
- _ = gen_server:call(Name,stop),
- _ = supervisor:delete_child(logger_sup, Name),
+ %% And we don't need to do supervisor:delete_child, since
+ %% the restart type is temporary, which means that the
+ %% child specification is automatically removed from the
+ %% supervisor when the process dies.
+ _ = gen_server:call(Pid, stop),
ok
end.
@@ -499,21 +500,31 @@ stop(Name) ->
if C == 0 -> Interval;
true -> C-1 end).
-%% check for overload between every request (and set Mode to async,
+%% check for overload between every event (and set Mode to async,
%% sync or drop accordingly), but never flush the whole mailbox
-%% before LogWindowSize requests have been handled
-do_log(Bin, CallOrCast, State = #{id:=Name}) ->
+%% before LogWindowSize events have been handled
+do_log(Bin, CallOrCast, State = #{id:=Name, mode:=Mode0}) ->
T1 = ?timestamp(),
%% check if the handler is getting overloaded, or if it's
%% recovering from overload (the check must be done for each
- %% request to react quickly to large bursts of requests and
+ %% event to react quickly to large bursts of events and
%% to ensure that the handler can never end up in drop mode
%% with an empty mailbox, which would stop operation)
{Mode1,QLen,Mem,State1} = logger_h_common:check_load(State),
+ if (Mode1 == drop) andalso (Mode0 =/= drop) ->
+ log_handler_info(Name, "Handler ~p switched to drop mode",
+ [Name], State);
+ (Mode0 == drop) andalso ((Mode1 == async) orelse (Mode1 == sync)) ->
+ log_handler_info(Name, "Handler ~p switched to ~w mode",
+ [Name,Mode1], State);
+ true ->
+ ok
+ end,
+
%% kill the handler if it can't keep up with the load
- logger_h_common:kill_if_choked(Name, QLen, Mem, State),
+ logger_h_common:kill_if_choked(Name, QLen, Mem, ?MODULE, State),
if Mode1 == flush ->
flush(Name, QLen, T1, State1);
@@ -523,10 +534,14 @@ do_log(Bin, CallOrCast, State = #{id:=Name}) ->
%% this clause is called by do_log/3 after an overload check
%% has been performed, where QLen > FlushQLen
-flush(Name, _QLen0, T1, State=#{last_log_ts := _T0}) ->
+flush(Name, _QLen0, T1, State=#{last_log_ts := _T0, mode_tab := ModeTab}) ->
%% flush messages in the mailbox (a limited number in
%% order to not cause long delays)
- _NewFlushed = logger_h_common:flush_log_requests(?FLUSH_MAX_N),
+ NewFlushed = logger_h_common:flush_log_events(?FLUSH_MAX_N),
+
+ %% write info in log about flushed messages
+ log_handler_info(Name, "Handler ~p flushed ~w log events",
+ [Name,NewFlushed], State),
%% because of the receive loop when flushing messages, the
%% handler will be scheduled out often and the mailbox could
@@ -534,50 +549,51 @@ flush(Name, _QLen0, T1, State=#{last_log_ts := _T0}) ->
{_,_QLen1} = process_info(self(), message_queue_len),
?observe(Name,{max_qlen,_QLen1}),
- %% Add 1 for the current log request
- ?observe(Name,{flushed,_NewFlushed+1}),
+ %% Add 1 for the current log event
+ ?observe(Name,{flushed,NewFlushed+1}),
State1 = ?update_max_time(?diff_time(T1,_T0),State),
- {dropped,?update_other(flushed,FLUSHED,_NewFlushed,
- State1#{mode => ?set_mode(Name,async),
+ {dropped,?update_other(flushed,FLUSHED,NewFlushed,
+ State1#{mode => ?set_mode(ModeTab,async),
last_qlen => 0,
last_log_ts => T1})}.
%% this clause is called to write to file
-write(Name, Mode, T1, Bin, _CallOrCast,
- State = #{file_ctrl_pid := FileCtrlPid,
+write(_Name, Mode, T1, Bin, _CallOrCast,
+ State = #{mode_tab := ModeTab,
+ file_ctrl_pid := FileCtrlPid,
file_ctrl_sync := FileCtrlSync,
last_qlen := LastQLen,
last_log_ts := T0,
file_ctrl_sync_int := FileCtrlSyncInt}) ->
%% check if we need to limit the number of writes
- %% during a burst of log requests
+ %% during a burst of log events
{DoWrite,BurstWinT,BurstMsgCount} = logger_h_common:limit_burst(State),
- %% only send a synhrounous request to the file controller process
+ %% only send a synhrounous event to the file controller process
%% every FileCtrlSyncInt time, to give the handler time between
%% file writes so it can keep up with incoming messages
{Result,LastQLen1} =
if DoWrite, FileCtrlSync == 0 ->
- ?observe(Name,{_CallOrCast,1}),
+ ?observe(_Name,{_CallOrCast,1}),
file_write_sync(FileCtrlPid, Bin, false),
{ok,element(2, process_info(self(), message_queue_len))};
DoWrite ->
- ?observe(Name,{_CallOrCast,1}),
+ ?observe(_Name,{_CallOrCast,1}),
file_write_async(FileCtrlPid, Bin),
{ok,LastQLen};
not DoWrite ->
- ?observe(Name,{flushed,1}),
+ ?observe(_Name,{flushed,1}),
{dropped,LastQLen}
end,
- %% Check if the time since the previous log request is long enough -
+ %% Check if the time since the previous log event is long enough -
%% and the queue length small enough - to assume the mailbox has
%% been emptied, and if so, do filesync operation and reset mode to
%% async. Note that this is the best we can do to detect an idle
%% handler without setting a timer after each log call/cast. If the
- %% time between two consecutive log requests is fast and no new
- %% request comes in after the last one, idle state won't be detected!
+ %% time between two consecutive log events is fast and no new
+ %% event comes in after the last one, idle state won't be detected!
Time = ?diff_time(T1,T0),
{Mode1,BurstMsgCount1} =
if (LastQLen1 < ?FILESYNC_OK_QLEN) andalso
@@ -589,7 +605,7 @@ write(Name, Mode, T1, Bin, _CallOrCast,
_File ->
file_ctrl_filesync_async(FileCtrlPid)
end,
- {?change_mode(Name, Mode, async),0};
+ {?change_mode(ModeTab, Mode, async),0};
true ->
{Mode,BurstMsgCount}
end,
@@ -600,6 +616,7 @@ write(Name, Mode, T1, Bin, _CallOrCast,
State1#{mode => Mode1,
last_qlen := LastQLen1,
last_log_ts => T1,
+ last_op => write,
burst_win_ts => BurstWinT,
burst_msg_count => BurstMsgCount1,
file_ctrl_sync =>
@@ -637,6 +654,20 @@ close_log_file(Fd) ->
_ = file:datasync(Fd),
_ = file:close(Fd).
+
+log_handler_info(Name, Format, Args, #{file_ctrl_pid := FileCtrlPid}) ->
+ Config =
+ case logger:get_handler_config(Name) of
+ {ok,Conf} -> Conf;
+ _ -> #{formatter=>{?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}}
+ end,
+ Meta = #{time=>erlang:system_time(microsecond)},
+ Bin = logger_h_common:log_to_binary(#{level => notice,
+ msg => {Format,Args},
+ meta => Meta}, Config),
+ _ = file_write_async(FileCtrlPid, Bin),
+ ok.
+
%%%-----------------------------------------------------------------
%%% File control process
@@ -709,7 +740,7 @@ file_ctrl_init(HandlerName, StdDev, Starter) ->
file_ctrl_loop(Fd, Type, DevName, Synced,
PrevWriteResult, PrevSyncResult, HandlerName) ->
receive
- %% asynchronous request
+ %% asynchronous event
{log,Bin} ->
Result = if Type == file ->
write_to_dev(Fd, Bin, DevName,
@@ -720,7 +751,7 @@ file_ctrl_loop(Fd, Type, DevName, Synced,
file_ctrl_loop(Fd, Type, DevName, false,
Result, PrevSyncResult, HandlerName);
- %% synchronous request
+ %% synchronous event
{{log,From,Bin,FileSync},MRef} ->
if Type == file ->
%% check that file hasn't been deleted
diff --git a/lib/kernel/src/logger_sup.erl b/lib/kernel/src/logger_sup.erl
index 4e4de94d5c..3d6f482e20 100644
--- a/lib/kernel/src/logger_sup.erl
+++ b/lib/kernel/src/logger_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -46,7 +46,11 @@ init([]) ->
intensity => 1,
period => 5},
- {ok, {SupFlags, []}}.
+ Watcher = #{id => logger_handler_watcher,
+ start => {logger_handler_watcher, start_link, []},
+ shutdown => brutal_kill},
+
+ {ok, {SupFlags, [Watcher]}}.
%%%===================================================================
%%% Internal functions
diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl
index 669adefdf8..bea08242d8 100644
--- a/lib/kernel/src/net_kernel.erl
+++ b/lib/kernel/src/net_kernel.erl
@@ -53,7 +53,7 @@
%% Documented API functions.
--export([allow/1,
+-export([allow/1, allowed/0,
connect_node/1,
monitor_nodes/1,
monitor_nodes/2,
@@ -171,6 +171,8 @@ kernel_apply(M,F,A) -> request({apply,M,F,A}).
Nodes :: [node()].
allow(Nodes) -> request({allow, Nodes}).
+allowed() -> request(allowed).
+
longnames() -> request(longnames).
-spec stop() -> ok | {error, Reason} when
@@ -470,7 +472,7 @@ handle_call({passive_cnct, Node}, From, State) ->
%% Explicit connect
%% The response is delayed until the connection is up and running.
%%
-handle_call({connect, _, Node, _, _}, From, State) when Node =:= node() ->
+handle_call({connect, _, Node}, From, State) when Node =:= node() ->
async_reply({reply, true, State}, From);
handle_call({connect, Type, Node}, From, State) ->
verbose({connect, Type, Node}, 1, State),
@@ -528,6 +530,9 @@ handle_call({allow, Nodes}, From, State) ->
async_reply({reply,error,State}, From)
end;
+handle_call(allowed, From, #state{allowed = Allowed} = State) ->
+ async_reply({reply,{ok,Allowed},State}, From);
+
%%
%% authentication, used by auth. Simply works as this:
%% if the message comes through, the other node IS authorized.
diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl
index 77c883f57f..29a26674ba 100644
--- a/lib/kernel/src/os.erl
+++ b/lib/kernel/src/os.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/src/seq_trace.erl b/lib/kernel/src/seq_trace.erl
index 8d7aba0f27..14fe21e9de 100644
--- a/lib/kernel/src/seq_trace.erl
+++ b/lib/kernel/src/seq_trace.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/src/user_drv.erl b/lib/kernel/src/user_drv.erl
index 99ea4210bd..9f914aa222 100644
--- a/lib/kernel/src/user_drv.erl
+++ b/lib/kernel/src/user_drv.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile
index 8599a3d814..4a86265a4a 100644
--- a/lib/kernel/test/Makefile
+++ b/lib/kernel/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -71,14 +71,14 @@ MODULES= \
init_SUITE \
kernel_config_SUITE \
logger_SUITE \
- logger_bench_SUITE \
logger_disk_log_h_SUITE \
logger_env_var_SUITE \
logger_filters_SUITE \
logger_formatter_SUITE \
logger_legacy_SUITE \
- logger_simple_SUITE \
+ logger_simple_h_SUITE \
logger_std_h_SUITE \
+ logger_test_lib \
os_SUITE \
pg2_SUITE \
seq_trace_SUITE \
diff --git a/lib/kernel/test/application_SUITE.erl b/lib/kernel/test/application_SUITE.erl
index c00fb44c46..5c35b82207 100644
--- a/lib/kernel/test/application_SUITE.erl
+++ b/lib/kernel/test/application_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -37,7 +37,8 @@
-export([config_change/1, persistent_env/1,
distr_changed_tc1/1, distr_changed_tc2/1,
ensure_started/1, ensure_all_started/1,
- shutdown_func/1, do_shutdown/1, shutdown_timeout/1, shutdown_deadlock/1]).
+ shutdown_func/1, do_shutdown/1, shutdown_timeout/1, shutdown_deadlock/1,
+ config_relative_paths/1]).
-define(TESTCASE, testcase_name).
-define(testcase, proplists:get_value(?TESTCASE, Config)).
@@ -55,7 +56,7 @@ all() ->
script_start, nodedown_start, permit_false_start_local,
permit_false_start_dist, get_key, get_env, ensure_all_started,
{group, distr_changed}, config_change, shutdown_func, shutdown_timeout,
- shutdown_deadlock,
+ shutdown_deadlock, config_relative_paths,
persistent_env].
groups() ->
@@ -1603,8 +1604,7 @@ get_key(Conf) when is_list(Conf) ->
{ok, [{init, [kalle]}, {takeover, []}, {go, [sune]}]} =
rpc:call(Cp1, application, get_key, [appinc, start_phases]),
{ok, Env} = rpc:call(Cp1, application, get_key, [appinc ,env]),
- [{included_applications,[appinc1,appinc2]},
- {own2,val2},{own_env1,value1}] = lists:sort(Env),
+ [{own2,val2},{own_env1,value1}] = lists:sort(Env),
{ok, []} = rpc:call(Cp1, application, get_key, [appinc, modules]),
{ok, {application_starter, [ch_sup, {appinc, 41, 43}] }} =
rpc:call(Cp1, application, get_key, [appinc, mod]),
@@ -1625,8 +1625,7 @@ get_key(Conf) when is_list(Conf) ->
{mod, {application_starter, [ch_sup, {appinc, 41, 43}] }},
{start_phases, [{init, [kalle]}, {takeover, []}, {go, [sune]}]}]} =
rpc:call(Cp1, application, get_all_key, [appinc]),
- [{included_applications,[appinc1,appinc2]},
- {own2,val2},{own_env1,value1}] = lists:sort(Env),
+ [{own2,val2},{own_env1,value1}] = lists:sort(Env),
{ok, "Test of new app file, including appnew"} =
gen_server:call({global, {ch,41}}, {get_pid_key, description}),
@@ -1643,8 +1642,7 @@ get_key(Conf) when is_list(Conf) ->
{ok, [{init, [kalle]}, {takeover, []}, {go, [sune]}]} =
gen_server:call({global, {ch,41}}, {get_pid_key, start_phases}),
{ok, Env} = gen_server:call({global, {ch,41}}, {get_pid_key, env}),
- [{included_applications,[appinc1,appinc2]},
- {own2,val2},{own_env1,value1}] = lists:sort(Env),
+ [{own2,val2},{own_env1,value1}] = lists:sort(Env),
{ok, []} =
gen_server:call({global, {ch,41}}, {get_pid_key, modules}),
{ok, {application_starter, [ch_sup, {appinc, 41, 43}] }} =
@@ -1671,8 +1669,7 @@ get_key(Conf) when is_list(Conf) ->
{mod, {application_starter, [ch_sup, {appinc, 41, 43}] }},
{start_phases, [{init, [kalle]}, {takeover, []}, {go, [sune]}]}]} =
gen_server:call({global, {ch,41}}, get_pid_all_key),
- [{included_applications,[appinc1,appinc2]},
- {own2,val2},{own_env1,value1}] = lists:sort(Env),
+ [{own2,val2},{own_env1,value1}] = lists:sort(Env),
stop_node_nice(Cp1),
ok.
@@ -2079,6 +2076,42 @@ shutdown_deadlock(Config) when is_list(Config) ->
%%-----------------------------------------------------------------
+%% Relative paths in sys.config
+%%-----------------------------------------------------------------
+config_relative_paths(Config) ->
+ Dir = ?config(priv_dir,Config),
+ SubDir = filename:join(Dir,"subdir"),
+ Sys = filename:join(SubDir,"sys.config"),
+ ok = filelib:ensure_dir(Sys),
+ ok = file:write_file(Sys,"[\"../up.config\",\"current\"].\n"),
+
+ Up = filename:join(Dir,"up.config"),
+ ok = file:write_file(Up,"[{app1,[{key1,value}]}].\n"),
+
+ {ok,Cwd} = file:get_cwd(),
+ Current1 = filename:join(Cwd,"current.config"),
+ ok = file:write_file(Current1,"[{app1,[{key2,value1}]}].\n"),
+
+ N1 = list_to_atom(lists:concat([?FUNCTION_NAME,"_1"])),
+ {ok,Node1} = start_node(N1,filename:rootname(Sys)),
+ ok = rpc:call(Node1, application, load, [app1()]),
+ {ok, value} = rpc:call(Node1, application, get_env,[app1,key1]),
+ {ok, value1} = rpc:call(Node1, application, get_env,[app1,key2]),
+
+ Current2 = filename:join(SubDir,"current.config"),
+ ok = file:write_file(Current2,"[{app1,[{key2,value2}]}].\n"),
+
+ N2 = list_to_atom(lists:concat([?FUNCTION_NAME,"_2"])),
+ {ok, Node2} = start_node(N2,filename:rootname(Sys)),
+ ok = rpc:call(Node2, application, load, [app1()]),
+ {ok, value} = rpc:call(Node2, application, get_env,[app1,key1]),
+ {ok, value2} = rpc:call(Node2, application, get_env,[app1,key2]),
+
+ stop_node_nice([Node1,Node2]),
+
+ ok.
+
+%%-----------------------------------------------------------------
%% Utility functions
%%-----------------------------------------------------------------
app0() ->
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 902196def2..1314316c13 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/test/erl_distribution_SUITE.erl b/lib/kernel/test/erl_distribution_SUITE.erl
index 0470f09f29..0e13f0383e 100644
--- a/lib/kernel/test/erl_distribution_SUITE.erl
+++ b/lib/kernel/test/erl_distribution_SUITE.erl
@@ -25,6 +25,7 @@
init_per_group/2,end_per_group/2]).
-export([tick/1, tick_change/1,
+ connect_node/1,
nodenames/1, hostnames/1,
illegal_nodenames/1, hidden_node/1,
setopts/1,
@@ -70,6 +71,7 @@ suite() ->
all() ->
[tick, tick_change, nodenames, hostnames, illegal_nodenames,
+ connect_node,
hidden_node, setopts,
table_waste, net_setuptime, inet_dist_options_options,
{group, monitor_nodes}].
@@ -106,6 +108,12 @@ init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
end_per_testcase(_Func, _Config) ->
ok.
+connect_node(Config) when is_list(Config) ->
+ Connected = nodes(connected),
+ true = net_kernel:connect_node(node()),
+ Connected = nodes(connected),
+ ok.
+
tick(Config) when is_list(Config) ->
PaDir = filename:dirname(code:which(erl_distribution_SUITE)),
@@ -244,7 +252,7 @@ illegal(Name) ->
test_node(Name) ->
test_node(Name, false).
test_node(Name, Illigal) ->
- ProgName = atom_to_list(lib:progname()),
+ ProgName = ct:get_progname(),
Command = ProgName ++ " -noinput " ++ long_or_short() ++ Name ++
" -eval \"net_adm:ping('" ++ atom_to_list(node()) ++ "')\"" ++
case Illigal of
diff --git a/lib/kernel/test/erl_prim_loader_SUITE.erl b/lib/kernel/test/erl_prim_loader_SUITE.erl
index 3502a4ad08..16a127aa3e 100644
--- a/lib/kernel/test/erl_prim_loader_SUITE.erl
+++ b/lib/kernel/test/erl_prim_loader_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/test/error_logger_SUITE.erl b/lib/kernel/test/error_logger_SUITE.erl
index 6c4526d0cf..eab72e58a7 100644
--- a/lib/kernel/test/error_logger_SUITE.erl
+++ b/lib/kernel/test/error_logger_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@
off_heap/1,
error_report/1, info_report/1, error/1, info/1,
emulator/1, via_logger_process/1, other_node/1,
- tty/1, logfile/1, add/1, delete/1]).
+ tty/1, logfile/1, add/1, delete/1, format_depth/1]).
-export([generate_error/2]).
@@ -48,7 +48,8 @@ suite() ->
all() ->
[off_heap, error_report, info_report, error, info, emulator,
- via_logger_process, other_node, tty, logfile, add, delete].
+ via_logger_process, other_node, tty, logfile, add, delete,
+ format_depth].
groups() ->
[].
@@ -309,6 +310,21 @@ delete(Config) when is_list(Config) ->
ok.
%%-----------------------------------------------------------------
+
+format_depth(_Config) ->
+ ok = application:set_env(kernel,error_logger_format_depth,30),
+ 30 = error_logger:get_format_depth(),
+ ok = application:set_env(kernel,error_logger_format_depth,3),
+ 10 = error_logger:get_format_depth(),
+ ok = application:set_env(kernel,error_logger_format_depth,11),
+ 11 = error_logger:get_format_depth(),
+ ok = application:set_env(kernel,error_logger_format_depth,unlimited),
+ unlimited = error_logger:get_format_depth(),
+ ok = application:unset_env(kernel,error_logger_format_depth),
+ unlimited = error_logger:get_format_depth(),
+ ok.
+
+%%-----------------------------------------------------------------
%% Check that the report has been received.
%%-----------------------------------------------------------------
reported(Tag, Type, Report) ->
diff --git a/lib/kernel/test/error_logger_warn_SUITE.erl b/lib/kernel/test/error_logger_warn_SUITE.erl
index a8087e11f9..8f1eb2ba0a 100644
--- a/lib/kernel/test/error_logger_warn_SUITE.erl
+++ b/lib/kernel/test/error_logger_warn_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -480,9 +480,12 @@ rb_utc() ->
UtcLog=case application:get_env(sasl,utc_log) of
{ok,true} ->
true;
- _AllOthers ->
+ {ok,false} ->
application:set_env(sasl,utc_log,true),
- false
+ false;
+ undefined ->
+ application:set_env(sasl,utc_log,true),
+ undefined
end,
application:start(sasl),
rb:start([{report_dir, rd()}]),
@@ -494,7 +497,12 @@ rb_utc() ->
Sum=one_rb_findstr([],"UTC"),
rb:stop(),
application:stop(sasl),
- application:set_env(sasl,utc_log,UtcLog),
+ case UtcLog of
+ undefined ->
+ application:unset_env(sasl,utc_log);
+ _ ->
+ application:set_env(sasl,utc_log,UtcLog)
+ end,
stop_node(Node),
ok.
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index ff93f25e25..e784c06865 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1367,6 +1367,10 @@ file_info_basic_file(Config) when is_list(Config) ->
io:put_chars(Fd1, "foo bar"),
ok = ?FILE_MODULE:close(Fd1),
+ %% Don't crash the file server when passing incorrect arguments.
+ {error,badarg} = ?FILE_MODULE:read_file_info(Name, [{time, gurka}]),
+ {error,badarg} = ?FILE_MODULE:read_file_info([#{} | gaffel]),
+
%% Test that the file has the expected attributes.
%% The times are tricky, so we will save them to a separate test case.
{ok,FileInfo} = ?FILE_MODULE:read_file_info(Name),
diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl
index 9dde00652c..a0ae792ba9 100644
--- a/lib/kernel/test/gen_sctp_SUITE.erl
+++ b/lib/kernel/test/gen_sctp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl
index 0fe44e8a88..1be016444f 100644
--- a/lib/kernel/test/gen_tcp_api_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_api_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index e47023d201..950f5bea6f 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index 6a50239c2a..3acfff929e 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@
-export([init_per_testcase/2, end_per_testcase/2]).
-export([send_to_closed/1, active_n/1,
- buffer_size/1, binary_passive_recv/1, bad_address/1,
+ buffer_size/1, binary_passive_recv/1, max_buffer_size/1, bad_address/1,
read_packets/1, open_fd/1, connect/1, implicit_inet6/1,
local_basic/1, local_unbound/1,
local_fdopen/1, local_fdopen_unbound/1, local_abstract/1]).
@@ -44,7 +44,7 @@ suite() ->
{timetrap,{minutes,1}}].
all() ->
- [send_to_closed, buffer_size, binary_passive_recv,
+ [send_to_closed, buffer_size, binary_passive_recv, max_buffer_size,
bad_address, read_packets, open_fd, connect,
implicit_inet6, active_n,
{group, local}].
@@ -237,6 +237,14 @@ buffer_size_server_recv(Socket, IP, Port, Cnt) ->
end.
+%%-------------------------------------------------------------
+%% OTP-15206: Keep buffer small for udp
+%%-------------------------------------------------------------
+max_buffer_size(Config) when is_list(Config) ->
+ {ok, Socket} = gen_udp:open(0, [binary]),
+ ok = inet:setopts(Socket,[{recbuf, 1 bsl 20}]),
+ {ok, [{buffer, 65536}]} = inet:getopts(Socket,[buffer]),
+ gen_udp:close(Socket).
%%-------------------------------------------------------------
%% OTP-3823 gen_udp:recv does not return address in binary mode
diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl
index 22db24de5f..f5ca6d0e1d 100644
--- a/lib/kernel/test/heart_SUITE.erl
+++ b/lib/kernel/test/heart_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -168,7 +168,7 @@ reboot(Config) when is_list(Config) ->
{ok, Node} = start_check(slave, ?UNIQ_NODE_NAME),
ok = rpc:call(Node, heart, set_cmd,
- [atom_to_list(lib:progname()) ++
+ [ct:get_progname() ++
" -noshell -heart " ++ name(Node) ++ "&"]),
rpc:call(Node, init, reboot, []),
receive
@@ -203,7 +203,7 @@ node_start_immediately_after_crash_test(Config) when is_list(Config) ->
[{"ERL_CRASH_DUMP_SECONDS", "0"}]),
ok = rpc:call(Node, heart, set_cmd,
- [atom_to_list(lib:progname()) ++
+ [ct:get_progname() ++
" -noshell -heart " ++ name(Node) ++ "&"]),
Mod = exhaust_atoms,
@@ -254,7 +254,7 @@ node_start_soon_after_crash_test(Config) when is_list(Config) ->
[{"ERL_CRASH_DUMP_SECONDS", "10"}]),
ok = rpc:call(Node, heart, set_cmd,
- [atom_to_list(lib:progname()) ++
+ [ct:get_progname() ++
" -noshell -heart " ++ name(Node) ++ "&"]),
Mod = exhaust_atoms,
@@ -309,7 +309,7 @@ set_cmd(Config) when is_list(Config) ->
clear_cmd(Config) when is_list(Config) ->
{ok, Node} = start_check(slave, ?UNIQ_NODE_NAME),
ok = rpc:call(Node, heart, set_cmd,
- [atom_to_list(lib:progname()) ++
+ [ct:get_progname() ++
" -noshell -heart " ++ name(Node) ++ "&"]),
rpc:call(Node, init, reboot, []),
receive
diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
index 2e5f8c7d2c..713de8c9a8 100644
--- a/lib/kernel/test/inet_SUITE.erl
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -97,7 +97,7 @@ end_per_group(_GroupName, Config) ->
init_per_testcase(lookup_bad_search_option, Config) ->
Db = inet_db,
Key = res_lookup,
- %% The bad option can not enter through inet_db:set_lookup/1,
+ %% The bad option cannot enter through inet_db:set_lookup/1,
%% but through e.g .inetrc.
Prev = ets:lookup(Db, Key),
ets:delete(Db, Key),
diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl
index 2a5b8d0044..cbec8d430c 100644
--- a/lib/kernel/test/inet_res_SUITE.erl
+++ b/lib/kernel/test/inet_res_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -531,7 +531,7 @@ edns0(Config) when is_list(Config) ->
case os:version() of
{M,V,_} when M < 5; M == 5, V =< 8 ->
%% In our test park only known platform
- %% with an DNS resolver that can not do
+ %% with an DNS resolver that cannot do
%% EDNS0.
{comment,"No EDNS0"}
end
diff --git a/lib/kernel/test/kernel.spec b/lib/kernel/test/kernel.spec
index 86d2155828..62afc9f97b 100644
--- a/lib/kernel/test/kernel.spec
+++ b/lib/kernel/test/kernel.spec
@@ -2,4 +2,3 @@
{config, "../test_server/ts.unix.config"}.
{suites,"../kernel_test", all}.
-{skip_suites,"../kernel_test",[logger_bench_SUITE],"Not ready"}.
diff --git a/lib/kernel/test/kernel_SUITE.erl b/lib/kernel/test/kernel_SUITE.erl
index 7898988dbe..3e5ed855b5 100644
--- a/lib/kernel/test/kernel_SUITE.erl
+++ b/lib/kernel/test/kernel_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/test/kernel_config_SUITE.erl b/lib/kernel/test/kernel_config_SUITE.erl
index 9a4578917d..9207025a2c 100644
--- a/lib/kernel/test/kernel_config_SUITE.erl
+++ b/lib/kernel/test/kernel_config_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -76,7 +76,7 @@ sync(Conf) when is_list(Conf) ->
%% Reset wall_clock
{T1,_} = erlang:statistics(wall_clock),
io:format("~p~n", [{t1, T1}]),
- Command = lists:concat([lib:progname(),
+ Command = lists:append([ct:get_progname(),
" -detached -sname cp1 ",
"-config ", Config,
" -env ERL_CRASH_DUMP erl_crash_dump.cp1"]),
diff --git a/lib/kernel/test/logger.cover b/lib/kernel/test/logger.cover
index b30bcfe920..960bc0abff 100644
--- a/lib/kernel/test/logger.cover
+++ b/lib/kernel/test/logger.cover
@@ -8,7 +8,7 @@
logger_filters,
logger_formatter,
logger_server,
- logger_simple,
+ logger_simple_h,
logger_std_h,
logger_sup]}.
diff --git a/lib/kernel/test/logger.spec b/lib/kernel/test/logger.spec
index cd76a754a4..1ab90b3e93 100644
--- a/lib/kernel/test/logger.spec
+++ b/lib/kernel/test/logger.spec
@@ -7,5 +7,5 @@
logger_filters_SUITE,
logger_formatter_SUITE,
logger_legacy_SUITE,
- logger_simple_SUITE,
+ logger_simple_h_SUITE,
logger_std_h_SUITE]}.
diff --git a/lib/kernel/test/logger_SUITE.erl b/lib/kernel/test/logger_SUITE.erl
index f311a9c7ed..6bd9b20c35 100644
--- a/lib/kernel/test/logger_SUITE.erl
+++ b/lib/kernel/test/logger_SUITE.erl
@@ -40,18 +40,18 @@ suite() ->
[{timetrap,{seconds,30}}].
init_per_suite(Config) ->
- case logger:get_handler_config(logger_std_h) of
+ case logger:get_handler_config(?STANDARD_HANDLER) of
{ok,StdH} ->
- ok = logger:remove_handler(logger_std_h),
- [{logger_std_h,StdH}|Config];
+ ok = logger:remove_handler(?STANDARD_HANDLER),
+ [{default_handler,StdH}|Config];
_ ->
Config
end.
end_per_suite(Config) ->
- case ?config(logger_std_h,Config) of
- {HMod,HConfig} ->
- ok = logger:add_handler(logger_std_h,HMod,HConfig);
+ case ?config(default_handler,Config) of
+ #{module:=HMod} = HConfig ->
+ ok = logger:add_handler(?STANDARD_HANDLER,HMod,HConfig);
_ ->
ok
end.
@@ -63,8 +63,8 @@ end_per_group(_Group, _Config) ->
ok.
init_per_testcase(_TestCase, Config) ->
- {ok,LC} = logger:get_logger_config(),
- [{logger_config,LC}|Config].
+ PC = logger:get_primary_config(),
+ [{logger_config,PC}|Config].
end_per_testcase(Case, Config) ->
try apply(?MODULE,Case,[cleanup,Config])
@@ -82,11 +82,13 @@ all() ->
add_remove_filter,
change_config,
set_formatter,
+ log_no_levels,
log_all_levels_api,
macros,
set_level,
- set_level_module,
- cache_level_module,
+ set_module_level,
+ set_application_level,
+ cache_module_level,
format_report,
filter_failed,
handler_failed,
@@ -105,29 +107,29 @@ start_stop(_Config) ->
add_remove_handler(_Config) ->
register(callback_receiver,self()),
- {ok,#{handlers:=Hs0}} = logger:get_logger_config(),
+ Hs0 = logger:get_handler_config(),
{error,{not_found,h1}} = logger:get_handler_config(h1),
ok = logger:add_handler(h1,?MODULE,#{}),
[add] = test_server:messages_get(),
- {ok,#{handlers:=Hs}} = logger:get_logger_config(),
- [h1|Hs0] = Hs,
- {ok,{?MODULE,#{level:=info,filters:=[],filter_default:=log}}} = % defaults
+ Hs = logger:get_handler_config(),
+ Hs0 = lists:filter(fun(#{id:=h1}) -> false; (_) -> true end, Hs),
+ {ok,#{module:=?MODULE,level:=all,filters:=[],filter_default:=log}} = %defaults
logger:get_handler_config(h1),
ok = logger:set_handler_config(h1,filter_default,stop),
[changing_config] = test_server:messages_get(),
- ?LOG_INFO("hello",[]),
+ ?LOG_NOTICE("hello",[]),
ok = check_no_log(),
ok = logger:set_handler_config(h1,filter_default,log),
[changing_config] = test_server:messages_get(),
- {ok,{?MODULE,#{filter_default:=log}}} = logger:get_handler_config(h1),
- ?LOG_INFO("hello",[]),
- ok = check_logged(info,"hello",[],?MY_LOC(1)),
+ {ok,#{filter_default:=log}} = logger:get_handler_config(h1),
+ ?LOG_NOTICE("hello",[]),
+ ok = check_logged(notice,"hello",[],?MY_LOC(1)),
ok = logger:remove_handler(h1),
[remove] = test_server:messages_get(),
- {ok,#{handlers:=Hs0}} = logger:get_logger_config(),
+ Hs0 = logger:get_handler_config(),
{error,{not_found,h1}} = logger:get_handler_config(h1),
{error,{not_found,h1}} = logger:remove_handler(h1),
- logger:info("hello",[]),
+ logger:notice("hello",[]),
ok = check_no_log(),
ok.
@@ -136,13 +138,13 @@ add_remove_handler(cleanup,_Config) ->
ok.
multiple_handlers(_Config) ->
- ok = logger:add_handler(h1,?MODULE,#{level=>info,filter_default=>log}),
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log}),
ok = logger:add_handler(h2,?MODULE,#{level=>error,filter_default=>log}),
?LOG_ERROR("hello",[]),
ok = check_logged(error,"hello",[],?MY_LOC(1)),
ok = check_logged(error,"hello",[],?MY_LOC(2)),
- ?LOG_INFO("hello",[]),
- ok = check_logged(info,"hello",[],?MY_LOC(1)),
+ ?LOG_NOTICE("hello",[]),
+ ok = check_logged(notice,"hello",[],?MY_LOC(1)),
ok = check_no_log(),
ok.
@@ -152,18 +154,18 @@ multiple_handlers(cleanup,_Config) ->
ok.
add_remove_filter(_Config) ->
- ok = logger:add_handler(h1,?MODULE,#{level=>info,filter_default=>log}),
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log}),
LF = {fun(Log,_) -> Log#{level=>error} end, []},
- ok = logger:add_logger_filter(lf,LF),
- {error,{already_exist,lf}} = logger:add_logger_filter(lf,LF),
- {error,{already_exist,lf}} = logger:add_logger_filter(lf,{fun(Log,_) ->
- Log
- end, []}),
- ?LOG_INFO("hello",[]),
+ ok = logger:add_primary_filter(lf,LF),
+ {error,{already_exist,lf}} = logger:add_primary_filter(lf,LF),
+ {error,{already_exist,lf}} = logger:add_primary_filter(lf,{fun(Log,_) ->
+ Log
+ end, []}),
+ ?LOG_NOTICE("hello",[]),
ok = check_logged(error,"hello",[],?MY_LOC(1)),
ok = check_no_log(),
- ok = logger:add_handler(h2,?MODULE,#{level=>info,filter_default=>log}),
+ ok = logger:add_handler(h2,?MODULE,#{level=>notice,filter_default=>log}),
HF = {fun(#{level:=error}=Log,_) ->
Log#{level=>mylevel};
(_,_) ->
@@ -175,16 +177,16 @@ add_remove_filter(_Config) ->
{error,{already_exist,hf}} = logger:add_handler_filter(h1,hf,{fun(Log,_) ->
Log
end, []}),
- ?LOG_INFO("hello",[]),
+ ?LOG_NOTICE("hello",[]),
ok = check_logged(mylevel,"hello",[],?MY_LOC(1)),
ok = check_logged(error,"hello",[],?MY_LOC(2)),
- ok = logger:remove_logger_filter(lf),
- {error,{not_found,lf}} = logger:remove_logger_filter(lf),
+ ok = logger:remove_primary_filter(lf),
+ {error,{not_found,lf}} = logger:remove_primary_filter(lf),
- ?LOG_INFO("hello",[]),
- ok = check_logged(info,"hello",[],?MY_LOC(1)),
- ok = check_logged(info,"hello",[],?MY_LOC(2)),
+ ?LOG_NOTICE("hello",[]),
+ ok = check_logged(notice,"hello",[],?MY_LOC(1)),
+ ok = check_logged(notice,"hello",[],?MY_LOC(2)),
?LOG_ERROR("hello",[]),
ok = check_logged(mylevel,"hello",[],?MY_LOC(1)),
@@ -192,9 +194,9 @@ add_remove_filter(_Config) ->
ok = logger:remove_handler_filter(h1,hf),
{error,{not_found,hf}} = logger:remove_handler_filter(h1,hf),
- ?LOG_INFO("hello",[]),
- ok = check_logged(info,"hello",[],?MY_LOC(1)),
- ok = check_logged(info,"hello",[],?MY_LOC(2)),
+ ?LOG_NOTICE("hello",[]),
+ ok = check_logged(notice,"hello",[],?MY_LOC(1)),
+ ok = check_logged(notice,"hello",[],?MY_LOC(2)),
?LOG_ERROR("hello",[]),
ok = check_logged(error,"hello",[],?MY_LOC(1)),
@@ -202,64 +204,83 @@ add_remove_filter(_Config) ->
ok.
add_remove_filter(cleanup,_Config) ->
- logger:remove_logger_filter(lf),
+ logger:remove_primary_filter(lf),
logger:remove_handler(h1),
logger:remove_handler(h2),
ok.
change_config(_Config) ->
%% Overwrite handler config - check that defaults are added
- ok = logger:add_handler(h1,?MODULE,#{level=>debug,custom=>custom}),
- {ok,{?MODULE,#{level:=debug,filter_default:=log,custom:=custom}}} =
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,custom=>custom}),
+ {ok,#{module:=?MODULE,level:=notice,filter_default:=log,custom:=custom}} =
logger:get_handler_config(h1),
register(callback_receiver,self()),
ok = logger:set_handler_config(h1,#{filter_default=>stop}),
[changing_config] = test_server:messages_get(),
- {ok,{?MODULE,#{level:=info,filter_default:=stop}=C2}} =
+ {ok,#{module:=?MODULE,level:=all,filter_default:=stop}=C2} =
logger:get_handler_config(h1),
false = maps:is_key(custom,C2),
- {error,fail} = logger:set_handler_config(h1,#{fail=>true}),
+ {error,fail} = logger:set_handler_config(h1,#{conf_call=>fun() -> {error,fail} end}),
{error,{attempting_syncronous_call_to_self,_}} =
logger:set_handler_config(
- h1,#{call=>fun() -> logger:set_module_level(?MODULE,debug) end}),
- {ok,{?MODULE,C2}} = logger:get_handler_config(h1),
+ h1,#{conf_call=>fun() -> logger:set_handler_config(?MODULE,#{}) end}),
+ ok =
+ logger:set_handler_config(
+ h1,#{conf_call=>fun() -> logger:set_module_level(?MODULE,debug) end}),
+ {ok,C2} = logger:get_handler_config(h1),
- %% Change one key only
- {error,fail} = logger:set_handler_config(h1,fail,true),
+ %% Change handler config: Single key
+ {error,fail} = logger:set_handler_config(h1,conf_call,fun() -> {error,fail} end),
ok = logger:set_handler_config(h1,custom,custom),
[changing_config] = test_server:messages_get(),
- {ok,{?MODULE,#{custom:=custom}=C3}} = logger:get_handler_config(h1),
+ {ok,#{custom:=custom}=C3} = logger:get_handler_config(h1),
C2 = maps:remove(custom,C3),
- %% Overwrite logger config - check that defaults are added
- {ok,LConfig} = logger:get_logger_config(),
- ok = logger:set_logger_config(#{filter_default=>stop}),
- {ok,#{level:=info,filters:=[],handlers:=[],filter_default:=stop}=LC1} =
- logger:get_logger_config(),
- 4 = maps:size(LC1),
-
- %% Change one key only
- ok = logger:set_logger_config(handlers,[h1]),
- {ok,#{level:=info,filters:=[],handlers:=[h1],filter_default:=stop}} =
- logger:get_logger_config(),
+ %% Change handler config: Map
+ ok = logger:update_handler_config(h1,#{custom=>new_custom}),
+ [changing_config] = test_server:messages_get(),
+ {ok,C4} = logger:get_handler_config(h1),
+ C4 = C3#{custom:=new_custom},
+
+ %% Change primary config: Single key
+ PConfig0 = logger:get_primary_config(),
+ ok = logger:set_primary_config(level,warning),
+ PConfig1 = logger:get_primary_config(),
+ PConfig1 = PConfig0#{level:=warning},
+
+ %% Change primary config: Map
+ ok = logger:update_primary_config(#{level=>error}),
+ PConfig2 = logger:get_primary_config(),
+ PConfig2 = PConfig1#{level:=error},
+
+ %% Overwrite primary config - check that defaults are added
+ ok = logger:set_primary_config(#{filter_default=>stop}),
+ #{level:=notice,filters:=[],filter_default:=stop}=PC1 =
+ logger:get_primary_config(),
+ 3 = maps:size(PC1),
+ %% Check that internal 'handlers' field has not been changed
+ MS = [{{{?HANDLER_KEY,'$1'},'_','_','_'},[],['$1']}],
+ HIds1 = lists:sort(ets:select(?LOGGER_TABLE,MS)), % dirty, internal data
+ HIds2 = lists:sort(logger:get_handler_ids()),
+ HIds1 = HIds2,
%% Cleanup
- ok = logger:set_logger_config(LConfig),
+ ok = logger:set_primary_config(PConfig0),
[] = test_server:messages_get(),
ok.
change_config(cleanup,Config) ->
logger:remove_handler(h1),
- LC = ?config(logger_config,Config),
- logger:set_logger_config(LC),
+ PC = ?config(logger_config,Config),
+ logger:set_primary_config(PC),
ok.
set_formatter(_Config) ->
{error,{not_found,h1}}=logger:set_handler_config(h1,formatter,{?MODULE,[]}),
- ok = logger:add_handler(h1,?MODULE,#{level=>info,filter_default=>log}),
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log}),
ok = logger:set_handler_config(h1,formatter,{?MODULE,[]}),
- logger:info("hello",[]),
+ logger:notice("hello",[]),
receive
{_Log,#{formatter:={?MODULE,[]}}} ->
ok
@@ -272,9 +293,50 @@ set_formatter(cleanup,_Config) ->
logger:remove_handler(h1),
ok.
+log_no_levels(_Config) ->
+ ok = logger:add_handler(h1,?MODULE,#{level=>all,filter_default=>log}),
+ logger:notice(M1=?map_rep),
+ ok = check_logged(notice,M1,#{}),
+
+ Levels = [emergency,alert,critical,error,warning,notice,info,debug],
+ ok = logger:set_primary_config(level,none),
+ [logger:Level(#{Level=>rep}) || Level <- Levels],
+ ok = check_no_log(),
+
+ ok = logger:set_primary_config(level,all),
+ M2 = ?map_rep,
+ ?LOG_NOTICE(M2),
+ ok = check_logged(notice,M2,#{}),
+
+ ok = logger:set_module_level(?MODULE,none),
+ ?LOG_EMERGENCY(?map_rep),
+ ?LOG_ALERT(?map_rep),
+ ?LOG_CRITICAL(?map_rep),
+ ?LOG_ERROR(?map_rep),
+ ?LOG_WARNING(?map_rep),
+ ?LOG_NOTICE(?map_rep),
+ ?LOG_INFO(?map_rep),
+ ?LOG_DEBUG(?map_rep),
+ ok = check_no_log(),
+
+ ok = logger:unset_module_level(?MODULE),
+ logger:notice(M3=?map_rep),
+ ok = check_logged(notice,M3,#{}),
+
+ ok = logger:set_handler_config(h1,level,none),
+ [logger:Level(#{Level=>rep}) || Level <- Levels],
+ ok = check_no_log(),
+
+ ok.
+log_no_levels(cleanup,_Config) ->
+ logger:remove_handler(h1),
+ logger:set_primary_config(level,notice),
+ logger:unset_module_level(?MODULE),
+ ok.
+
log_all_levels_api(_Config) ->
- ok = logger:set_logger_config(level,debug),
- ok = logger:add_handler(h1,?MODULE,#{level=>debug,filter_default=>log}),
+ ok = logger:set_primary_config(level,all),
+ ok = logger:add_handler(h1,?MODULE,#{level=>all,filter_default=>log}),
test_api(emergency),
test_api(alert),
test_api(critical),
@@ -288,72 +350,121 @@ log_all_levels_api(_Config) ->
log_all_levels_api(cleanup,_Config) ->
logger:remove_handler(h1),
- logger:set_logger_config(level,info),
+ logger:set_primary_config(level,notice),
ok.
macros(_Config) ->
- ok = logger:set_module_level(?MODULE,debug),
- ok = logger:add_handler(h1,?MODULE,#{level=>debug,filter_default=>log}),
+ ok = logger:add_handler(h1,?MODULE,#{level=>all,filter_default=>log}),
test_macros(emergency),
+ test_log_macro(alert),
ok.
macros(cleanup,_Config) ->
logger:remove_handler(h1),
- logger:reset_module_level(?MODULE),
+ logger:unset_module_level(?MODULE),
ok.
set_level(_Config) ->
- ok = logger:add_handler(h1,?MODULE,#{level=>debug,filter_default=>log}),
+ ok = logger:add_handler(h1,?MODULE,#{level=>all,filter_default=>log}),
logger:debug(?map_rep),
ok = check_no_log(),
- logger:info(M1=?map_rep),
- ok = check_logged(info,M1,#{}),
- ok = logger:set_logger_config(level,debug),
+ logger:notice(M1=?map_rep),
+ ok = check_logged(notice,M1,#{}),
+ ok = logger:set_primary_config(level,debug),
logger:debug(M2=?map_rep),
ok = check_logged(debug,M2,#{}),
ok.
set_level(cleanup,_Config) ->
logger:remove_handler(h1),
- logger:set_logger_config(level,info),
+ logger:set_primary_config(level,notice),
ok.
-set_level_module(_Config) ->
- ok = logger:add_handler(h1,?MODULE,#{level=>info,filter_default=>log}),
+set_module_level(_Config) ->
+ [] = logger:get_module_level([?MODULE,other]),
+ [] = logger:get_module_level(?MODULE),
+ [] = logger:get_module_level(),
+
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log}),
{error,{invalid_level,bad}} = logger:set_module_level(?MODULE,bad),
- {error,{not_a_module,{bad}}} = logger:set_module_level({bad},warning),
+ {error,{not_a_list_of_modules,{bad}}} =
+ logger:set_module_level({bad},warning),
ok = logger:set_module_level(?MODULE,warning),
- logger:info(?map_rep,?MY_LOC(0)),
+ [{?MODULE,warning}] = logger:get_module_level([?MODULE,other]),
+ [{?MODULE,warning}] = logger:get_module_level(?MODULE),
+ [{?MODULE,warning}] = logger:get_module_level(),
+ logger:notice(?map_rep,?MY_LOC(0)),
ok = check_no_log(),
logger:warning(M1=?map_rep,?MY_LOC(0)),
ok = check_logged(warning,M1,?MY_LOC(1)),
- ok = logger:set_module_level(?MODULE,info),
- logger:info(M2=?map_rep,?MY_LOC(0)),
- ok = check_logged(info,M2,?MY_LOC(1)),
-
- {error,{not_a_module,{bad}}} = logger:reset_module_level({bad}),
- ok = logger:reset_module_level(?MODULE),
+ ok = logger:set_module_level(?MODULE,notice),
+ [{?MODULE,notice}] = logger:get_module_level([?MODULE,other]),
+ [{?MODULE,notice}] = logger:get_module_level(?MODULE),
+ [{?MODULE,notice}] = logger:get_module_level(),
+ logger:notice(M2=?map_rep,?MY_LOC(0)),
+ ok = check_logged(notice,M2,?MY_LOC(1)),
+
+ {error,{not_a_list_of_modules,{bad}}} = logger:unset_module_level({bad}),
+ ok = logger:unset_module_level(?MODULE),
+ [] = logger:get_module_level([?MODULE,other]),
+ [] = logger:get_module_level(?MODULE),
+ [] = logger:get_module_level(),
+
+ ok = logger:set_module_level([m1,m2,m3],notice),
+ [{m1,notice},{m2,notice},{m3,notice}] = logger:get_module_level(),
+ ok = logger:unset_module_level(m2),
+ [{m1,notice},{m3,notice}] = logger:get_module_level(),
+ ok = logger:unset_module_level(),
+ [] = logger:get_module_level(),
ok.
-set_level_module(cleanup,_Config) ->
+set_module_level(cleanup,_Config) ->
logger:remove_handler(h1),
- logger:reset_module_level(?MODULE),
+ logger:unset_module_level(?MODULE),
ok.
-cache_level_module(_Config) ->
- ok = logger:reset_module_level(?MODULE),
- [] = ets:lookup(logger,?MODULE), %dirty - add API in logger_config?
- ?LOG_INFO(?map_rep),
+set_application_level(_Config) ->
+
+ {error,{not_loaded,mnesia}} = logger:set_application_level(mnesia, warning),
+ {error,{not_loaded,mnesia}} = logger:unset_application_level(mnesia),
+
+ application:load(mnesia),
+ {ok, Modules} = application:get_key(mnesia, modules),
+ [] = logger:get_module_level(Modules),
+
+ {error,{invalid_level,warn}} = logger:set_application_level(mnesia, warn),
+
+ ok = logger:set_application_level(mnesia, debug),
+ DebugModules = lists:sort([{M,debug} || M <- Modules]),
+ DebugModules = lists:sort(logger:get_module_level(Modules)),
+
+ ok = logger:set_application_level(mnesia, warning),
+
+ WarnModules = lists:sort([{M,warning} || M <- Modules]),
+ WarnModules = lists:sort(logger:get_module_level(Modules)),
+
+ ok = logger:unset_application_level(mnesia),
+ [] = logger:get_module_level(Modules).
+
+set_application_level(cleanup,_Config) ->
+ ok = logger:unset_application_level(mnesia),
+ ok = application:unload(mnesia),
+ ok.
+
+cache_module_level(_Config) ->
+ ok = logger:unset_module_level(?MODULE),
+ [] = ets:lookup(?LOGGER_TABLE,?MODULE), %dirty - add API in logger_config?
+ ?LOG_NOTICE(?map_rep),
%% Caching is done asynchronously, so wait a bit for the update
timer:sleep(100),
- [_] = ets:lookup(logger,?MODULE), %dirty - add API in logger_config?
- ok = logger:reset_module_level(?MODULE),
- [] = ets:lookup(logger,?MODULE), %dirty - add API in logger_config?
+ [_] = ets:lookup(?LOGGER_TABLE,?MODULE), %dirty - add API in logger_config?
+ ok = logger:unset_module_level(?MODULE),
+ [] = ets:lookup(?LOGGER_TABLE,?MODULE), %dirty - add API in logger_config?
ok.
-cache_level_module(cleanup,_Config) ->
- logger:reset_module_level(?MODULE),
+cache_module_level(cleanup,_Config) ->
+ logger:unset_module_level(?MODULE),
ok.
format_report(_Config) ->
@@ -383,22 +494,26 @@ format_report(_Config) ->
ok.
filter_failed(_Config) ->
- ok = logger:add_handler(h1,?MODULE,#{level=>info,filter_default=>log}),
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log}),
%% Logger filters
{error,{invalid_filter,_}} =
- logger:add_logger_filter(lf,{fun(_) -> ok end,args}),
- ok = logger:add_logger_filter(lf,{fun(_,_) -> a=b end,args}),
- {ok,#{filters:=[_]}} = logger:get_logger_config(),
- ok = logger:info(M1=?map_rep),
- ok = check_logged(info,M1,#{}),
- {error,{not_found,lf}} = logger:remove_logger_filter(lf),
-
- ok = logger:add_logger_filter(lf,{fun(_,_) -> faulty_return end,args}),
- {ok,#{filters:=[_]}} = logger:get_logger_config(),
- ok = logger:info(M2=?map_rep),
- ok = check_logged(info,M2,#{}),
- {error,{not_found,lf}} = logger:remove_logger_filter(lf),
+ logger:add_primary_filter(lf,{fun(_) -> ok end,args}),
+ ok = logger:add_primary_filter(lf,
+ {fun(_,_) ->
+ erlang:error({badmatch,b})
+ end,
+ args}),
+ #{filters:=[_]} = logger:get_primary_config(),
+ ok = logger:notice(M1=?map_rep),
+ ok = check_logged(notice,M1,#{}),
+ {error,{not_found,lf}} = logger:remove_primary_filter(lf),
+
+ ok = logger:add_primary_filter(lf,{fun(_,_) -> faulty_return end,args}),
+ #{filters:=[_]} = logger:get_primary_config(),
+ ok = logger:notice(M2=?map_rep),
+ ok = check_logged(notice,M2,#{}),
+ {error,{not_found,lf}} = logger:remove_primary_filter(lf),
%% Handler filters
{error,{not_found,h0}} =
@@ -406,16 +521,20 @@ filter_failed(_Config) ->
{error,{not_found,h0}} = logger:remove_handler_filter(h0,hf),
{error,{invalid_filter,_}} =
logger:add_handler_filter(h1,hf,{fun(_) -> ok end,args}),
- ok = logger:add_handler_filter(h1,hf,{fun(_,_) -> a=b end,args}),
- {ok,{?MODULE,#{filters:=[_]}}} = logger:get_handler_config(h1),
- ok = logger:info(M3=?map_rep),
- ok = check_logged(info,M3,#{}),
+ ok = logger:add_handler_filter(h1,hf,
+ {fun(_,_) ->
+ erlang:error({badmatch,b})
+ end,
+ args}),
+ {ok,#{filters:=[_]}} = logger:get_handler_config(h1),
+ ok = logger:notice(M3=?map_rep),
+ ok = check_logged(notice,M3,#{}),
{error,{not_found,hf}} = logger:remove_handler_filter(h1,hf),
ok = logger:add_handler_filter(h1,hf,{fun(_,_) -> faulty_return end,args}),
- {ok,{?MODULE,#{filters:=[_]}}} = logger:get_handler_config(h1),
- ok = logger:info(M4=?map_rep),
- ok = check_logged(info,M4,#{}),
+ {ok,#{filters:=[_]}} = logger:get_handler_config(h1),
+ ok = logger:notice(M4=?map_rep),
+ ok = check_logged(notice,M4,#{}),
{error,{not_found,hf}} = logger:remove_handler_filter(h1,hf),
ok.
@@ -425,6 +544,7 @@ filter_failed(cleanup,_Config) ->
ok.
handler_failed(_Config) ->
+ register(callback_receiver,self()),
{error,{invalid_id,1}} = logger:add_handler(1,?MODULE,#{}),
{error,{invalid_module,"nomodule"}} = logger:add_handler(h1,"nomodule",#{}),
{error,{invalid_handler_config,bad}} = logger:add_handler(h1,?MODULE,bad),
@@ -434,26 +554,66 @@ handler_failed(_Config) ->
logger:add_handler(h1,?MODULE,#{filter_default=>true}),
{error,{invalid_formatter,[]}} =
logger:add_handler(h1,?MODULE,#{formatter=>[]}),
- ok = logger:add_handler(h1,nomodule,#{filter_default=>log}),
- logger:info(?map_rep),
+ {error,{invalid_handler,_}} = logger:add_handler(h1,nomodule,#{filter_default=>log}),
+ logger:notice(?map_rep),
check_no_log(),
- #{logger:=#{handlers:=Ids1},
- handlers:=H1} = logger:i(),
- false = lists:member(h1,Ids1),
- false = lists:keymember(h1,1,H1),
+ H1 = logger:get_handler_config(),
+ false = lists:search(fun(#{id:=h1}) -> true; (_) -> false end,H1),
{error,{not_found,h1}} = logger:remove_handler(h1),
- ok = logger:add_handler(h2,?MODULE,#{filter_default=>log,crash=>true}),
+ ok = logger:add_handler(h2,?MODULE,
+ #{filter_default => log,
+ log_call => fun() ->
+ erlang:error({badmatch,b})
+ end}),
{error,{already_exist,h2}} = logger:add_handler(h2,othermodule,#{}),
+ [add] = test_server:messages_get(),
- logger:info(?map_rep),
- check_no_log(),
- #{logger:=#{handlers:=Ids2},
- handlers:=H2} = logger:i(),
- false = lists:member(h2,Ids2),
- false = lists:keymember(h2,1,H2),
+ logger:notice(?map_rep),
+ [remove] = test_server:messages_get(),
+ H2 = logger:get_handler_config(),
+ false = lists:search(fun(#{id:=h2}) -> true; (_) -> false end,H2),
{error,{not_found,h2}} = logger:remove_handler(h2),
+ CallAddHandler = fun() -> logger:add_handler(h2,?MODULE,#{}) end,
+ CrashHandler = fun() -> erlang:error({badmatch,b}) end,
+ KillHandler = fun() -> exit(self(), die) end,
+
+ {error,{handler_not_added,{attempting_syncronous_call_to_self,_}}} =
+ logger:add_handler(h1,?MODULE,#{add_call=>CallAddHandler}),
+ {error,{handler_not_added,{callback_crashed,_}}} =
+ logger:add_handler(h1,?MODULE,#{add_call=>CrashHandler}),
+ {error,{handler_not_added,{logger_process_exited,_,die}}} =
+ logger:add_handler(h1,?MODULE,#{add_call=>KillHandler}),
+
+ check_no_log(),
+ ok = logger:add_handler(h1,?MODULE,#{}),
+ {error,{attempting_syncronous_call_to_self,_}} =
+ logger:set_handler_config(h1,#{conf_call=>CallAddHandler}),
+ {error,{callback_crashed,_}} =
+ logger:set_handler_config(h1,#{conf_call=>CrashHandler}),
+ {error,{logger_process_exited,_,die}} =
+ logger:set_handler_config(h1,#{conf_call=>KillHandler}),
+
+ {error,{attempting_syncronous_call_to_self,_}} =
+ logger:set_handler_config(h1,conf_call,CallAddHandler),
+ {error,{callback_crashed,_}} =
+ logger:set_handler_config(h1,conf_call,CrashHandler),
+ {error,{logger_process_exited,_,die}} =
+ logger:set_handler_config(h1,conf_call,KillHandler),
+
+ ok = logger:remove_handler(h1),
+ [add,remove] = test_server:messages_get(),
+
+ check_no_log(),
+ ok = logger:add_handler(h1,?MODULE,#{rem_call=>CallAddHandler}),
+ ok = logger:remove_handler(h1),
+ ok = logger:add_handler(h1,?MODULE,#{rem_call=>CrashHandler}),
+ ok = logger:remove_handler(h1),
+ ok = logger:add_handler(h1,?MODULE,#{rem_call=>KillHandler}),
+ ok = logger:remove_handler(h1),
+ [add,add,add] = test_server:messages_get(),
+
ok.
handler_failed(cleanup,_Config) ->
@@ -464,22 +624,18 @@ handler_failed(cleanup,_Config) ->
config_sanity_check(_Config) ->
%% Logger config
{error,{invalid_filter_default,bad}} =
- logger:set_logger_config(filter_default,bad),
- {error,{invalid_level,bad}} = logger:set_logger_config(level,bad),
- {error,{invalid_handlers,bad}} = logger:set_logger_config(handlers,bad),
- {error,{invalid_id,{bad,bad}}} =
- logger:set_logger_config(handlers,[{bad,bad}]),
- {error,{invalid_id,"bad"}} = logger:set_logger_config(handlers,["bad"]),
- {error,{invalid_filters,bad}} = logger:set_logger_config(filters,bad),
- {error,{invalid_filter,bad}} = logger:set_logger_config(filters,[bad]),
+ logger:set_primary_config(filter_default,bad),
+ {error,{invalid_level,bad}} = logger:set_primary_config(level,bad),
+ {error,{invalid_filters,bad}} = logger:set_primary_config(filters,bad),
+ {error,{invalid_filter,bad}} = logger:set_primary_config(filters,[bad]),
{error,{invalid_filter,{_,_}}} =
- logger:set_logger_config(filters,[{id,bad}]),
+ logger:set_primary_config(filters,[{id,bad}]),
{error,{invalid_filter,{_,{_,_}}}} =
- logger:set_logger_config(filters,[{id,{bad,args}}]),
+ logger:set_primary_config(filters,[{id,{bad,args}}]),
{error,{invalid_filter,{_,{_,_}}}} =
- logger:set_logger_config(filters,[{id,{fun() -> ok end,args}}]),
- {error,{invalid_logger_config,{bad,bad}}} =
- logger:set_logger_config(bad,bad),
+ logger:set_primary_config(filters,[{id,{fun() -> ok end,args}}]),
+ {error,{invalid_primary_config,{bad,bad}}} =
+ logger:set_primary_config(bad,bad),
%% Handler config
{error,{not_found,h1}} = logger:set_handler_config(h1,a,b),
@@ -499,29 +655,96 @@ config_sanity_check(_Config) ->
logger:set_handler_config(h1,formatter,bad),
{error,{invalid_module,{bad}}} =
logger:set_handler_config(h1,formatter,{{bad},cfg}),
- {error,{invalid_formatter_config,bad}} =
+ {error,{invalid_formatter_config,logger_formatter,bad}} =
logger:set_handler_config(h1,formatter,{logger_formatter,bad}),
- {error,{invalid_formatter_config,{bad,bad}}} =
+ {error,{invalid_formatter_config,logger_formatter,{bad,bad}}} =
logger:set_handler_config(h1,formatter,{logger_formatter,#{bad=>bad}}),
- {error,{invalid_formatter_config,{template,bad}}} =
+ {error,{invalid_formatter_template,logger_formatter,bad}} =
logger:set_handler_config(h1,formatter,{logger_formatter,
#{template=>bad}}),
- {error,{invalid_formatter_template,[1]}} =
+ {error,{invalid_formatter_template,logger_formatter,[1]}} =
logger:set_handler_config(h1,formatter,{logger_formatter,
#{template=>[1]}}),
ok = logger:set_handler_config(h1,formatter,{logger_formatter,
#{template=>[]}}),
- {error,{invalid_formatter_config,{single_line,bad}}} =
+ {error,{invalid_formatter_config,logger_formatter,{single_line,bad}}} =
logger:set_handler_config(h1,formatter,{logger_formatter,
#{single_line=>bad}}),
ok = logger:set_handler_config(h1,formatter,{logger_formatter,
#{single_line=>true}}),
- {error,{invalid_formatter_config,{legacy_header,bad}}} =
+ {error,{invalid_formatter_config,logger_formatter,{legacy_header,bad}}} =
logger:set_handler_config(h1,formatter,{logger_formatter,
#{legacy_header=>bad}}),
ok = logger:set_handler_config(h1,formatter,{logger_formatter,
#{legacy_header=>true}}),
+ {error,{invalid_formatter_config,logger_formatter,{report_cb,bad}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{report_cb=>bad}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{report_cb=>fun(R) ->
+ {"~p",[R]}
+ end}}),
+ {error,{invalid_formatter_config,logger_formatter,{chars_limit,bad}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{chars_limit=>bad}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{chars_limit=>unlimited}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{chars_limit=>4}}),
+ {error,{invalid_formatter_config,logger_formatter,{depth,bad}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{depth=>bad}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{depth=>unlimited}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{depth=>4}}),
+ {error,{invalid_formatter_config,logger_formatter,{max_size,bad}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{max_size=>bad}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{max_size=>unlimited}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{max_size=>4}}),
+ ok = logger:set_handler_config(h1,formatter,{module,config}),
+ {error,{callback_crashed,{error,{badmatch,3},[{?MODULE,check_config,1,_}]}}} =
+ logger:set_handler_config(h1,formatter,{?MODULE,crash}),
ok = logger:set_handler_config(h1,custom,custom),
+
+ %% Old utc parameter is no longer allowed (replaced by time_offset)
+ {error,{invalid_formatter_config,logger_formatter,{utc,true}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{utc=>true}}),
+ {error,{invalid_formatter_config,logger_formatter,{time_offset,bad}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_offset=>bad}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_offset=>0}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_offset=>""}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_offset=>"Z"}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_offset=>"z"}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_offset=>"-0:0"}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_offset=>"+10:13"}}),
+
+ {error,{invalid_formatter_config,logger_formatter,{time_offset,"+0"}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_offset=>"+0"}}),
+
+ {error,{invalid_formatter_config,logger_formatter,{time_designator,bad}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_designator=>bad}}),
+ {error,{invalid_formatter_config,logger_formatter,{time_designator,"s"}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_designator=>"s"}}),
+ {error,{invalid_formatter_config,logger_formatter,{time_designator,0}}} =
+ logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_designator=>0}}),
+ ok = logger:set_handler_config(h1,formatter,{logger_formatter,
+ #{time_designator=>$\s}}),
ok.
config_sanity_check(cleanup,_Config) ->
@@ -529,30 +752,30 @@ config_sanity_check(cleanup,_Config) ->
ok.
log_failed(_Config) ->
- ok = logger:add_handler(h1,?MODULE,#{level=>info,filter_default=>log}),
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log}),
{error,function_clause} = ?TRY(logger:log(bad,?map_rep)),
- {error,function_clause} = ?TRY(logger:log(info,?map_rep,bad)),
- {error,function_clause} = ?TRY(logger:log(info,fun() -> ?map_rep end,bad)),
- {error,function_clause} = ?TRY(logger:log(info,fun() -> ?map_rep end,bad,#{})),
- {error,function_clause} = ?TRY(logger:log(info,bad,bad,bad)),
- {error,function_clause} = ?TRY(logger:log(info,bad,bad,#{})),
+ {error,function_clause} = ?TRY(logger:log(notice,?map_rep,bad)),
+ {error,function_clause} = ?TRY(logger:log(notice,fun() -> ?map_rep end,bad)),
+ {error,function_clause} = ?TRY(logger:log(notice,fun() -> ?map_rep end,bad,#{})),
+ {error,function_clause} = ?TRY(logger:log(notice,bad,bad,bad)),
+ {error,function_clause} = ?TRY(logger:log(notice,bad,bad,#{})),
check_no_log(),
- ok = logger:log(info,M1=?str,#{}),
- check_logged(info,M1,#{}),
- ok = logger:log(info,M2=?map_rep,#{}),
- check_logged(info,M2,#{}),
- ok = logger:log(info,M3=?keyval_rep,#{}),
- check_logged(info,M3,#{}),
+ ok = logger:log(notice,M1=?str,#{}),
+ check_logged(notice,M1,#{}),
+ ok = logger:log(notice,M2=?map_rep,#{}),
+ check_logged(notice,M2,#{}),
+ ok = logger:log(notice,M3=?keyval_rep,#{}),
+ check_logged(notice,M3,#{}),
%% Should we check report input more thoroughly?
- ok = logger:log(info,M4=?keyval_rep++[other,stuff,in,list],#{}),
- check_logged(info,M4,#{}),
+ ok = logger:log(notice,M4=?keyval_rep++[other,stuff,in,list],#{}),
+ check_logged(notice,M4,#{}),
%% This might break a handler since it is assumed to be a format
%% string and args, so it depends how the handler protects itself
%% against something like io_lib:format("ok","ok")
- ok = logger:log(info,"ok","ok",#{}),
- check_logged(info,"ok","ok",#{}),
+ ok = logger:log(notice,"ok","ok",#{}),
+ check_logged(notice,"ok","ok",#{}),
ok.
@@ -561,7 +784,7 @@ log_failed(cleanup,_Config) ->
ok.
emulator(_Config) ->
- ok = logger:add_handler(h1,?MODULE,#{level=>info,filter_default=>log,
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log,
tc_proc=>self()}),
Msg = "Error in process ~p on node ~p with exit value:~n~p~n",
Error = {badmatch,4},
@@ -580,7 +803,7 @@ generate_error(Error, Stack) ->
erlang:raise(error, Error, Stack).
via_logger_process(Config) ->
- ok = logger:add_handler(h1,?MODULE,#{level=>info,filter_default=>log,
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log,
tc_proc=>self()}),
%% Explicitly send a message to the logger process
@@ -617,7 +840,7 @@ via_logger_process(cleanup, Config) ->
ok.
other_node(_Config) ->
- ok = logger:add_handler(h1,?MODULE,#{level=>info,filter_default=>log,
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log,
tc_proc=>self()}),
{ok,Node} = test_server:start_node(?FUNCTION_NAME,slave,[]),
rpc:call(Node,logger,error,[Msg=?str,#{}]),
@@ -634,8 +857,8 @@ compare_levels(_Config) ->
Levels = [emergency,alert,critical,error,warning,notice,info,debug],
ok = compare(Levels),
{error,badarg} = ?TRY(logger:compare_levels(bad,bad)),
- {error,badarg} = ?TRY(logger:compare_levels({bad},info)),
- {error,badarg} = ?TRY(logger:compare_levels(info,"bad")),
+ {error,badarg} = ?TRY(logger:compare_levels({bad},notice)),
+ {error,badarg} = ?TRY(logger:compare_levels(notice,"bad")),
ok.
compare([L|Rest]) ->
@@ -649,21 +872,21 @@ compare([]) ->
process_metadata(_Config) ->
undefined = logger:get_process_metadata(),
{error,badarg} = ?TRY(logger:set_process_metadata(bad)),
- ok = logger:add_handler(h1,?MODULE,#{level=>info,filter_default=>log}),
- Time = erlang:monotonic_time(microsecond),
+ ok = logger:add_handler(h1,?MODULE,#{level=>notice,filter_default=>log}),
+ Time = erlang:system_time(microsecond),
ProcMeta = #{time=>Time,line=>0,custom=>proc},
ok = logger:set_process_metadata(ProcMeta),
S1 = ?str,
- ?LOG_INFO(S1,#{custom=>macro}),
- check_logged(info,S1,#{time=>Time,line=>0,custom=>macro}),
+ ?LOG_NOTICE(S1,#{custom=>macro}),
+ check_logged(notice,S1,#{time=>Time,line=>0,custom=>macro}),
- Time2 = erlang:monotonic_time(microsecond),
+ Time2 = erlang:system_time(microsecond),
S2 = ?str,
- ?LOG_INFO(S2,#{time=>Time2,line=>1,custom=>macro}),
- check_logged(info,S2,#{time=>Time2,line=>1,custom=>macro}),
+ ?LOG_NOTICE(S2,#{time=>Time2,line=>1,custom=>macro}),
+ check_logged(notice,S2,#{time=>Time2,line=>1,custom=>macro}),
- logger:info(S3=?str,#{custom=>func}),
- check_logged(info,S3,#{time=>Time,line=>0,custom=>func}),
+ logger:notice(S3=?str,#{custom=>func}),
+ check_logged(notice,S3,#{time=>Time,line=>0,custom=>func}),
ProcMeta = logger:get_process_metadata(),
ok = logger:update_process_metadata(#{custom=>changed,custom2=>added}),
@@ -720,17 +943,20 @@ check_maps(Expected,Got,What) ->
end.
%% Handler
-adding_handler(_Id,Config) ->
+adding_handler(#{add_call:=Fun}) ->
+ Fun();
+adding_handler(Config) ->
maybe_send(add),
{ok,Config}.
-removing_handler(_Id,_Config) ->
+
+removing_handler(#{rem_call:=Fun}) ->
+ Fun();
+removing_handler(_Config) ->
maybe_send(remove),
ok.
-changing_config(_Id,_Old,#{call:=Fun}) ->
+changing_config(_Old,#{conf_call:=Fun}) ->
Fun();
-changing_config(_Id,_Old,#{fail:=true}) ->
- {error,fail};
-changing_config(_Id,_Old,Config) ->
+changing_config(_Old,Config) ->
maybe_send(changing_config),
{ok,Config}.
@@ -740,8 +966,8 @@ maybe_send(Msg) ->
Pid -> Pid ! Msg
end.
-log(_Log,#{crash:=true}) ->
- a=b;
+log(_Log,#{log_call:=Fun}) ->
+ Fun();
log(Log,Config) ->
TcProc = maps:get(tc_proc,Config,self()),
TcProc ! {Log,Config},
@@ -825,7 +1051,40 @@ test_macros(emergency=Level) ->
[{F2,x},{error,fun_that_crashes}],#{}),
ok.
+test_log_macro(Level) ->
+ ?LOG(Level,#{Level=>rep}),
+ ok = check_logged(Level,#{Level=>rep},?MY_LOC(1)),
+ ?LOG(Level,#{Level=>rep},#{my=>meta}),
+ ok = check_logged(Level,#{Level=>rep},(?MY_LOC(1))#{my=>meta}),
+ ?LOG(Level,"~w: ~w",[Level,fa]),
+ ok = check_logged(Level,"~w: ~w",[Level,fa],?MY_LOC(1)),
+ ?LOG(Level,"~w: ~w ~w",[Level,fa,meta],#{my=>meta}),
+ ok = check_logged(Level,"~w: ~w ~w",[Level,fa,meta],(?MY_LOC(1))#{my=>meta}),
+ ?LOG(Level,fun(x) -> {"~w: ~w ~w",[Level,fun_to_fa,meta]} end,
+ x, #{my=>meta}),
+ ok = check_logged(Level,"~w: ~w ~w",[Level,fun_to_fa,meta],
+ (?MY_LOC(3))#{my=>meta}),
+ ?LOG(Level,fun(x) -> #{Level=>fun_to_r,meta=>true} end, x, #{my=>meta}),
+ ok = check_logged(Level,#{Level=>fun_to_r,meta=>true},
+ (?MY_LOC(2))#{my=>meta}),
+ ?LOG(Level,fun(x) -> <<"fun_to_s">> end,x,#{}),
+ ok = check_logged(Level,<<"fun_to_s">>,?MY_LOC(1)),
+ F1=fun(x) -> {fun_to_bad} end,
+ ?LOG(Level,F1,x,#{}),
+ ok = check_logged(Level,"LAZY_FUN ERROR: ~tp; Returned: ~tp",
+ [{F1,x},{fun_to_bad}],#{}),
+ F2=fun(x) -> erlang:error(fun_that_crashes) end,
+ ?LOG(Level,F2,x,#{}),
+ ok = check_logged(Level,"LAZY_FUN CRASH: ~tp; Reason: ~tp",
+ [{F2,x},{error,fun_that_crashes}],#{}),
+ ok.
+
%%%-----------------------------------------------------------------
%%% Called by macro ?TRY(X)
my_try(Fun) ->
try Fun() catch C:R -> {C,R} end.
+
+check_config(crash) ->
+ erlang:error({badmatch,3});
+check_config(_) ->
+ ok.
diff --git a/lib/kernel/test/logger_bench_SUITE.erl b/lib/kernel/test/logger_bench_SUITE.erl
deleted file mode 100644
index d47122ea9d..0000000000
--- a/lib/kernel/test/logger_bench_SUITE.erl
+++ /dev/null
@@ -1,500 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2018. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% 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(logger_bench_SUITE).
-
--compile(export_all).
-
-%%%-----------------------------------------------------------------
-%%% To include lager tests, add paths to lager and goldrush
-%%% (goldrush is a dependency inside the lager repo)
-%%%
-%%% To print data to .csv files, add the following to a config file:
-%%% {print_csv,[{console_handler,[{path,"/some/dir/"}]}]}.
-%%%
-%%%-----------------------------------------------------------------
-
--include_lib("common_test/include/ct.hrl").
--include_lib("common_test/include/ct_event.hrl").
--include_lib("kernel/include/logger.hrl").
--include_lib("kernel/src/logger_internal.hrl").
-
--define(msg,lists:flatten(string:pad("Log from "++atom_to_list(?FUNCTION_NAME)++
- ":"++integer_to_list(?LINE),
- 80,trailing,$*))).
--define(meta,#{mfa=>{?MODULE,?FUNCTION_NAME,?FUNCTION_ARITY},
- pid=>self()}).
-
--define(NO_COMPARE,[profile]).
-
--define(TIMES,100000).
-
-suite() ->
- [{timetrap,{seconds,120}}].
-
-init_per_suite(Config) ->
- DataDir = ?config(data_dir,Config),
- have_lager() andalso make(DataDir),
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(Group, Config) ->
- H = remove_all_handlers(),
- do_init_per_group(Group),
- [{handlers,H}|Config].
-
-do_init_per_group(minimal_handler) ->
- ok = logger:add_handler(?MODULE,?MODULE,#{level=>error,filter_default=>log});
-do_init_per_group(console_handler) ->
- ok = logger:add_handler(?MODULE,logger_std_h,
- #{filter_default=>stop,
- filters=>?DEFAULT_HANDLER_FILTERS,
- logger_std_h=>#{type=>standard_io,
- toggle_sync_qlen => ?TIMES+1,
- drop_new_reqs_qlen => ?TIMES+2,
- flush_reqs_qlen => ?TIMES+3,
- enable_burst_limit => false}}),
- have_lager() andalso lager_helper:start(),
- ok.
-
-end_per_group(Group, Config) ->
- case ?config(saved_config,Config) of
- {_,[{bench,Bench}]} ->
- print_compare_chart(Group,Bench);
- _ ->
- ok
- end,
- add_all_handlers(?config(handlers,Config)),
- do_end_per_group(Group).
-
-do_end_per_group(minimal_handler) ->
- ok = logger:remove_handler(?MODULE);
-do_end_per_group(console_handler) ->
- ok = logger:remove_handler(?MODULE),
- have_lager() andalso lager_helper:stop(),
- ok.
-
-init_per_testcase(_TestCase, Config) ->
- Config.
-
-end_per_testcase(Case, Config) ->
- try apply(?MODULE,Case,[cleanup,Config])
- catch error:undef -> ok
- end,
- wait_for_handlers(),
- ok.
-
-wait_for_handlers() ->
- wait_for_handler(?MODULE),
- wait_for_handler(lager_event).
-
-wait_for_handler(Handler) ->
- case whereis(Handler) of
- undefined ->
- io:format("~p: noproc1",[Handler]),
- ok;
- Pid ->
- case process_info(Pid,message_queue_len) of
- {_,0} ->
- io:format("~p: queue=~p",[Handler,0]),
- ok;
- {_,Q} ->
- io:format("~p: queue=~p",[Handler,Q]),
- timer:sleep(2000),
- wait_for_handler(Handler);
- undefined ->
- io:format("~p: noproc2",[Handler]),
- ok
- end
- end.
-
-groups() ->
- [{minimal_handler,[],[log,
- log_drop,
- log_drop_by_handler,
- macro,
- macro_drop,
- macro_drop_by_handler,
- error_logger,
- error_logger_drop,
- error_logger_drop_by_handler
- ]},
- {console_handler,[],[%profile,
- log,
- log_drop,
- log_drop_by_handler,
- %% log_handler_complete,
- macro,
- macro_drop,
- macro_drop_by_handler,
- %% macro_handler_complete,
- error_logger,
- error_logger_drop,
- error_logger_drop_by_handler%% ,
- %% error_logger_handler_complete
- ] ++ lager_cases()}
- ].
-
-lager_cases() ->
- case have_lager() of
- true ->
- [lager_log,
- lager_log_drop,
- lager_log_drop_by_handler,
- %% lager_log_handler_complete,
- lager_parsetrans,
- lager_parsetrans_drop,
- lager_parsetrans_drop_by_handler%% ,
- %% lager_parsetrans_handler_complete
- ];
- false ->
- []
- end.
-
-
-all() ->
- [{group,minimal_handler},
- {group,console_handler}
- ].
-
-log(Config) ->
- Times = ?TIMES,
- run_benchmark(Config,?FUNCTION_NAME,fun do_log_func/2, [error,?msg], Times).
-
-log_drop(Config) ->
- Times = ?TIMES*100,
- ok = logger:set_logger_config(level,error),
- run_benchmark(Config,?FUNCTION_NAME,fun do_log_func/2, [info,?msg], Times).
-
-log_drop(cleanup,_Config) ->
- ok = logger:set_logger_config(level,info).
-
-log_drop_by_handler(Config) ->
- Times = ?TIMES,
- %% just ensure correct levels
- ok = logger:set_logger_config(level,info),
- ok = logger:set_handler_config(?MODULE,level,error),
- run_benchmark(Config,?FUNCTION_NAME,fun do_log_func/2, [info,?msg], Times).
-
-log_handler_complete(Config) ->
- ok = logger:set_handler_config(?MODULE,formatter,
- {?MODULE,?DEFAULT_FORMAT_CONFIG}),
- handler_complete(Config, ?FUNCTION_NAME, fun do_log_func/2, [error,?msg]).
-
-log_handler_complete(cleanup,_Config) ->
- ok=logger:set_handler_config(?MODULE,formatter,
- {?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}).
-
-macro(Config) ->
- Times = ?TIMES,
- run_benchmark(Config,?FUNCTION_NAME,fun do_log_macro/2,[error,?msg], Times).
-
-macro_drop(Config) ->
- Times = ?TIMES*100,
- ok = logger:set_logger_config(level,error),
- run_benchmark(Config,?FUNCTION_NAME,fun do_log_macro/2,[info,?msg], Times).
-
-macro_drop(cleanup,_Config) ->
- ok = logger:set_logger_config(level,info).
-
-macro_drop_by_handler(Config) ->
- Times = ?TIMES,
- %% just ensure correct levels
- ok = logger:set_logger_config(level,info),
- ok = logger:set_handler_config(?MODULE,level,error),
- run_benchmark(Config,?FUNCTION_NAME,fun do_log_macro/2, [info,?msg], Times).
-
-macro_handler_complete(Config) ->
- ok = logger:set_handler_config(?MODULE,formatter,
- {?MODULE,?DEFAULT_FORMAT_CONFIG}),
- handler_complete(Config, ?FUNCTION_NAME, fun do_log_macro/2, [error,?msg]).
-
-macro_handler_complete(cleanup,_Config) ->
- ok=logger:set_handler_config(?MODULE,formatter,
- {?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}).
-
-error_logger(Config) ->
- Times = ?TIMES,
- run_benchmark(Config,?FUNCTION_NAME,fun do_error_logger/2, [error,?msg], Times).
-
-error_logger_drop(Config) ->
- Times = ?TIMES*100,
- ok = logger:set_logger_config(level,error),
- run_benchmark(Config,?FUNCTION_NAME,fun do_error_logger/2, [info,?msg], Times).
-
-error_logger_drop(cleanup,_Config) ->
- ok = logger:set_logger_config(level,info).
-
-error_logger_drop_by_handler(Config) ->
- Times = ?TIMES,
- %% just ensure correct levels
- ok = logger:set_logger_config(level,info),
- ok = logger:set_handler_config(?MODULE,level,error),
- run_benchmark(Config,?FUNCTION_NAME,fun do_log_func/2, [info,?msg], Times).
-
-error_logger_handler_complete(Config) ->
- ok = logger:set_handler_config(?MODULE,formatter,
- {?MODULE,?DEFAULT_FORMAT_CONFIG}),
- handler_complete(Config, ?FUNCTION_NAME, fun do_error_logger/2, [error,?msg]).
-
-error_logger_handler_complete(cleanup,_Config) ->
- ok=logger:set_handler_config(?MODULE,formatter,
- {?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}).
-
-lager_log(Config) ->
- Times = ?TIMES,
- run_benchmark(Config,?FUNCTION_NAME,fun lager_helper:do_func/2, [error,?msg], Times).
-
-lager_log_drop(Config) ->
- Times = ?TIMES*100,
- run_benchmark(Config,?FUNCTION_NAME,fun lager_helper:do_func/2, [info,?msg], Times).
-
-lager_log_drop_by_handler(Config) ->
- %% This concept does not exist, so doing same as lager_log_drop/1
- Times = ?TIMES,
- run_benchmark(Config,?FUNCTION_NAME,fun lager_helper:do_func/2, [info,?msg], Times).
-
-lager_log_handler_complete(Config) ->
- handler_complete(Config, ?FUNCTION_NAME, fun lager_helper:do_func/2, [error,?msg]).
-
-lager_parsetrans(Config) ->
- Times = ?TIMES,
- run_benchmark(Config,?FUNCTION_NAME,fun lager_helper:do_parsetrans/2, [error,?msg], Times).
-
-lager_parsetrans_drop(Config) ->
- Times = ?TIMES*100,
- run_benchmark(Config,?FUNCTION_NAME,fun lager_helper:do_parsetrans/2, [info,?msg], Times).
-
-lager_parsetrans_drop_by_handler(Config) ->
- %% This concept does not exist, so doing same as lager_parsetrans_drop/1
- Times = ?TIMES,
- run_benchmark(Config,?FUNCTION_NAME,fun lager_helper:do_parsetrans/2, [info,?msg], Times).
-
-lager_parsetrans_handler_complete(Config) ->
- handler_complete(Config, ?FUNCTION_NAME, fun lager_helper:do_parsetrans/2, [error,?msg]).
-
-
-profile(Config) ->
- Times = ?TIMES,
- %% fprof:apply(fun repeated_apply/3,[fun lager_helper:do_func/2,[error,?msg],Times]),
- fprof:apply(fun repeated_apply/3,[fun do_log_func/2,[error,?msg],Times]),
- ok = fprof:profile(),
- ok = fprof:analyse(dest,"../fprof.analyse"),
- ok.
-
-%%%-----------------------------------------------------------------
-%%% Internal
-%% Handler
-log(_Log,_Config) ->
- ok.
-
-format(Log=#{meta:=#{pid:=Pid}},Config) when is_pid(Pid) ->
- String = ?DEFAULT_FORMATTER:format(Log,Config),
- Pid ! done,
- String;
-format(Log=#{meta:=#{pid:=PidStr}},Config) when is_list(PidStr) ->
- String = ?DEFAULT_FORMATTER:format(Log,Config),
- list_to_pid(PidStr) ! done,
- String.
-
-handler_complete(Config, TC, Fun, Args) ->
- Times = ?TIMES,
- Start = os:perf_counter(microsecond),
- repeated_apply(Fun, Args, Times),
- MSecs = wait_for_done(Start,Times),
- calc_and_report(Config,TC,MSecs,Times).
-
-wait_for_done(Start,0) ->
- os:perf_counter(microsecond) - Start;
-wait_for_done(Start,N) ->
- receive
- done ->
- wait_for_done(Start,N-1)
- after 20000 ->
- ct:fail("missing " ++ integer_to_list(N) ++ " replys")
- end.
-
-%%%-----------------------------------------------------------------
-%%% Benchmark stuff
-run_benchmark(Config,Tag,Fun,Args,Times) ->
- _ = erlang:apply(Fun, Args), % apply once to ensure level is cached
- MSecs = measure_repeated_op(Fun, Args, Times),
- %% fprof:profile(),
- %% fprof:analyse(dest,"../"++atom_to_list(Tag)++".prof"),
- calc_and_report(Config,Tag,MSecs,Times).
-
-measure_repeated_op(Fun, Args, Times) ->
- Start = os:perf_counter(microsecond),
- %% fprof:apply(fun repeated_apply/3, [Fun, Args, Times]),
- repeated_apply(Fun, Args, Times),
- os:perf_counter(microsecond) - Start.
-
-repeated_apply(_F, _Args, Times) when Times =< 0 ->
- ok;
-repeated_apply(F, Args, Times) ->
- erlang:apply(F, Args),
- repeated_apply(F, Args, Times - 1).
-
-calc_and_report(Config,Tag,MSecs,Times) ->
- IOPS = trunc(Times * (1000000 / MSecs)),
- ct_event:notify(#event{ name = benchmark_data, data = [{value,IOPS}] }),
- ct:print("~p:~n~p IOPS, ~p us", [Tag, IOPS, MSecs]),
- ct:comment("~p IOPS, ~p us", [IOPS, MSecs]),
- Bench = case ?config(saved_config,Config) of
- {_,[{bench,B}]} -> B;
- undefined -> []
- end,
- {save_config,[{bench,[{Tag,IOPS,MSecs}|Bench]}]}.
-
-remove_all_handlers() ->
- #{handlers:=Hs} = logger:i(),
- [logger:remove_handler(Id) || {Id,_,_} <- Hs],
- Hs.
-
-add_all_handlers(Hs) ->
- [logger:add_handler(Id,Mod,Config) || {Id,Mod,Config} <- Hs],
- ok.
-
-%%%-----------------------------------------------------------------
-%%% Call logger in different ways
-do_log_func(Level,Msg) ->
- logger:Level(Msg,[],?meta).
-
-do_log_macro(error,Msg) ->
- ?LOG_ERROR(Msg,[]);
-do_log_macro(info,Msg) ->
- ?LOG_INFO(Msg,[]);
-do_log_macro(debug,Msg) ->
- ?LOG_DEBUG(Msg,[]).
-
-do_error_logger(error,Msg) ->
- error_logger:error_msg(Msg,[]);
-do_error_logger(info,Msg) ->
- error_logger:info_msg(Msg,[]).
-
-%%%-----------------------------------------------------------------
-%%%
-print_compare_chart(Group,Bench) ->
- io:format("~-20s~12s~12s~12s~12s",
- ["Microseconds:","Log","Drop","HDrop","Complete"]),
- io:format(user,"~-20s~12s~12s~12s~12s~n",
- ["Microseconds:","Log","Drop","HDrop","Complete"]),
- {Log,Drop,HDrop,Comp} = sort_bench(Bench,[],[],[],[]),
- print_compare_chart(Log,Drop,HDrop,Comp),
- io:format(user,"~n",[]),
- maybe_print_csv_files(Group,
- [{log,Log},{drop,Drop},{hdrop,HDrop},{comp,Comp}]).
-
-print_compare_chart([{What,LIOPS,LMSecs}|Log],
- [{What,DIOPS,DMSecs}|Drop],
- [{What,HIOPS,HMSecs}|HDrop],
- [{What,CIOPS,CMSecs}|Comp]) ->
- io:format("~-20w~12w~12w~12w~12w",[What,LMSecs,DMSecs,HMSecs,CMSecs]),
- io:format(user,"~-20w~12w~12w~12w~12w~n",[What,LMSecs,DMSecs,HMSecs,CMSecs]),
- print_compare_chart(Log,Drop,HDrop,Comp);
-print_compare_chart([{What,LIOPS,LMSecs}|Log],
- [{What,DIOPS,DMSecs}|Drop],
- [{What,HIOPS,HMSecs}|HDrop],
- []=Comp) ->
- io:format("~-20w~12w~12w~12w",[What,LMSecs,DMSecs,HMSecs]),
- io:format(user,"~-20w~12w~12w~12w~n",[What,LMSecs,DMSecs,HMSecs]),
- print_compare_chart(Log,Drop,HDrop,Comp);
-print_compare_chart([],[],[],[]) ->
- ok;
-print_compare_chart(Log,Drop,HDrop,Comp) ->
- ct:fail({Log,Drop,HDrop,Comp}).
-
-sort_bench([{TC,IOPS,MSecs}|Bench],Log,Drop,HDrop,Comp) ->
- case lists:member(TC,?NO_COMPARE) of
- true ->
- sort_bench(Bench,Log,Drop,HDrop,Comp);
- false ->
- TCStr = atom_to_list(TC),
- {What,Type} =
- case re:run(TCStr,"(.*)_(drop.*)",
- [{capture,all_but_first,list}]) of
- {match,[WhatStr,TypeStr]} ->
- {list_to_atom(WhatStr),list_to_atom(TypeStr)};
- nomatch ->
- case re:run(TCStr,"(.*)_(handler_complete.*)",
- [{capture,all_but_first,list}]) of
- {match,[WhatStr,TypeStr]} ->
- {list_to_atom(WhatStr),list_to_atom(TypeStr)};
- nomatch ->
- {TC,log}
- end
- end,
- case Type of
- log ->
- sort_bench(Bench,[{What,IOPS,MSecs}|Log],Drop,HDrop,Comp);
- drop ->
- sort_bench(Bench,Log,[{What,IOPS,MSecs}|Drop],HDrop,Comp);
- drop_by_handler ->
- sort_bench(Bench,Log,Drop,[{What,IOPS,MSecs}|HDrop],Comp);
- handler_complete ->
- sort_bench(Bench,Log,Drop,HDrop,[{What,IOPS,MSecs}|Comp])
- end
- end;
-sort_bench([],Log,Drop,HDrop,Comp) ->
- {lists:keysort(1,Log),
- lists:keysort(1,Drop),
- lists:keysort(1,HDrop),
- lists:keysort(1,Comp)}.
-
-maybe_print_csv_files(Group,Data) ->
- case ct:get_config({print_csv,Group}) of
- undefined ->
- ok;
- Cfg ->
- Path = proplists:get_value(path,Cfg,".."),
- Files = [begin
- File = filename:join(Path,F)++".csv",
- case filelib:is_regular(File) of
- true ->
- {ok,Fd} = file:open(File,[append]),
- Fd;
- false ->
- {ok,Fd} = file:open(File,[write]),
- ok = file:write(Fd,
- "error_logger,lager_log,"
- "lager_parsetrans,logger_log,"
- "logger_macro\n"),
- Fd
- end
- end || {F,_} <- Data],
- [print_csv_file(F,D) || {F,D} <- lists:zip(Files,Data)],
- [file:close(Fd) || Fd <- Files],
- ok
- end.
-
-print_csv_file(Fd,{_,Data}) ->
- AllIOPS = [integer_to_list(IOPS) || {_,IOPS,_} <- Data],
- ok = file:write(Fd,lists:join(",",AllIOPS)++"\n").
-
-have_lager() ->
- code:ensure_loaded(lager) == {module,lager}.
-
-make(Dir) ->
- {ok,Cwd} = file:get_cwd(),
- ok = file:set_cwd(Dir),
- up_to_date = make:all([load]),
- ok = file:set_cwd(Cwd),
- code:add_path(Dir).
diff --git a/lib/kernel/test/logger_bench_SUITE_data/Emakefile b/lib/kernel/test/logger_bench_SUITE_data/Emakefile
deleted file mode 100644
index 85c82bdaab..0000000000
--- a/lib/kernel/test/logger_bench_SUITE_data/Emakefile
+++ /dev/null
@@ -1 +0,0 @@
-{['lager_helper'],[{outdir,"."},debug_info,{i,"/home/uabshan/Work/git/otp/lib/kernel/src"},{i,"/home/uabshan/Work/git/otp/lib/kernel/include"}]}.
diff --git a/lib/kernel/test/logger_bench_SUITE_data/lager_helper.erl b/lib/kernel/test/logger_bench_SUITE_data/lager_helper.erl
deleted file mode 100644
index 296ced4276..0000000000
--- a/lib/kernel/test/logger_bench_SUITE_data/lager_helper.erl
+++ /dev/null
@@ -1,73 +0,0 @@
--module(lager_helper).
-
--compile(export_all).
--compile({parse_transform,lager_transform}).
-
--include_lib("kernel/src/logger_internal.hrl").
-
-start() ->
- application:load(lager),
- application:set_env(lager, error_logger_redirect, false),
- application:set_env(lager, async_threshold, 100010),
- application:set_env(lager, async_threshold_window, 100),
- application:set_env(lager,handlers,[{?MODULE,[{level,error}]}]),
- lager:start().
-
-stop() ->
- application:stop(lager).
-
-do_func(Level,Msg) ->
- lager:log(Level,[{pid,self()}],Msg,[]).
-
-do_parsetrans(error,Msg) ->
- lager:error(Msg,[]);
-do_parsetrans(info,Msg) ->
- lager:info(Msg,[]).
-
-%%%-----------------------------------------------------------------
-%%% Dummy handler for lager
--record(state, {level :: {'mask', integer()},
- formatter :: atom(),
- format_config :: any()}).
-init(Opts) ->
- Level = proplists:get_value(level,Opts,info),
- Formatter = proplists:get_value(formatter,Opts,logger_bench_SUITE),
- FormatConfig = proplists:get_value(format_config,Opts,?DEFAULT_FORMAT_CONFIG),
- {ok,#state{level=lager_util:config_to_mask(Level),
- formatter=Formatter,
- format_config=FormatConfig}}.
-
-handle_call(get_loglevel, #state{level=Level} = State) ->
- {ok, Level, State};
-handle_call({set_loglevel, Level}, State) ->
- try lager_util:config_to_mask(Level) of
- Levels ->
- {ok, ok, State#state{level=Levels}}
- catch
- _:_ ->
- {ok, {error, bad_log_level}, State}
- end;
-handle_call(_Request, State) ->
- {ok, ok, State}.
-
-handle_event({log, Message},
- #state{level=L,formatter=Formatter,format_config=FormatConfig} = State) ->
- case lager_util:is_loggable(Message, L, ?MODULE) of
- true ->
- Metadata =
- case maps:from_list(lager_msg:metadata(Message)) of
- Meta = #{pid:=Pid} when is_pid(Pid) ->
- Meta;
- Meta = #{pid:=PidStr} when is_list(PidStr) ->
- Meta
- end,
- Log = #{level=>lager_msg:severity(Message),
- msg=>{report,lager_msg:message(Message)},
- meta=>Metadata},
- io:put_chars(user, Formatter:format(Log,FormatConfig)),
- {ok, State};
- false ->
- {ok, State}
- end;
-handle_event(_Event, State) ->
- {ok, State}.
diff --git a/lib/kernel/test/logger_disk_log_h_SUITE.erl b/lib/kernel/test/logger_disk_log_h_SUITE.erl
index 63e5b56021..a4b15c841b 100644
--- a/lib/kernel/test/logger_disk_log_h_SUITE.erl
+++ b/lib/kernel/test/logger_disk_log_h_SUITE.erl
@@ -1,3 +1,22 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% 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(logger_disk_log_h_SUITE).
-compile(export_all).
@@ -26,12 +45,9 @@
-define(log_no(File,N), lists:concat([File,".",N])).
-define(domain,#{domain=>[?MODULE]}).
--define(SYNC_REP_INT, if is_atom(?FILESYNC_REPEAT_INTERVAL) -> 5500;
- true -> ?FILESYNC_REPEAT_INTERVAL + 500
- end).
-
suite() ->
- [{timetrap,{seconds,30}}].
+ [{timetrap,{seconds,30}},
+ {ct_hooks,[logger_test_lib]}].
init_per_suite(Config) ->
timer:start(), % to avoid progress report
@@ -49,9 +65,10 @@ end_per_group(_Group, _Config) ->
init_per_testcase(TestHooksCase, Config) when
TestHooksCase == write_failure;
TestHooksCase == sync_failure ->
- if ?TEST_HOOKS_TAB == undefined ->
+ case (fun() -> ?TEST_HOOKS_TAB == undefined end)() of
+ true ->
{skip,"Define the TEST_HOOKS macro to run this test"};
- true ->
+ false ->
ct:print("********** ~w **********", [TestHooksCase]),
Config
end;
@@ -81,7 +98,7 @@ all() ->
bad_input,
info_and_reset,
reconfig,
- disk_log_sync,
+ sync,
disk_log_full,
disk_log_wrap,
disk_log_events,
@@ -106,10 +123,10 @@ start_stop_handler(_Config) ->
ok = logger:add_handler(?MODULE, logger_disk_log_h, #{}),
{error,{already_exist,?MODULE}} =
logger:add_handler(?MODULE, logger_disk_log_h, #{}),
- true = is_pid(whereis(?MODULE)),
+ true = is_pid(whereis(h_proc_name())),
ok = logger:remove_handler(?MODULE),
timer:sleep(500),
- undefined = whereis(?MODULE).
+ undefined = whereis(h_proc_name()).
start_stop_handler(cleanup, _Config) ->
logger:remove_handler(?MODULE).
@@ -122,8 +139,8 @@ create_log(Config) ->
filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
formatter=>{?MODULE,self()}},
#{file=>LogFile1}),
- logger:info("hello", ?domain),
- logger_disk_log_h:disk_log_sync(Name1),
+ logger:notice("hello", ?domain),
+ logger_disk_log_h:filesync(Name1),
ct:pal("Checking contents of ~p", [?log_no(LogFile1,1)]),
try_read_file(?log_no(LogFile1,1), {ok,<<"hello\n">>}, 5000),
@@ -135,8 +152,8 @@ create_log(Config) ->
filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
formatter=>{?MODULE,self()}},
#{file=>LogFile2}),
- logger:info("dummy", ?domain),
- logger_disk_log_h:disk_log_sync(Name2),
+ logger:notice("dummy", ?domain),
+ logger_disk_log_h:filesync(Name2),
ct:pal("Checking contents of ~p", [?log_no(LogFile2,1)]),
try_read_file(?log_no(LogFile2,1), {ok,<<"dummy\n">>}, 5000),
@@ -156,22 +173,22 @@ open_existing_log(Config) ->
filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
formatter=>{?MODULE,self()}},
#{file=>LogFile1}),
- logger:info("one", ?domain),
- logger_disk_log_h:disk_log_sync(HName),
+ logger:notice("one", ?domain),
+ logger_disk_log_h:filesync(HName),
ct:pal("Checking contents of ~p", [?log_no(LogFile1,1)]),
try_read_file(?log_no(LogFile1,1), {ok,<<"one\n">>}, 5000),
- logger:info("two", ?domain),
+ logger:notice("two", ?domain),
ok = remove_and_stop(HName),
try_read_file(?log_no(LogFile1,1), {ok,<<"one\ntwo\n">>}, 5000),
- logger:info("two and a half", ?domain),
+ logger:notice("two and a half", ?domain),
ok = start_and_add(HName, #{filter_default=>stop,
filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
formatter=>{?MODULE,self()}},
#{file=>LogFile1}),
- logger:info("three", ?domain),
- logger_disk_log_h:disk_log_sync(HName),
+ logger:notice("three", ?domain),
+ logger_disk_log_h:filesync(HName),
try_read_file(?log_no(LogFile1,1), {ok,<<"one\ntwo\nthree\n">>}, 5000),
remove_and_stop(HName),
try_read_file(?log_no(LogFile1,1), {ok,<<"one\ntwo\nthree\n">>}, 5000).
@@ -195,23 +212,23 @@ disk_log_opts(Config) ->
ct:log("Fullname = ~s", [WFileFull]),
{WFileFull,wrap,{Size,2},1} = {Get(file,WInfo1),Get(type,WInfo1),
Get(size,WInfo1),Get(current_file,WInfo1)},
- logger:info("123", ?domain),
- logger_disk_log_h:disk_log_sync(WName),
+ logger:notice("123", ?domain),
+ logger_disk_log_h:filesync(WName),
timer:sleep(500),
1 = Get(current_file, disk_log:info(WName)),
- logger:info("45", ?domain),
- logger_disk_log_h:disk_log_sync(WName),
+ logger:notice("45", ?domain),
+ logger_disk_log_h:filesync(WName),
timer:sleep(500),
1 = Get(current_file, disk_log:info(WName)),
- logger:info("6", ?domain),
- logger_disk_log_h:disk_log_sync(WName),
+ logger:notice("6", ?domain),
+ logger_disk_log_h:filesync(WName),
timer:sleep(500),
2 = Get(current_file, disk_log:info(WName)),
- logger:info("7890", ?domain),
- logger_disk_log_h:disk_log_sync(WName),
+ logger:notice("7890", ?domain),
+ logger_disk_log_h:filesync(WName),
timer:sleep(500),
2 = Get(current_file, disk_log:info(WName)),
@@ -228,8 +245,8 @@ disk_log_opts(Config) ->
ct:log("Fullname = ~s", [HFile1Full]),
{HFile1Full,halt,infinity} = {Get(file,HInfo1),Get(type,HInfo1),
Get(size,HInfo1)},
- logger:info("12345", ?domain),
- logger_disk_log_h:disk_log_sync(HName1),
+ logger:notice("12345", ?domain),
+ logger_disk_log_h:filesync(HName1),
timer:sleep(500),
1 = Get(no_written_items, disk_log:info(HName1)),
@@ -252,17 +269,17 @@ disk_log_opts(Config) ->
default_formatter(Config) ->
PrivDir = ?config(priv_dir,Config),
LogFile = filename:join(PrivDir,atom_to_list(?FUNCTION_NAME)),
- HConfig = #{disk_log_opts => #{file=>LogFile},
- filter_default=>log},
+ HandlerConfig = #{config => #{file=>LogFile},
+ filter_default=>log},
ct:pal("Log: ~p", [LogFile]),
- ok = logger:add_handler(?MODULE, logger_disk_log_h, HConfig),
+ ok = logger:add_handler(?MODULE, logger_disk_log_h, HandlerConfig),
ok = logger:set_handler_config(?MODULE,formatter,
{?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}),
LogName = lists:concat([LogFile, ".1"]),
- logger:info("dummy"),
+ logger:notice("dummy"),
wait_until_written(LogName),
{ok,Bin} = file:read_file(LogName),
- match = re:run(Bin, "=INFO REPORT====.*\ndummy", [{capture,none}]),
+ match = re:run(Bin, "=NOTICE REPORT====.*\ndummy", [{capture,none}]),
ok.
default_formatter(cleanup, _Config) ->
logger:remove_handler(?MODULE).
@@ -276,8 +293,8 @@ logging(Config) ->
formatter=>{?MODULE,self()}},
#{file => LogFile}),
MsgFormatter = fun(Term) -> {io_lib:format("Term:~p",[Term]),[]} end,
- logger:info([{x,y}], #{report_cb => MsgFormatter}),
- logger:info([{x,y}], #{}),
+ logger:notice([{x,y}], #{report_cb => MsgFormatter}),
+ logger:notice([{x,y}], #{}),
ct:pal("Checking contents of ~p", [?log_no(LogFile,1)]),
try_read_file(?log_no(LogFile,1), {ok,<<"Term:[{x,y}]\n x: y\n">>}, 5000).
@@ -289,10 +306,10 @@ errors(Config) ->
PrivDir = ?config(priv_dir,Config),
Name1 = list_to_atom(lists:concat([?FUNCTION_NAME,"_1"])),
LogFile1 = filename:join(PrivDir,Name1),
- HConfig = #{disk_log_opts=>#{file=>LogFile1},
- filter_default=>log,
- formatter=>{?MODULE,self()}},
- ok = logger:add_handler(Name1, logger_disk_log_h, HConfig),
+ HandlerConfig = #{config=>#{file=>LogFile1},
+ filter_default=>log,
+ formatter=>{?MODULE,self()}},
+ ok = logger:add_handler(Name1, logger_disk_log_h, HandlerConfig),
{error,{already_exist,Name1}} =
logger:add_handler(Name1, logger_disk_log_h, #{}),
@@ -301,7 +318,7 @@ errors(Config) ->
{error,{illegal_config_change,_,_}} =
logger:set_handler_config(Name1,
- disk_log_opts,
+ config,
#{file=>LogFile1,
type=>halt}),
{error,{illegal_config_change,_,_}} =
@@ -320,43 +337,42 @@ formatter_fail(Config) ->
Name = ?FUNCTION_NAME,
LogFile = filename:join(PrivDir,Name),
ct:pal("Log = ~p", [LogFile]),
- HConfig = #{disk_log_opts => #{file=>LogFile},
- filter_default=>stop,
- filters=>?DEFAULT_HANDLER_FILTERS([?MODULE])},
+ HandlerConfig = #{config => #{file=>LogFile},
+ filter_default=>stop,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE])},
%% no formatter!
- logger:add_handler(Name, logger_disk_log_h, HConfig),
- Pid = whereis(Name),
+ logger:add_handler(Name, logger_disk_log_h, HandlerConfig),
+ Pid = whereis(h_proc_name(Name)),
true = is_pid(Pid),
- {ok,#{handlers:=H}} = logger:get_logger_config(),
+ H = logger:get_handler_ids(),
true = lists:member(Name,H),
%% Formatter is added automatically
- {ok,{_,#{formatter:={logger_formatter,_}}}} =
- logger:get_handler_config(Name),
- logger:info(M1=?msg,?domain),
- Got1 = try_match_file(?log_no(LogFile,1),"=INFO REPORT====.*\n"++M1,5000),
+ {ok,#{formatter:={logger_formatter,_}}} = logger:get_handler_config(Name),
+ logger:notice(M1=?msg,?domain),
+ Got1 = try_match_file(?log_no(LogFile,1),"[0-9\\+\\-T:\\.]* notice: "++M1,5000),
ok = logger:set_handler_config(Name,formatter,{nonexistingmodule,#{}}),
- logger:info(M2=?msg,?domain),
+ logger:notice(M2=?msg,?domain),
Got2 = try_match_file(?log_no(LogFile,1),
- Got1++"=INFO REPORT====.*\nFORMATTER CRASH: .*"++M2,
+ escape(Got1)++"[0-9\\+\\-T:\\.]* notice: FORMATTER CRASH: .*"++M2,
5000),
ok = logger:set_handler_config(Name,formatter,{?MODULE,crash}),
- logger:info(M3=?msg,?domain),
+ logger:notice(M3=?msg,?domain),
Got3 = try_match_file(?log_no(LogFile,1),
- Got2++"=INFO REPORT====.*\nFORMATTER CRASH: .*"++M3,
+ escape(Got2)++"[0-9\\+\\-T:\\.]* notice: FORMATTER CRASH: .*"++M3,
5000),
ok = logger:set_handler_config(Name,formatter,{?MODULE,bad_return}),
- logger:info(?msg,?domain),
+ logger:notice(?msg,?domain),
try_match_file(?log_no(LogFile,1),
- Got3++"FORMATTER ERROR: bad_return_value",
+ escape(Got3)++"FORMATTER ERROR: bad_return_value",
5000),
%% Check that handler is still alive and was never dead
- Pid = whereis(Name),
- {ok,#{handlers:=H}} = logger:get_logger_config(),
+ Pid = whereis(h_proc_name(Name)),
+ H = logger:get_handler_ids(),
ok.
formatter_fail(cleanup,_Config) ->
@@ -366,40 +382,49 @@ formatter_fail(cleanup,_Config) ->
config_fail(_Config) ->
{error,{handler_not_added,{invalid_config,logger_disk_log_h,{bad,bad}}}} =
logger:add_handler(?MODULE,logger_disk_log_h,
- #{logger_disk_log_h => #{bad => bad},
+ #{config => #{bad => bad},
filter_default=>log,
formatter=>{?MODULE,self()}}),
- {error,{handler_not_added,{invalid_levels,{42,42,_}}}} =
+
+ {error,{handler_not_added,{invalid_levels,{_,1,_}}}} =
+ logger:add_handler(?MODULE,logger_disk_log_h,
+ #{config => #{drop_mode_qlen=>1}}),
+ {error,{handler_not_added,{invalid_levels,{43,42,_}}}} =
logger:add_handler(?MODULE,logger_disk_log_h,
- #{logger_disk_log_h => #{toggle_sync_qlen=>42,
- drop_new_reqs_qlen=>42}}),
+ #{config => #{sync_mode_qlen=>43,
+ drop_mode_qlen=>42}}),
+ {error,{handler_not_added,{invalid_levels,{_,43,42}}}} =
+ logger:add_handler(?MODULE,logger_disk_log_h,
+ #{config => #{drop_mode_qlen=>43,
+ flush_qlen=>42}}),
ok = logger:add_handler(?MODULE,logger_disk_log_h,
#{filter_default=>log,
formatter=>{?MODULE,self()}}),
%% can't change the disk log options for a log already in use
{error,{illegal_config_change,_,_}} =
- logger:set_handler_config(?MODULE,disk_log_opts,
+ logger:set_handler_config(?MODULE,config,
#{max_no_files=>2}),
%% can't change name of an existing handler
{error,{illegal_config_change,_,_}} =
logger:set_handler_config(?MODULE,id,bad),
- %% incorrect values of OP params
+ %% incorrect values of OP params
+ {ok,#{config := HConfig}} = logger:get_handler_config(?MODULE),
{error,{invalid_levels,_}} =
- logger:set_handler_config(?MODULE,logger_disk_log_h,
- #{toggle_sync_qlen=>100,
- flush_reqs_qlen=>99}),
+ logger:set_handler_config(?MODULE,config,
+ HConfig#{sync_mode_qlen=>100,
+ flush_qlen=>99}),
%% invalid name of config parameter
{error,{invalid_config,logger_disk_log_h,{filesync_rep_int,2000}}} =
- logger:set_handler_config(?MODULE, logger_disk_log_h,
- #{filesync_rep_int => 2000}),
+ logger:set_handler_config(?MODULE, config,
+ HConfig#{filesync_rep_int => 2000}),
ok.
config_fail(cleanup,_Config) ->
logger:remove_handler(?MODULE).
bad_input(_Config) ->
- {error,{badarg,{disk_log_sync,["BadType"]}}} =
- logger_disk_log_h:disk_log_sync("BadType"),
+ {error,{badarg,{filesync,["BadType"]}}} =
+ logger_disk_log_h:filesync("BadType"),
{error,{badarg,{info,["BadType"]}}} = logger_disk_log_h:info("BadType"),
{error,{badarg,{reset,["BadType"]}}} = logger_disk_log_h:reset("BadType").
@@ -420,16 +445,16 @@ reconfig(Config) ->
filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
formatter=>{?MODULE,self()}}),
#{id := ?MODULE,
- toggle_sync_qlen := ?TOGGLE_SYNC_QLEN,
- drop_new_reqs_qlen := ?DROP_NEW_REQS_QLEN,
- flush_reqs_qlen := ?FLUSH_REQS_QLEN,
- enable_burst_limit := ?ENABLE_BURST_LIMIT,
- burst_limit_size := ?BURST_LIMIT_SIZE,
- burst_window_time := ?BURST_WINDOW_TIME,
- enable_kill_overloaded := ?ENABLE_KILL_OVERLOADED,
- handler_overloaded_qlen := ?HANDLER_OVERLOADED_QLEN,
- handler_overloaded_mem := ?HANDLER_OVERLOADED_MEM,
- handler_restart_after := ?HANDLER_RESTART_AFTER,
+ sync_mode_qlen := ?SYNC_MODE_QLEN,
+ drop_mode_qlen := ?DROP_MODE_QLEN,
+ flush_qlen := ?FLUSH_QLEN,
+ burst_limit_enable := ?BURST_LIMIT_ENABLE,
+ burst_limit_max_count := ?BURST_LIMIT_MAX_COUNT,
+ burst_limit_window_time := ?BURST_LIMIT_WINDOW_TIME,
+ overload_kill_enable := ?OVERLOAD_KILL_ENABLE,
+ overload_kill_qlen := ?OVERLOAD_KILL_QLEN,
+ overload_kill_mem_size := ?OVERLOAD_KILL_MEM_SIZE,
+ overload_kill_restart_after := ?OVERLOAD_KILL_RESTART_AFTER,
filesync_repeat_interval := ?FILESYNC_REPEAT_INTERVAL,
log_opts := #{type := ?DISK_LOG_TYPE,
max_no_files := ?DISK_LOG_MAX_NO_FILES,
@@ -437,29 +462,30 @@ reconfig(Config) ->
file := _DiskLogFile}} =
logger_disk_log_h:info(?MODULE),
- ok = logger:set_handler_config(?MODULE, logger_disk_log_h,
- #{toggle_sync_qlen => 1,
- drop_new_reqs_qlen => 2,
- flush_reqs_qlen => 3,
- enable_burst_limit => false,
- burst_limit_size => 10,
- burst_window_time => 10,
- enable_kill_overloaded => true,
- handler_overloaded_qlen => 100000,
- handler_overloaded_mem => 10000000,
- handler_restart_after => never,
- filesync_repeat_interval => no_repeat}),
+ {ok,#{config := HConfig0}} = logger:get_handler_config(?MODULE),
+ HConfig1 = HConfig0#{sync_mode_qlen => 1,
+ drop_mode_qlen => 2,
+ flush_qlen => 3,
+ burst_limit_enable => false,
+ burst_limit_max_count => 10,
+ burst_limit_window_time => 10,
+ overload_kill_enable => true,
+ overload_kill_qlen => 100000,
+ overload_kill_mem_size => 10000000,
+ overload_kill_restart_after => infinity,
+ filesync_repeat_interval => no_repeat},
+ ok = logger:set_handler_config(?MODULE, config, HConfig1),
#{id := ?MODULE,
- toggle_sync_qlen := 1,
- drop_new_reqs_qlen := 2,
- flush_reqs_qlen := 3,
- enable_burst_limit := false,
- burst_limit_size := 10,
- burst_window_time := 10,
- enable_kill_overloaded := true,
- handler_overloaded_qlen := 100000,
- handler_overloaded_mem := 10000000,
- handler_restart_after := never,
+ sync_mode_qlen := 1,
+ drop_mode_qlen := 2,
+ flush_qlen := 3,
+ burst_limit_enable := false,
+ burst_limit_max_count := 10,
+ burst_limit_window_time := 10,
+ overload_kill_enable := true,
+ overload_kill_qlen := 100000,
+ overload_kill_mem_size := 10000000,
+ overload_kill_restart_after := infinity,
filesync_repeat_interval := no_repeat} =
logger_disk_log_h:info(?MODULE),
@@ -471,7 +497,7 @@ reconfig(Config) ->
#{filter_default=>log,
filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
formatter=>{?MODULE,self()},
- disk_log_opts=>
+ config=>
#{type => halt,
max_no_files => 1,
max_no_bytes => 1024,
@@ -486,13 +512,13 @@ reconfig(Config) ->
reconfig(cleanup, _Config) ->
logger:remove_handler(?MODULE).
-disk_log_sync(Config) ->
+sync(Config) ->
Dir = ?config(priv_dir,Config),
File = filename:join(Dir, ?FUNCTION_NAME),
Log = lists:concat([File,".1"]),
ok = logger:add_handler(?MODULE,
logger_disk_log_h,
- #{disk_log_opts => #{file => File},
+ #{config => #{file => File},
filter_default=>log,
filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
formatter=>{?MODULE,nl}}),
@@ -502,7 +528,7 @@ disk_log_sync(Config) ->
[{disk_log,blog,<<"first\n">>},
{disk_log,sync}]),
- logger:info("first", ?domain),
+ logger:notice("first", ?domain),
%% wait for automatic disk_log_sync
check_tracer(?FILESYNC_REPEAT_INTERVAL*2),
@@ -513,16 +539,18 @@ disk_log_sync(Config) ->
{disk_log,sync}]),
%% two log requests in fast succession will make the handler skip
%% an automatic disk log sync
- logger:info("second", ?domain),
- logger:info("third", ?domain),
- %% do explicit disk_log_sync
- logger_disk_log_h:disk_log_sync(?MODULE),
+ logger:notice("second", ?domain),
+ logger:notice("third", ?domain),
+ %% do explicit sync
+ logger_disk_log_h:filesync(?MODULE),
check_tracer(100),
%% check that if there's no repeated disk_log_sync active,
%% a disk_log_sync is still performed when handler goes idle
- logger:set_handler_config(?MODULE, logger_disk_log_h,
- #{filesync_repeat_interval => no_repeat}),
+ {ok,#{config := HConfig}} = logger:get_handler_config(?MODULE),
+ HConfig1 = HConfig#{filesync_repeat_interval => no_repeat},
+ ok = logger:set_handler_config(?MODULE, config, HConfig1),
+
no_repeat = maps:get(filesync_repeat_interval,
logger_disk_log_h:info(?MODULE)),
@@ -532,9 +560,9 @@ disk_log_sync(Config) ->
{disk_log,blog,<<"fifth\n">>},
{disk_log,sync}]),
- logger:info("fourth", ?domain),
+ logger:notice("fourth", ?domain),
timer:sleep(?IDLE_DETECT_TIME_MSEC*2),
- logger:info("fifth", ?domain),
+ logger:notice("fifth", ?domain),
%% wait for automatic disk_log_sync
check_tracer(?IDLE_DETECT_TIME_MSEC*2),
@@ -548,16 +576,17 @@ disk_log_sync(Config) ->
start_tracer([{logger_disk_log_h,handle_cast,2}],
[OneSync || _ <- lists:seq(1, 1 + trunc(WaitT/SyncInt))]),
- logger:set_handler_config(?MODULE, logger_disk_log_h,
- #{filesync_repeat_interval => SyncInt}),
+ HConfig2 = HConfig#{filesync_repeat_interval => SyncInt},
+ ok = logger:set_handler_config(?MODULE, config, HConfig2),
+
SyncInt = maps:get(filesync_repeat_interval,
logger_disk_log_h:info(?MODULE)),
timer:sleep(WaitT),
- logger:set_handler_config(?MODULE, logger_disk_log_h,
- #{filesync_repeat_interval => no_repeat}),
+ HConfig3 = HConfig#{filesync_repeat_interval => no_repeat},
+ ok = logger:set_handler_config(?MODULE, config, HConfig3),
check_tracer(100),
ok.
-disk_log_sync(cleanup,_Config) ->
+sync(cleanup,_Config) ->
dbg:stop_clear(),
logger:remove_handler(?MODULE).
@@ -573,7 +602,7 @@ disk_log_wrap(Config) ->
#{filter_default=>log,
filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
formatter=>{?MODULE,self()},
- disk_log_opts=>
+ config=>
#{type => wrap,
max_no_files => MaxFiles,
max_no_bytes => MaxBytes,
@@ -587,7 +616,7 @@ disk_log_wrap(Config) ->
Pid
end,
{ok,_} = dbg:tracer(process, {TraceFun, Tester}),
- {ok,_} = dbg:p(whereis(?MODULE), [c]),
+ {ok,_} = dbg:p(whereis(h_proc_name()), [c]),
{ok,_} = dbg:tp(logger_disk_log_h, handle_info, 2, []),
Text = [34 + rand:uniform(126-34) || _ <- lists:seq(1,MaxBytes)],
@@ -595,7 +624,7 @@ disk_log_wrap(Config) ->
%% fill first file
lists:foreach(fun(N) ->
Log = lists:concat([File,".",N]),
- logger:info(Text, ?domain),
+ logger:notice(Text, ?domain),
wait_until_written(Log),
ct:pal("N = ~w",
[N = Get(current_file,
@@ -629,7 +658,7 @@ disk_log_full(Config) ->
#{filter_default=>log,
filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
formatter=>{?MODULE,self()},
- disk_log_opts=>
+ config=>
#{type => halt,
max_no_files => 1,
max_no_bytes => MaxBytes,
@@ -641,12 +670,12 @@ disk_log_full(Config) ->
Pid
end,
{ok,_} = dbg:tracer(process, {TraceFun, Tester}),
- {ok,_} = dbg:p(whereis(?MODULE), [c]),
+ {ok,_} = dbg:p(whereis(h_proc_name()), [c]),
{ok,_} = dbg:tp(logger_disk_log_h, handle_info, 2, []),
NoOfChars = 5,
Text = [34 + rand:uniform(126-34) || _ <- lists:seq(1,NoOfChars)],
- [logger:info(Text, ?domain) || _ <- lists:seq(1,trunc(MaxBytes/NoOfChars)+1)],
+ [logger:notice(Text, ?domain) || _ <- lists:seq(1,trunc(MaxBytes/NoOfChars)+1)],
%% wait for trace messages
timer:sleep(2000),
@@ -690,10 +719,10 @@ disk_log_events(Config) ->
Pid
end,
{ok,_} = dbg:tracer(process, {TraceFun, Tester}),
- {ok,_} = dbg:p(whereis(?MODULE), [c]),
+ {ok,_} = dbg:p(whereis(h_proc_name()), [c]),
{ok,_} = dbg:tp(logger_disk_log_h, handle_info, 2, []),
- [whereis(?MODULE) ! E || E <- Events],
+ [whereis(h_proc_name()) ! E || E <- Events],
%% wait for trace messages
timer:sleep(2000),
dbg:stop_clear(),
@@ -717,7 +746,7 @@ write_failure(Config) ->
Log = lists:concat([File,".1"]),
ct:pal("Log = ~p", [Log]),
- Node = start_h_on_new_node(Config, ?FUNCTION_NAME, File),
+ Node = start_h_on_new_node(Config, File),
false = (undefined == rpc:call(Node, ets, whereis, [?TEST_HOOKS_TAB])),
rpc:call(Node, ets, insert, [?TEST_HOOKS_TAB,{tester,self()}]),
rpc:call(Node, ?MODULE, set_internal_log, [?MODULE,internal_log]),
@@ -726,9 +755,15 @@ write_failure(Config) ->
ct:pal("LogOpts = ~p", [LogOpts = maps:get(log_opts, HState)]),
ok = log_on_remote_node(Node, "Logged1"),
- rpc:call(Node, logger_disk_log_h, disk_log_sync, [?STANDARD_HANDLER]),
+ rpc:call(Node, logger_disk_log_h, filesync, [?STANDARD_HANDLER]),
?check_no_log,
- try_read_file(Log, {ok,<<"Logged1\n">>}, ?SYNC_REP_INT),
+
+ SyncRepInt = case (fun() -> is_atom(?FILESYNC_REPEAT_INTERVAL) end)() of
+ true -> 5500;
+ false -> ?FILESYNC_REPEAT_INTERVAL + 500
+ end,
+
+ try_read_file(Log, {ok,<<"Logged1\n">>}, SyncRepInt),
rpc:call(Node, ?MODULE, set_result, [disk_log_blog,{error,no_such_log}]),
ok = log_on_remote_node(Node, "Cause simple error printout"),
@@ -746,9 +781,9 @@ write_failure(Config) ->
rpc:call(Node, ?MODULE, set_result, [disk_log_blog,ok]),
ok = log_on_remote_node(Node, "Logged2"),
- rpc:call(Node, logger_disk_log_h, disk_log_sync, [?STANDARD_HANDLER]),
+ rpc:call(Node, logger_disk_log_h, filesync, [?STANDARD_HANDLER]),
?check_no_log,
- try_read_file(Log, {ok,<<"Logged1\nLogged2\n">>}, ?SYNC_REP_INT),
+ try_read_file(Log, {ok,<<"Logged1\nLogged2\n">>}, SyncRepInt),
ok.
write_failure(cleanup, _Config) ->
Nodes = nodes(),
@@ -761,7 +796,7 @@ sync_failure(Config) ->
File = filename:join(Dir, FileName),
- Node = start_h_on_new_node(Config, ?FUNCTION_NAME, File),
+ Node = start_h_on_new_node(Config, File),
false = (undefined == rpc:call(Node, ets, whereis, [?TEST_HOOKS_TAB])),
rpc:call(Node, ets, insert, [?TEST_HOOKS_TAB,{tester,self()}]),
rpc:call(Node, ?MODULE, set_internal_log, [?MODULE,internal_log]),
@@ -771,7 +806,7 @@ sync_failure(Config) ->
SyncInt = 500,
ok = rpc:call(Node, logger, set_handler_config,
- [?STANDARD_HANDLER, logger_disk_log_h,
+ [?STANDARD_HANDLER, config,
#{filesync_repeat_interval => SyncInt}]),
Info = rpc:call(Node, logger_disk_log_h, info, [?STANDARD_HANDLER]),
SyncInt = maps:get(filesync_repeat_interval, Info),
@@ -782,7 +817,7 @@ sync_failure(Config) ->
rpc:call(Node, ?MODULE, set_result, [disk_log_sync,{error,no_such_log}]),
ok = log_on_remote_node(Node, "Cause simple error printout"),
- ?check({error,{?STANDARD_HANDLER,sync,LogOpts,{error,no_such_log}}}),
+ ?check({error,{?STANDARD_HANDLER,filesync,LogOpts,{error,no_such_log}}}),
ok = log_on_remote_node(Node, "No second error printout"),
?check_no_log,
@@ -790,7 +825,7 @@ sync_failure(Config) ->
rpc:call(Node, ?MODULE, set_result,
[disk_log_sync,{error,{blocked_log,?STANDARD_HANDLER}}]),
ok = log_on_remote_node(Node, "Cause simple error printout"),
- ?check({error,{?STANDARD_HANDLER,sync,LogOpts,
+ ?check({error,{?STANDARD_HANDLER,filesync,LogOpts,
{error,{blocked_log,?STANDARD_HANDLER}}}}),
rpc:call(Node, ?MODULE, set_result, [disk_log_sync,ok]),
@@ -801,21 +836,12 @@ sync_failure(cleanup, _Config) ->
Nodes = nodes(),
[test_server:stop_node(Node) || Node <- Nodes].
-start_h_on_new_node(_Config, Func, File) ->
- Pa = filename:dirname(code:which(?MODULE)),
- Dest =
- case os:type() of
- {win32,_} ->
- lists:concat([" {disk_log,\\\"",File,"\\\"}"]);
- _ ->
- lists:concat([" \'{disk_log,\"",File,"\"}\'"])
- end,
- Args = lists:concat([" -kernel ",logger_dest,Dest," -pa ",Pa]),
- NodeName = lists:concat([?MODULE,"_",Func]),
- ct:pal("Starting ~s with ~tp", [NodeName,Args]),
- {ok,Node} = test_server:start_node(NodeName, peer, [{args, Args}]),
- Pid = rpc:call(Node,erlang,whereis,[?STANDARD_HANDLER]),
- true = is_pid(Pid),
+start_h_on_new_node(Config, File) ->
+ {ok,_,Node} =
+ logger_test_lib:setup(
+ Config,
+ [{logger,[{handler,default,logger_disk_log_h,
+ #{ config => #{ file => File }}}]}]),
ok = rpc:call(Node,logger,set_handler_config,[?STANDARD_HANDLER,formatter,
{?MODULE,nl}]),
Node.
@@ -823,7 +849,7 @@ start_h_on_new_node(_Config, Func, File) ->
log_on_remote_node(Node,Msg) ->
_ = spawn_link(Node,
fun() -> erlang:group_leader(whereis(user),self()),
- logger:info(Msg)
+ logger:notice(Msg)
end),
ok.
@@ -848,79 +874,133 @@ internal_log(Type, Term) ->
op_switch_to_sync(Config) ->
{Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ NumOfReqs = 500,
NewHConfig =
- HConfig#{logger_disk_log_h => DLHConfig#{toggle_sync_qlen => 3,
- drop_new_reqs_qlen => 501,
- flush_reqs_qlen => 2000,
- enable_burst_limit => false}},
+ HConfig#{config => DLHConfig#{sync_mode_qlen => 2,
+ drop_mode_qlen => NumOfReqs+1,
+ flush_qlen => 2*NumOfReqs,
+ burst_limit_enable => false}},
ok = logger:set_handler_config(?MODULE, NewHConfig),
- NumOfReqs = 500,
- send_burst({n,NumOfReqs}, seq, {chars,79}, info),
- NumOfReqs = count_lines(Log),
- ok = file:delete(Log).
+ send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
+ Lines = count_lines(Log),
+ NumOfReqs = Lines,
+ ok = file_delete(Log),
+ ok.
op_switch_to_sync(cleanup, _Config) ->
ok = stop_handler(?MODULE).
+op_switch_to_drop() ->
+ [{timetrap,{seconds,180}}].
op_switch_to_drop(Config) ->
- {Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
-
- NewHConfig =
- HConfig#{logger_disk_log_h => DLHConfig#{toggle_sync_qlen => 2,
- drop_new_reqs_qlen => 3,
- flush_reqs_qlen => 600,
- enable_burst_limit => false}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
- NumOfReqs = 500,
- send_burst({n,NumOfReqs}, seq, {chars,79}, info),
- Logged = count_lines(Log),
- ct:pal("Number of messages dropped = ~w (~w)",
- [NumOfReqs-Logged,NumOfReqs]),
- true = (Logged < NumOfReqs),
- ok = file:delete(Log).
+ Test =
+ fun() ->
+ {Log,HConfig,DLHConfig} =
+ start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ NumOfReqs = 300,
+ Procs = 2,
+ Bursts = 10,
+ NewHConfig =
+ HConfig#{config =>
+ DLHConfig#{sync_mode_qlen => 1,
+ drop_mode_qlen => 2,
+ flush_qlen => Procs*NumOfReqs*Bursts,
+ burst_limit_enable => false}},
+ ok = logger:set_handler_config(?MODULE, NewHConfig),
+ %% It sometimes happens that the handler either gets
+ %% the requests in a slow enough pace so that dropping
+ %% never occurs. Therefore, lets generate a number of
+ %% bursts to increase the chance of message buildup.
+ [send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice) ||
+ _ <- lists:seq(1, Bursts)],
+ Logged = count_lines(Log),
+ ok = stop_handler(?MODULE),
+ ct:pal("Number of messages dropped = ~w (~w)",
+ [Procs*NumOfReqs*Bursts-Logged,Procs*NumOfReqs*Bursts]),
+ true = (Logged < (Procs*NumOfReqs*Bursts)),
+ true = (Logged > 0),
+ _ = file_delete(Log),
+ ok
+ end,
+ %% As it's tricky to get the timing right in only one go, we perform the
+ %% test repeatedly, hoping that will generate a successful result.
+ case repeat_until_ok(Test, 10) of
+ {ok,{Failures,_Result}} ->
+ ct:log("Failed ~w times before success!", [Failures]);
+ {fails,Reason} ->
+ ct:fail(Reason)
+ end.
op_switch_to_drop(cleanup, _Config) ->
- ok = stop_handler(?MODULE).
+ _ = stop_handler(?MODULE).
op_switch_to_flush() ->
[{timetrap,{minutes,3}}].
op_switch_to_flush(Config) ->
- {Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
-
- %% it's important that both async and sync requests have been queued
- %% when the flush happens (verify with coverage of flush_log_requests/2)
+ Test =
+ fun() ->
+ {Log,HConfig,DLHConfig} =
+ start_handler(?MODULE, ?FUNCTION_NAME, Config),
+
+ %% NOTE: it's important that both async and sync
+ %% requests have been queued when the flush happens
+ %% (verify with coverage of flush_log_requests/2)
- NewHConfig =
- HConfig#{logger_disk_log_h => DLHConfig#{toggle_sync_qlen => 2,
- drop_new_reqs_qlen => 99,
- flush_reqs_qlen => 100,
- enable_burst_limit => false}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
- NumOfReqs = 1000,
- Procs = 500,
- send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, info),
- Logged = count_lines(Log),
- ct:pal("Number of messages flushed/dropped = ~w (~w)",
- [(NumOfReqs*Procs)-Logged,NumOfReqs*Procs]),
- true = (Logged < (NumOfReqs*Procs)),
- ok = file:delete(Log).
+ NewHConfig =
+ HConfig#{config =>
+ DLHConfig#{sync_mode_qlen => 2,
+ %% disable drop mode
+ drop_mode_qlen => 300,
+ flush_qlen => 300,
+ burst_limit_enable => false}},
+ ok = logger:set_handler_config(?MODULE, NewHConfig),
+ NumOfReqs = 1500,
+ Procs = 10,
+ Bursts = 10,
+ %% It sometimes happens that the handler either gets
+ %% the requests in a slow enough pace so that flushing
+ %% never occurs, or it gets all messages at once,
+ %% causing all messages to get flushed (no dropping of
+ %% sync messages gets tested). Therefore, lets
+ %% generate a number of bursts to increase the chance
+ %% of message buildup in some random fashion.
+ [send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice) ||
+ _ <- lists:seq(1,Bursts)],
+ Logged = count_lines(Log),
+ ok= stop_handler(?MODULE),
+ ct:pal("Number of messages flushed/dropped = ~w (~w)",
+ [NumOfReqs*Procs*Bursts-Logged,NumOfReqs*Procs*Bursts]),
+ true = (Logged < (NumOfReqs*Procs*Bursts)),
+ true = (Logged > 0),
+ _ = file_delete(Log),
+ ok
+ end,
+ %% As it's tricky to get the timing right in only one go, we perform the
+ %% test repeatedly, hoping that will generate a successful result.
+ case repeat_until_ok(Test, 10) of
+ {ok,{Failures,_Result}} ->
+ ct:log("Failed ~w times before success!", [Failures]);
+ {fails,Reason} ->
+ ct:fail(Reason)
+ end.
op_switch_to_flush(cleanup, _Config) ->
- ok = stop_handler(?MODULE).
+ _ = stop_handler(?MODULE).
limit_burst_disabled(Config) ->
{Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
NewHConfig =
- HConfig#{logger_disk_log_h => DLHConfig#{enable_burst_limit => false,
- burst_limit_size => 10,
- burst_window_time => 2000,
- drop_new_reqs_qlen => 200,
- flush_reqs_qlen => 300}},
+ HConfig#{config => DLHConfig#{burst_limit_enable => false,
+ burst_limit_max_count => 10,
+ burst_limit_window_time => 2000,
+ drop_mode_qlen => 200,
+ flush_qlen => 300}},
ok = logger:set_handler_config(?MODULE, NewHConfig),
NumOfReqs = 100,
- send_burst({n,NumOfReqs}, seq, {chars,79}, info),
+ send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
Logged = count_lines(Log),
ct:pal("Number of messages logged = ~w", [Logged]),
- ok = file:delete(Log),
- NumOfReqs = Logged.
+ NumOfReqs = Logged,
+ ok = file_delete(Log),
+ ok.
limit_burst_disabled(cleanup, _Config) ->
ok = stop_handler(?MODULE).
@@ -928,18 +1008,19 @@ limit_burst_enabled_one(Config) ->
{Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
ReqLimit = 10,
NewHConfig =
- HConfig#{logger_disk_log_h => DLHConfig#{enable_burst_limit => true,
- burst_limit_size => ReqLimit,
- burst_window_time => 2000,
- drop_new_reqs_qlen => 200,
- flush_reqs_qlen => 300}},
+ HConfig#{config => DLHConfig#{burst_limit_enable => true,
+ burst_limit_max_count => ReqLimit,
+ burst_limit_window_time => 2000,
+ drop_mode_qlen => 200,
+ flush_qlen => 300}},
ok = logger:set_handler_config(?MODULE, NewHConfig),
NumOfReqs = 100,
- send_burst({n,NumOfReqs}, seq, {chars,79}, info),
+ send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
Logged = count_lines(Log),
ct:pal("Number of messages logged = ~w", [Logged]),
- ok = file:delete(Log),
- ReqLimit = Logged.
+ ReqLimit = Logged,
+ ok = file_delete(Log),
+ ok.
limit_burst_enabled_one(cleanup, _Config) ->
ok = stop_handler(?MODULE).
@@ -948,58 +1029,59 @@ limit_burst_enabled_period(Config) ->
ReqLimit = 10,
BurstTWin = 1000,
NewHConfig =
- HConfig#{logger_disk_log_h => DLHConfig#{enable_burst_limit => true,
- burst_limit_size => ReqLimit,
- burst_window_time => BurstTWin,
- drop_new_reqs_qlen => 20000,
- flush_reqs_qlen => 20001}},
+ HConfig#{config => DLHConfig#{burst_limit_enable => true,
+ burst_limit_max_count => ReqLimit,
+ burst_limit_window_time => BurstTWin,
+ drop_mode_qlen => 20000,
+ flush_qlen => 20001}},
ok = logger:set_handler_config(?MODULE, NewHConfig),
Windows = 3,
- Sent = send_burst({t,BurstTWin*Windows}, seq, {chars,79}, info),
+ Sent = send_burst({t,BurstTWin*Windows}, seq, {chars,79}, notice),
Logged = count_lines(Log),
ct:pal("Number of messages sent = ~w~nNumber of messages logged = ~w",
[Sent,Logged]),
- ok = file:delete(Log),
true = (Logged > (ReqLimit*Windows)) andalso
- (Logged < (ReqLimit*(Windows+2))).
+ (Logged < (ReqLimit*(Windows+2))),
+ ok = file_delete(Log),
+ ok.
limit_burst_enabled_period(cleanup, _Config) ->
ok = stop_handler(?MODULE).
kill_disabled(Config) ->
{Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
NewHConfig =
- HConfig#{logger_disk_log_h=>DLHConfig#{enable_kill_overloaded=>false,
- handler_overloaded_qlen=>10,
- handler_overloaded_mem=>100}},
+ HConfig#{config=>DLHConfig#{overload_kill_enable=>false,
+ overload_kill_qlen=>10,
+ overload_kill_mem_size=>100}},
ok = logger:set_handler_config(?MODULE, NewHConfig),
NumOfReqs = 100,
- send_burst({n,NumOfReqs}, seq, {chars,79}, info),
+ send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
Logged = count_lines(Log),
ct:pal("Number of messages logged = ~w", [Logged]),
- ok = file:delete(Log),
- true = is_pid(whereis(?MODULE)),
+ ok = file_delete(Log),
+ true = is_pid(whereis(h_proc_name())),
ok.
kill_disabled(cleanup, _Config) ->
ok = stop_handler(?MODULE).
qlen_kill_new(Config) ->
- {_Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
- Pid0 = whereis(?MODULE),
+ {Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ Pid0 = whereis(h_proc_name()),
{_,Mem0} = process_info(Pid0, memory),
- RestartAfter = 2000,
+ RestartAfter = ?OVERLOAD_KILL_RESTART_AFTER,
NewHConfig =
- HConfig#{logger_disk_log_h =>
- DLHConfig#{enable_kill_overloaded=>true,
- handler_overloaded_qlen=>10,
- handler_overloaded_mem=>Mem0+50000,
- handler_restart_after=>RestartAfter}},
+ HConfig#{config =>
+ DLHConfig#{overload_kill_enable=>true,
+ overload_kill_qlen=>10,
+ overload_kill_mem_size=>Mem0+50000,
+ overload_kill_restart_after=>RestartAfter}},
ok = logger:set_handler_config(?MODULE, NewHConfig),
MRef = erlang:monitor(process, Pid0),
NumOfReqs = 100,
- Procs = 2,
- send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, info),
- %% send_burst({n,NumOfReqs}, seq, {chars,79}, info),
+ Procs = 4,
+ send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice),
+ %% send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
receive
{'DOWN', MRef, _, _, Info} ->
case Info of
@@ -1008,8 +1090,8 @@ qlen_kill_new(Config) ->
killed ->
ct:pal("Slow shutdown, handler process was killed!", [])
end,
- timer:sleep(RestartAfter + 1000),
- true = is_pid(whereis(?MODULE)),
+ file_delete(Log),
+ {ok,_} = wait_for_process_up(RestartAfter * 3),
ok
after
5000 ->
@@ -1021,22 +1103,22 @@ qlen_kill_new(cleanup, _Config) ->
ok = stop_handler(?MODULE).
mem_kill_new(Config) ->
- {_Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
- Pid0 = whereis(?MODULE),
+ {Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ Pid0 = whereis(h_proc_name()),
{_,Mem0} = process_info(Pid0, memory),
- RestartAfter = 2000,
+ RestartAfter = ?OVERLOAD_KILL_RESTART_AFTER,
NewHConfig =
- HConfig#{logger_disk_log_h =>
- DLHConfig#{enable_kill_overloaded=>true,
- handler_overloaded_qlen=>50000,
- handler_overloaded_mem=>Mem0+500,
- handler_restart_after=>RestartAfter}},
+ HConfig#{config =>
+ DLHConfig#{overload_kill_enable=>true,
+ overload_kill_qlen=>50000,
+ overload_kill_mem_size=>Mem0+500,
+ overload_kill_restart_after=>RestartAfter}},
ok = logger:set_handler_config(?MODULE, NewHConfig),
MRef = erlang:monitor(process, Pid0),
NumOfReqs = 100,
- Procs = 2,
- send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, info),
- %% send_burst({n,NumOfReqs}, seq, {chars,79}, info),
+ Procs = 4,
+ send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice),
+ %% send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
receive
{'DOWN', MRef, _, _, Info} ->
case Info of
@@ -1045,8 +1127,8 @@ mem_kill_new(Config) ->
killed ->
ct:pal("Slow shutdown, handler process was killed!", [])
end,
- timer:sleep(RestartAfter * 2),
- true = is_pid(whereis(?MODULE)),
+ file_delete(Log),
+ {ok,_} = wait_for_process_up(RestartAfter * 3),
ok
after
5000 ->
@@ -1057,53 +1139,58 @@ mem_kill_new(Config) ->
mem_kill_new(cleanup, _Config) ->
ok = stop_handler(?MODULE).
+restart_after() ->
+ [{timetrap,{minutes,2}}].
restart_after(Config) ->
{Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
NewHConfig1 =
- HConfig#{logger_disk_log_h=>DLHConfig#{enable_kill_overloaded=>true,
- handler_overloaded_qlen=>10,
- handler_restart_after=>never}},
+ HConfig#{config=>DLHConfig#{overload_kill_enable=>true,
+ overload_kill_qlen=>10,
+ overload_kill_restart_after=>infinity}},
ok = logger:set_handler_config(?MODULE, NewHConfig1),
- MRef1 = erlang:monitor(process, whereis(?MODULE)),
+ MRef1 = erlang:monitor(process, whereis(h_proc_name())),
%% kill handler
- send_burst({n,100}, {spawn,2,0}, {chars,79}, info),
+ send_burst({n,100}, {spawn,4,0}, {chars,79}, notice),
receive
- {'DOWN', MRef1, _, _, _Info1} ->
- timer:sleep(?HANDLER_RESTART_AFTER + 1000),
- undefined = whereis(?MODULE),
+ {'DOWN', MRef1, _, _, _Reason1} ->
+ file_delete(Log),
+ error = wait_for_process_up(?OVERLOAD_KILL_RESTART_AFTER * 3),
ok
after
5000 ->
+ Info1 = logger_std_h:info(?MODULE),
+ ct:pal("Handler state = ~p", [Info1]),
ct:fail("Handler not dead! It should not have survived this!")
end,
{Log,_,_} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
- RestartAfter = 2000,
+ RestartAfter = ?OVERLOAD_KILL_RESTART_AFTER,
NewHConfig2 =
- HConfig#{logger_disk_log_h=>DLHConfig#{enable_kill_overloaded=>true,
- handler_overloaded_qlen=>10,
- handler_restart_after=>RestartAfter}},
+ HConfig#{config=>DLHConfig#{overload_kill_enable=>true,
+ overload_kill_qlen=>10,
+ overload_kill_restart_after=>RestartAfter}},
ok = logger:set_handler_config(?MODULE, NewHConfig2),
- Pid0 = whereis(?MODULE),
+ Pid0 = whereis(h_proc_name()),
MRef2 = erlang:monitor(process, Pid0),
%% kill handler
- send_burst({n,100}, {spawn,2,0}, {chars,79}, info),
+ send_burst({n,100}, {spawn,4,0}, {chars,79}, notice),
receive
- {'DOWN', MRef2, _, _, _Info2} ->
- timer:sleep(RestartAfter + 1000),
- Pid1 = whereis(?MODULE),
- true = is_pid(Pid1),
+ {'DOWN', MRef2, _, _, _Reason2} ->
+ file_delete(Log),
+ {ok,Pid1} = wait_for_process_up(RestartAfter * 3),
false = (Pid1 == Pid0),
ok
after
5000 ->
+ Info2 = logger_std_h:info(?MODULE),
+ ct:pal("Handler state = ~p", [Info2]),
ct:fail("Handler not dead! It should not have survived this!")
end,
ok.
restart_after(cleanup, _Config) ->
ok = stop_handler(?MODULE).
-%% send handler requests (filesync, info, reset, change_config)
+%% send handler requests (sync, info, reset, change_config)
%% during high load to verify that sync, dropping and flushing is
%% handled correctly.
handler_requests_under_load() ->
@@ -1111,18 +1198,18 @@ handler_requests_under_load() ->
handler_requests_under_load(Config) ->
{Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
NewHConfig =
- HConfig#{logger_disk_log_h => DLHConfig#{toggle_sync_qlen => 2,
- drop_new_reqs_qlen => 1000,
- flush_reqs_qlen => 2000,
- enable_burst_limit => false}},
+ HConfig#{config => DLHConfig#{sync_mode_qlen => 2,
+ drop_mode_qlen => 1000,
+ flush_qlen => 2000,
+ burst_limit_enable => false}},
ok = logger:set_handler_config(?MODULE, NewHConfig),
- Pid = spawn_link(fun() -> send_requests(?MODULE, 1, [{disk_log_sync,[]},
+ Pid = spawn_link(fun() -> send_requests(?MODULE, 1, [{filesync,[]},
{info,[]},
{reset,[]},
{change_config,[]}])
end),
Procs = 100,
- Sent = Procs * send_burst({n,5000}, {spawn,Procs,10}, {chars,79}, info),
+ Sent = Procs * send_burst({n,5000}, {spawn,Procs,10}, {chars,79}, notice),
Pid ! {self(),finish},
ReqResult = receive {Pid,Result} -> Result end,
Logged = count_lines(Log),
@@ -1135,7 +1222,7 @@ handler_requests_under_load(Config) ->
Errors = [{Req,FindError(Res)} || {Req,Res} <- ReqResult],
NoOfReqs = lists:foldl(fun({_,Res}, N) -> N + length(Res) end, 0, ReqResult),
ct:pal("~w requests made. Errors: ~n~p", [NoOfReqs,Errors]),
- ok = file:delete(Log).
+ ok = file_delete(Log).
handler_requests_under_load(cleanup, _Config) ->
ok = stop_handler(?MODULE).
@@ -1149,7 +1236,7 @@ send_requests(HName, TO, Reqs = [{Req,Res}|Rs]) ->
case Req of
change_config ->
logger:set_handler_config(HName, logger_disk_log_h,
- #{enable_kill_overloaded =>
+ #{overload_kill_enable =>
false});
Func ->
logger_disk_log_h:Func(HName)
@@ -1163,21 +1250,22 @@ start_handler(Name, FuncName, Config) ->
Dir = ?config(priv_dir,Config),
File = filename:join(Dir, FuncName),
ct:pal("Logging to ~tp", [File]),
+ FullFile = lists:concat([File,".1"]),
+ _ = file_delete(FullFile),
ok = logger:add_handler(Name,
logger_disk_log_h,
- #{disk_log_opts=>#{file => File,
- max_no_files => 1,
- max_no_bytes => 100000000},
+ #{config=>#{file => File,
+ max_no_files => 1,
+ max_no_bytes => 100000000},
filter_default=>log,
filters=>?DEFAULT_HANDLER_FILTERS([Name]),
formatter=>{?MODULE,op}}),
- {ok,{_,HConfig = #{logger_disk_log_h := DLHConfig}}} =
- logger:get_handler_config(Name),
- {lists:concat([File,".1"]),HConfig,DLHConfig}.
+ {ok,HConfig = #{config := DLHConfig}} = logger:get_handler_config(Name),
+ {FullFile,HConfig,DLHConfig}.
stop_handler(Name) ->
- ok = logger:remove_handler(Name),
- ct:pal("Handler ~p stopped!", [Name]).
+ ct:pal("Stopping handler ~p!", [Name]),
+ logger:remove_handler(Name).
send_burst(NorT, Type, {chars,Sz}, Class) ->
Text = [34 + rand:uniform(126-34) || _ <- lists:seq(1,Sz)],
@@ -1200,12 +1288,9 @@ send_n_burst(N, seq, Text, Class) ->
send_n_burst(N-1, seq, Text, Class);
send_n_burst(N, {spawn,Ps,TO}, Text, Class) ->
ct:pal("~w processes each sending ~w messages", [Ps,N]),
- PerProc = fun() ->
- send_n_burst(N, seq, Text, Class)
- end,
MRefs = [begin if TO == 0 -> ok; true -> timer:sleep(TO) end,
- monitor(process,spawn_link(PerProc)) end ||
- _ <- lists:seq(1,Ps)],
+ monitor(process,spawn_link(per_proc_fun(N,Text,Class,X)))
+ end || X <- lists:seq(1,Ps)],
lists:foreach(fun(MRef) ->
receive
{'DOWN', MRef, _, _, _} ->
@@ -1224,6 +1309,16 @@ send_t_burst(T0, T, Text, Class, N) ->
send_t_burst(T0, T, Text, Class, N+1)
end.
+per_proc_fun(N,Text,Class,X) when X rem 2 == 0 ->
+ fun() ->
+ process_flag(priority,high),
+ send_n_burst(N, seq, Text, Class)
+ end;
+per_proc_fun(N,Text,Class,_) ->
+ fun() ->
+ send_n_burst(N, seq, Text, Class)
+ end.
+
%%%-----------------------------------------------------------------
%%% Formatter callback
%%% Using this to send the formatted string back to the test case
@@ -1249,9 +1344,11 @@ format(#{msg:={report,#{label:={gen_server,terminate}}}},op) ->
"";
format(#{msg:={report,#{label:={proc_lib,crash}}}},op) ->
"";
-format(#{msg:={F,A}},Pid) when is_list(F), is_list(A) ->
+format(#{msg:={F,A}},OpOrPid) when is_list(F), is_list(A) ->
String = lists:flatten(io_lib:format(F,A)),
- Pid ! {log,String},
+ if is_pid(OpOrPid) -> OpOrPid ! {log,String};
+ true -> ok
+ end,
String++"\n";
format(#{msg:={string,String0}},Pid) ->
String = unicode:characters_to_list(String0),
@@ -1267,16 +1364,17 @@ remove(Handler, LogName) ->
HState = #{log_names := Logs} = logger_disk_log_h:info(),
false = maps:is_key(LogName, HState),
false = lists:member(LogName, Logs),
- false = logger_config:exist(logger, LogName),
+ false = logger_config:exist(?LOGGER_TABLE, LogName),
{error,no_such_log} = disk_log:info(LogName),
ok.
start_and_add(Name, Config, LogOpts) ->
- ct:pal("Adding handler ~w with: ~p",
- [Name,Config#{disk_log_opts=>LogOpts}]),
- ok = logger:add_handler(Name, logger_disk_log_h,
- Config#{disk_log_opts=>LogOpts}),
- Pid = whereis(Name),
+ HConfig = maps:get(config, Config, #{}),
+ HConfig1 = maps:merge(HConfig, LogOpts),
+ Config1 = Config#{config=>HConfig1},
+ ct:pal("Adding handler ~w with: ~p", [Name,Config1]),
+ ok = logger:add_handler(Name, logger_disk_log_h, Config1),
+ Pid = whereis(h_proc_name(Name)),
true = is_pid(Pid),
Name = proplists:get_value(name, disk_log:info(Name)),
ok.
@@ -1284,7 +1382,7 @@ start_and_add(Name, Config, LogOpts) ->
remove_and_stop(Handler) ->
ok = logger:remove_handler(Handler),
timer:sleep(500),
- undefined = whereis(Handler),
+ undefined = whereis(h_proc_name(Handler)),
ok.
try_read_file(FileName, Expected, Time) ->
@@ -1340,31 +1438,58 @@ wait_until_written(File, Sz) ->
{ok,#file_info{size = Sz}} ->
timer:sleep(1000),
case file:read_file_info(File) of
- {ok,#file_info{size = Sz1}} ->
+ {ok,#file_info{size = Sz}} ->
ok;
- {ok,#file_info{size = Sz2}} ->
- wait_until_written(File, Sz2)
+ {ok,#file_info{size = Sz1}} ->
+ wait_until_written(File, Sz1)
end;
{ok,#file_info{size = Sz1}} ->
wait_until_written(File, Sz1)
end.
count_lines1(File) ->
- Counter = fun Cnt(Dev,LC) ->
- case file:read_line(Dev) of
- eof -> LC;
- _ -> Cnt(Dev,LC+1)
- end
- end,
{_,Dev} = file:open(File, [read]),
- Lines = Counter(Dev, 0),
+ Lines = count_lines2(Dev, 0),
file:close(Dev),
Lines.
+count_lines2(Dev, LC) ->
+ case file:read_line(Dev) of
+ {ok,"Handler logger_disk_log_h_SUITE " ++_} ->
+ %% Not counting handler info
+ count_lines2(Dev,LC);
+ {ok,_} ->
+ count_lines2(Dev,LC+1);
+ eof -> LC
+ end.
+
+repeat_until_ok(Fun, N) ->
+ repeat_until_ok(Fun, 0, N, undefined).
+
+repeat_until_ok(_Fun, Stop, Stop, Reason) ->
+ {fails,Reason};
+
+repeat_until_ok(Fun, C, Stop, FirstReason) ->
+ if C > 0 -> timer:sleep(5000);
+ true -> ok
+ end,
+ try Fun() of
+ Result ->
+ {ok,{C,Result}}
+ catch
+ _:Reason:Stack ->
+ ct:pal("Test fails: ~p (~p)~n", [Reason,hd(Stack)]),
+ if FirstReason == undefined ->
+ repeat_until_ok(Fun, C+1, Stop, {Reason,Stack});
+ true ->
+ repeat_until_ok(Fun, C+1, Stop, FirstReason)
+ end
+ end.
+
start_tracer(Trace,Expected) ->
Pid = self(),
dbg:tracer(process,{fun tracer/2,{Pid,Expected}}),
- dbg:p(whereis(?MODULE),[c]),
+ dbg:p(h_proc_name(),[c]),
tpl(Trace),
ok.
@@ -1382,7 +1507,8 @@ tpl([{M,F,A}|Trace]) ->
tpl([]) ->
ok.
-tracer({trace,_,call,{logger_disk_log_h,handle_cast,[{Op,_}|_]}}, {Pid,[{Mod,Func,Op}|Expected]}) ->
+tracer({trace,_,call,{logger_disk_log_h,handle_cast,[Op|_]}},
+ {Pid,[{Mod,Func,Op}|Expected]}) ->
maybe_tracer_done(Pid,Expected,{Mod,Func,Op});
tracer({trace,_,call,{Mod=disk_log,Func=blog,[_,Data]}}, {Pid,[{Mod,Func,Data}|Expected]}) ->
maybe_tracer_done(Pid,Expected,{Mod,Func,Data});
@@ -1412,3 +1538,43 @@ check_tracer(T) ->
dbg:stop_clear(),
ct:fail({timeout,tracer})
end.
+
+escape([$+|Rest]) ->
+ [$\\,$+|escape(Rest)];
+escape([H|T]) ->
+ [H|escape(T)];
+escape([]) ->
+ [].
+
+h_proc_name() ->
+ h_proc_name(?MODULE).
+h_proc_name(Name) ->
+ list_to_atom(lists:concat([logger_disk_log_h,"_",Name])).
+
+wait_for_process_up(T) ->
+ wait_for_process_up(?MODULE, h_proc_name(), T).
+
+wait_for_process_up(Name, RegName, T) ->
+ N = (T div 500) + 1,
+ wait_for_process_up1(Name, RegName, N).
+
+wait_for_process_up1(_Name, _RegName, 0) ->
+ error;
+wait_for_process_up1(Name, RegName, N) ->
+ timer:sleep(500),
+ case whereis(RegName) of
+ Pid when is_pid(Pid) ->
+ case logger:get_handler_config(Name) of
+ {ok,_} ->
+ %% ct:pal("Process ~p up (~p tries left)",[Name,N]),
+ {ok,Pid};
+ _ ->
+ wait_for_process_up1(Name, RegName, N-1)
+ end;
+ undefined ->
+ %% ct:pal("Waiting for process ~p (~p tries left)",[Name,N]),
+ wait_for_process_up1(Name, RegName, N-1)
+ end.
+
+file_delete(Log) ->
+ file:delete(Log).
diff --git a/lib/kernel/test/logger_env_var_SUITE.erl b/lib/kernel/test/logger_env_var_SUITE.erl
index c2d3364701..e8d1a313dc 100644
--- a/lib/kernel/test/logger_env_var_SUITE.erl
+++ b/lib/kernel/test/logger_env_var_SUITE.erl
@@ -1,4 +1,4 @@
-%
+%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2018. All Rights Reserved.
@@ -21,431 +21,663 @@
-compile(export_all).
--include_lib("common_test/include/ct.hrl").
-include_lib("kernel/include/logger.hrl").
-include_lib("kernel/src/logger_internal.hrl").
--define(all_vars,[{kernel,logger_dest},
- {kernel,logger_level},
- {kernel,logger_log_progress},
- {kernel,logger_sasl_compatible},
- {kernel,error_logger}]).
+-import(logger_test_lib,[setup/2,log/3,sync_and_read/3]).
suite() ->
- [{timetrap,{seconds,30}}].
+ [{timetrap,{seconds,60}},
+ {ct_hooks,[logger_test_lib]}].
init_per_suite(Config) ->
- Env = [{App,Key,application:get_env(App,Key)} || {App,Key} <- ?all_vars],
- Removed = cleanup(),
- [{env,Env},{logger,Removed}|Config].
-
-end_per_suite(Config) ->
- [application:set_env(App,Key,Val) ||
- {App,Key,Val} <- ?config(env,Config),
- Val =/= undefined],
- Hs = ?config(logger,Config),
- [ok = logger:add_handler(Id,Mod,C) || {Id,Mod,C} <- Hs],
- ok.
-
-init_per_group(_Group, Config) ->
- Config.
-
-end_per_group(_Group, _Config) ->
- ok.
-
-init_per_testcase(_TestCase, Config) ->
Config.
-end_per_testcase(Case, Config) ->
- try apply(?MODULE,Case,[cleanup,Config])
- catch error:undef -> ok
- end,
- cleanup(),
+end_per_suite(_Config) ->
ok.
groups() ->
- [].
-
-all() ->
+ [{error_logger,[],[error_logger_tty,
+ error_logger_tty_sasl_compatible,
+ error_logger_false,
+ error_logger_false_progress,
+ error_logger_false_sasl_compatible,
+ error_logger_silent,
+ error_logger_silent_sasl_compatible,
+ error_logger_file]},
+ {logger,[],[logger_file,
+ logger_file_sasl_compatible,
+ logger_file_log_progress,
+ logger_file_no_filter,
+ logger_file_no_filter_level,
+ logger_file_formatter,
+ logger_filters,
+ logger_filters_stop,
+ logger_module_level,
+ logger_disk_log,
+ logger_disk_log_formatter,
+ logger_undefined,
+ logger_many_handlers_default_first,
+ logger_many_handlers_default_last,
+ logger_many_handlers_default_last_broken_filter
+ ]},
+ {bad,[],[bad_error_logger,
+ bad_level,
+ bad_sasl_compatibility]}].
+
+all() ->
[default,
default_sasl_compatible,
- dest_tty,
- dest_tty_sasl_compatible,
- dest_false,
- dest_false_progress,
- dest_false_sasl_compatible,
- dest_silent,
- dest_silent_sasl_compatible,
- dest_file_old,
- dest_file,
- dest_disk_log,
- %% disk_log_vars, % or test this in logger_disk_log_SUITE?
sasl_compatible_false,
sasl_compatible_false_no_progress,
sasl_compatible,
- bad_dest%% ,
- %% bad_level,
- %% bad_sasl_compatibility,
- %% bad_progress
+ all_logger_level,
+ {group,bad},
+ {group,error_logger},
+ {group,logger}
].
default(Config) ->
- {ok,{_Log,Hs}} = setup(Config,?FUNCTION_NAME,
- undefined,
- undefined, % dest
- undefined, % level
- undefined, % sasl comp (default=false)
- undefined), % progress (default=false)
- {logger_std_h,logger_std_h,StdC} = lists:keyfind(logger_std_h,1,Hs),
- true = is_pid(whereis(logger_std_h)),
- info = maps:get(level,StdC),
+ {ok,#{primary:=P,handlers:=Hs,module_levels:=ML},_Node} = setup(Config,[]),
+ notice = maps:get(level,P),
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
StdFilters = maps:get(filters,StdC),
- {domain,{_,{log,prefix_of,[beam,erlang,otp,sasl]}}} =
- lists:keyfind(domain,1,StdFilters),
- true = lists:keymember(stop_progress,1,StdFilters),
- false = lists:keymember(logger_simple,1,Hs),
- false = lists:keymember(sasl_h,1,Hs),
- false = is_pid(whereis(sasl_h)),
+ {domain,{_,{log,super,[otp,sasl]}}} = lists:keyfind(domain,1,StdFilters),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+ [] = ML,
ok.
default_sasl_compatible(Config) ->
- {ok,{_Log,Hs}} = setup(Config,?FUNCTION_NAME,
- undefined,
- undefined, % dest
- undefined, % level
- true, % sasl comp (default=false)
- undefined), % progress (default=false)
- {logger_std_h,logger_std_h,StdC} = lists:keyfind(logger_std_h,1,Hs),
- true = is_pid(whereis(logger_std_h)),
- info = maps:get(level,StdC),
+ {ok,#{primary:=P,handlers:=Hs,module_levels:=ML},_Node} =
+ setup(Config,[{logger_sasl_compatible,true}]),
+ info = maps:get(level,P),
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
StdFilters = maps:get(filters,StdC),
- {domain,{_,{log,prefix_of,[beam,erlang,otp]}}} =
- lists:keyfind(domain,1,StdFilters),
- false = lists:keymember(stop_progress,1,StdFilters),
- false = lists:keymember(logger_simple,1,Hs),
- true = lists:keymember(sasl_h,1,Hs),
- true = is_pid(whereis(sasl_h)),
+ {domain,{_,{log,super,[otp]}}} = lists:keyfind(domain,1,StdFilters),
+ false = exists(simple,Hs),
+ true = exists(sasl,Hs),
+ [] = ML,
ok.
-dest_tty(Config) ->
- {ok,{_Log,Hs}} = setup(Config,?FUNCTION_NAME,
- logger_dest,
- tty, % dest
- undefined, % level
- undefined, % sasl comp (default=false)
- undefined), % progress (default=false)
- {logger_std_h,logger_std_h,StdC} = lists:keyfind(logger_std_h,1,Hs),
- true = is_pid(whereis(logger_std_h)),
- info = maps:get(level,StdC),
+error_logger_tty(Config) ->
+ {ok,#{primary:=P,handlers:=Hs,module_levels:=ML},_Node} =
+ setup(Config,[{error_logger,tty}]),
+ notice = maps:get(level,P),
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
StdFilters = maps:get(filters,StdC),
- {domain,{_,{log,prefix_of,[beam,erlang,otp,sasl]}}} =
- lists:keyfind(domain,1,StdFilters),
- true = lists:keymember(stop_progress,1,StdFilters),
- false = lists:keymember(logger_simple,1,Hs),
- false = lists:keymember(sasl_h,1,Hs),
- false = is_pid(whereis(sasl_h)),
+ {domain,{_,{log,super,[otp,sasl]}}} = lists:keyfind(domain,1,StdFilters),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+ [] = ML,
ok.
-dest_tty_sasl_compatible(Config) ->
- {ok,{_Log,Hs}} = setup(Config,?FUNCTION_NAME,
- logger_dest,
- tty, % dest
- undefined, % level
- true, % sasl comp (default=false)
- undefined), % progress (default=false)
- {logger_std_h,logger_std_h,StdC} = lists:keyfind(logger_std_h,1,Hs),
- true = is_pid(whereis(logger_std_h)),
- info = maps:get(level,StdC),
+error_logger_tty_sasl_compatible(Config) ->
+ {ok,#{primary:=P,handlers:=Hs,module_levels:=ML},_Node} =
+ setup(Config,
+ [{error_logger,tty},
+ {logger_sasl_compatible,true}]),
+ info = maps:get(level,P),
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
StdFilters = maps:get(filters,StdC),
- {domain,{_,{log,prefix_of,[beam,erlang,otp]}}} =
- lists:keyfind(domain,1,StdFilters),
- false = lists:keymember(stop_progress,1,StdFilters),
- false = lists:keymember(logger_simple,1,Hs),
- true = lists:keymember(sasl_h,1,Hs),
- true = is_pid(whereis(sasl_h)),
+ {domain,{_,{log,super,[otp]}}} = lists:keyfind(domain,1,StdFilters),
+ false = exists(simple,Hs),
+ true = exists(sasl,Hs),
+ [] = ML,
ok.
-dest_false(Config) ->
- {ok,{_Log,Hs}} = setup(Config,?FUNCTION_NAME,
- logger_dest,
- false, % dest
- notice, % level
- undefined, % sasl comp (default=false)
- undefined), % progress (default=false)
- false = lists:keymember(logger_std_h,1,Hs),
- {logger_simple,logger_simple,SimpleC} = lists:keyfind(logger_simple,1,Hs),
- notice = maps:get(level,SimpleC),
+error_logger_false(Config) ->
+ {ok,#{handlers:=Hs,primary:=P,module_levels:=ML},_Node} =
+ setup(Config,
+ [{error_logger,false},
+ {logger_level,notice}]),
+ false = exists(?STANDARD_HANDLER,Hs),
+ #{module:=logger_simple_h} = SimpleC = find(simple,Hs),
+ all = maps:get(level,SimpleC),
+ notice = maps:get(level,P),
SimpleFilters = maps:get(filters,SimpleC),
- {domain,{_,{log,prefix_of,[beam,erlang,otp,sasl]}}} =
- lists:keyfind(domain,1,SimpleFilters),
- true = lists:keymember(stop_progress,1,SimpleFilters),
- false = lists:keymember(sasl_h,1,Hs),
+ {domain,{_,{log,super,[otp,sasl]}}} = lists:keyfind(domain,1,SimpleFilters),
+ false = exists(sasl,Hs),
+ [] = ML,
ok.
-dest_false_progress(Config) ->
- {ok,{_Log,Hs}} = setup(Config,?FUNCTION_NAME,
- logger_dest,
- false, % dest
- notice, % level
- undefined, % sasl comp (default=false)
- true), % progress (default=false)
- false = lists:keymember(logger_std_h,1,Hs),
- {logger_simple,logger_simple,SimpleC} = lists:keyfind(logger_simple,1,Hs),
- notice = maps:get(level,SimpleC),
+error_logger_false_progress(Config) ->
+ {ok,#{handlers:=Hs,primary:=P,module_levels:=ML},_Node} =
+ setup(Config,
+ [{error_logger,false},
+ {logger_level,notice}]),
+ false = exists(?STANDARD_HANDLER,Hs),
+ #{module:=logger_simple_h} = SimpleC = find(simple,Hs),
+ all = maps:get(level,SimpleC),
+ notice = maps:get(level,P),
SimpleFilters = maps:get(filters,SimpleC),
- {domain,{_,{log,prefix_of,[beam,erlang,otp,sasl]}}} =
- lists:keyfind(domain,1,SimpleFilters),
- false = lists:keymember(stop_progress,1,SimpleFilters),
- false = lists:keymember(sasl_h,1,Hs),
+ {domain,{_,{log,super,[otp,sasl]}}} = lists:keyfind(domain,1,SimpleFilters),
+ false = exists(sasl,Hs),
+ [] = ML,
ok.
-dest_false_sasl_compatible(Config) ->
- {ok,{_Log,Hs}} = setup(Config,?FUNCTION_NAME,
- logger_dest,
- false, % dest
- notice, % level
- true, % sasl comp (default=false)
- undefined), % progress (default=false)
- false = lists:keymember(logger_std_h,1,Hs),
- {logger_simple,logger_simple,SimpleC} = lists:keyfind(logger_simple,1,Hs),
- notice = maps:get(level,SimpleC),
+error_logger_false_sasl_compatible(Config) ->
+ {ok,#{handlers:=Hs,primary:=P,module_levels:=ML},_Node} =
+ setup(Config,
+ [{error_logger,false},
+ {logger_level,notice},
+ {logger_sasl_compatible,true}]),
+ false = exists(?STANDARD_HANDLER,Hs),
+ #{module:=logger_simple_h} = SimpleC = find(simple,Hs),
+ all = maps:get(level,SimpleC),
+ info = maps:get(level,P),
SimpleFilters = maps:get(filters,SimpleC),
- {domain,{_,{log,prefix_of,[beam,erlang,otp]}}} =
- lists:keyfind(domain,1,SimpleFilters),
- false = lists:keymember(stop_progress,1,SimpleFilters),
- true = lists:keymember(sasl_h,1,Hs),
- true = is_pid(whereis(sasl_h)),
+ {domain,{_,{log,super,[otp]}}} = lists:keyfind(domain,1,SimpleFilters),
+ true = exists(sasl,Hs),
+ [] = ML,
+ ok.
+
+error_logger_silent(Config) ->
+ {ok,#{handlers:=Hs},_Node} = setup(Config,
+ [{error_logger,silent}]),
+ false = exists(?STANDARD_HANDLER,Hs),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+ ok.
+
+error_logger_silent_sasl_compatible(Config) ->
+ {ok,#{handlers:=Hs},_Node} = setup(Config,
+ [{error_logger,silent},
+ {logger_sasl_compatible,true}]),
+ false = exists(?STANDARD_HANDLER,Hs),
+ false = exists(simple,Hs),
+ true = exists(sasl,Hs),
+ ok.
+
+
+error_logger_file(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,_,Node} = setup(Config,
+ [{error_logger,{file,Log}}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 0),% progress in std logger
+ ok.
+
+
+logger_file(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{primary:=P,handlers:=Hs,module_levels:=ML},Node}
+ = setup(Config,
+ [{logger,
+ [{handler,?STANDARD_HANDLER,logger_std_h,
+ #{config=>#{type=>{file,Log}}}}]}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 0),% progress in std logger
+
+ notice = maps:get(level,P),
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ StdFilters = maps:get(filters,StdC),
+ {domain,{_,{log,super,[otp,sasl]}}} = lists:keyfind(domain,1,StdFilters),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+ [] = ML,
+ ok.
+
+logger_file_sasl_compatible(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{primary:=P,handlers:=Hs,module_levels:=ML},Node}
+ = setup(Config,
+ [{logger_sasl_compatible,true},
+ {logger,
+ [{handler,?STANDARD_HANDLER,logger_std_h,
+ #{config=>#{type=>{file,Log}}}}]}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 0),% progress in std logger
+
+ info = maps:get(level,P),
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ StdFilters = maps:get(filters,StdC),
+ {domain,{_,{log,super,[otp]}}} = lists:keyfind(domain,1,StdFilters),
+ false = exists(simple,Hs),
+ true = exists(sasl,Hs),
+ [] = ML,
+ ok.
+
+logger_file_log_progress(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{primary:=P,handlers:=Hs,module_levels:=ML},Node}
+ = setup(Config,
+ [{logger_level,info},
+ {logger,
+ [{handler,?STANDARD_HANDLER,logger_std_h,
+ #{config=>#{type=>{file,Log}}}}]}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 6,% progress in std logger
+ info),
+
+ info = maps:get(level,P),
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ StdFilters = maps:get(filters,StdC),
+ {domain,{_,{log,super,[otp,sasl]}}} = lists:keyfind(domain,1,StdFilters),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+ [] = ML,
+ ok.
+
+logger_file_no_filter(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{handlers:=Hs},Node}
+ = setup(Config,
+ [{logger,
+ [{handler,?STANDARD_HANDLER,logger_std_h,
+ #{filter_default=>log,filters=>[],
+ config=>#{type=>{file,Log}}}}]}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 6),% progress in std logger
+
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ [] = maps:get(filters,StdC),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+
+ ok.
+
+logger_file_no_filter_level(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{handlers:=Hs},Node}
+ = setup(Config,
+ [{logger,
+ [{handler,?STANDARD_HANDLER,logger_std_h,
+ #{filters=>[],level=>error,
+ config=>#{type=>{file,Log}}}}]}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 0,% progress in std logger
+ error),% level
+
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ error = maps:get(level,StdC),
+ [] = maps:get(filters,StdC),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+
+ ok.
+
+logger_file_formatter(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{handlers:=Hs},Node}
+ = setup(Config,
+ [{logger,
+ [{handler,?STANDARD_HANDLER,logger_std_h,
+ #{filters=>[],
+ formatter=>{logger_formatter,#{}},
+ config=>#{type=>{file,Log}}}}]}]),
+ check_single_log(Node,Log,
+ file,% dest
+ 6),% progress in std logger
+
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ [] = maps:get(filters,StdC),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+
+ ok.
+
+logger_filters(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{handlers:=Hs,primary:=P},Node}
+ = setup(Config,
+ [{logger_level,info},
+ {logger,
+ [{handler,?STANDARD_HANDLER,logger_std_h,
+ #{config=>#{type=>{file,Log}}}},
+ {filters,log,[{stop_progress,{fun logger_filters:progress/2,stop}}]}
+ ]}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 0,% progress in std logger
+ info),
+
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ StdFilters = maps:get(filters,StdC),
+ {domain,{_,{log,super,[otp,sasl]}}} = lists:keyfind(domain,1,StdFilters),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+ LoggerFilters = maps:get(filters,P),
+ true = lists:keymember(stop_progress,1,LoggerFilters),
+
+ ok.
+
+logger_filters_stop(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{handlers:=Hs,primary:=P},Node}
+ = setup(Config,
+ [{logger_level,info},
+ {logger,
+ [{handler,?STANDARD_HANDLER,logger_std_h,
+ #{filters=>[],
+ config=>#{type=>{file,Log}}}},
+ {filters,stop,[{log_error,{fun logger_filters:level/2,{log,gt,info}}}]}
+ ]}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 0,% progress in std logger
+ info),
+
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ [] = maps:get(filters,StdC),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+ LoggerFilters = maps:get(filters,P),
+ true = lists:keymember(log_error,1,LoggerFilters),
+
ok.
-dest_silent(Config) ->
- {ok,{_Log,Hs}} = setup(Config,?FUNCTION_NAME,
- logger_dest,
- silent, % dest
- undefined, % level
- undefined, % sasl comp (default=false)
- undefined), % progress (default=false)
- false = lists:keymember(logger_std_h,1,Hs),
- false = lists:keymember(logger_simple,1,Hs),
- false = lists:keymember(sasl_h,1,Hs),
+logger_module_level(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{handlers:=Hs,module_levels:=ModuleLevels},Node}
+ = setup(Config,
+ [{logger_level,info},
+ {logger,
+ [{handler,?STANDARD_HANDLER,logger_std_h,
+ #{config=>#{type=>{file,Log}}}},
+ {module_level,error,[supervisor]}
+ ]}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 3,% progress in std logger
+ info),
+
+ #{module:=logger_std_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ StdFilters = maps:get(filters,StdC),
+ {domain,{_,{log,super,[otp,sasl]}}} = lists:keyfind(domain,1,StdFilters),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+ [{supervisor,error}] = ModuleLevels,
ok.
-dest_silent_sasl_compatible(Config) ->
- {ok,{_Log,Hs}} = setup(Config,?FUNCTION_NAME,
- logger_dest,
- silent, % dest
- undefined, % level
- true, % sasl comp (default=false)
- undefined), % progress (default=false)
- false = lists:keymember(logger_std_h,1,Hs),
- false = lists:keymember(logger_simple,1,Hs),
- true = lists:keymember(sasl_h,1,Hs),
- true = is_pid(whereis(sasl_h)),
+logger_disk_log(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{handlers:=Hs},Node}
+ = setup(Config,
+ [{logger,
+ [{handler,?STANDARD_HANDLER,logger_disk_log_h,
+ #{config=>#{file=>Log}}}]}]),
+ check_default_log(Node,Log,
+ disk_log,% dest
+ 0),% progress in std logger
+
+ #{module:=logger_disk_log_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ StdFilters = maps:get(filters,StdC),
+ {domain,{_,{log,super,[otp,sasl]}}} = lists:keyfind(domain,1,StdFilters),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
+
ok.
+logger_disk_log_formatter(Config) ->
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,#{handlers:=Hs},Node}
+ = setup(Config,
+ [{logger,
+ [{handler,?STANDARD_HANDLER,logger_disk_log_h,
+ #{filters=>[],
+ formatter=>{logger_formatter,#{}},
+ config=>#{file=>Log}}}]}]),
+ check_single_log(Node,Log,
+ disk_log,% dest
+ 6),% progress in std logger
+
+ #{module:=logger_disk_log_h} = StdC = find(?STANDARD_HANDLER,Hs),
+ all = maps:get(level,StdC),
+ [] = maps:get(filters,StdC),
+ false = exists(simple,Hs),
+ false = exists(sasl,Hs),
-dest_file_old(Config) ->
- {ok,{Log,_Hs}} = setup(Config,?FUNCTION_NAME,
- error_logger,
- file, % dest
- undefined, % level
- undefined, % sasl comp (default=false)
- undefined), % progress (default=false)
- check_log(Log,
- file, % dest
- 0), % progress in std logger
ok.
-
-
-dest_file(Config) ->
- {ok,{Log,_Hs}} = setup(Config,?FUNCTION_NAME,
- logger_dest,
- file, % dest
- undefined, % level
- undefined, % sasl comp (default=false)
- undefined), % progress (default=false)
- check_log(Log,
- file, % dest
- 0), % progress in std logger
+
+logger_undefined(Config) ->
+ {ok,#{handlers:=Hs,primary:=P},_Node} =
+ setup(Config,[{logger,[{handler,?STANDARD_HANDLER,undefined}]}]),
+ false = exists(?STANDARD_HANDLER,Hs),
+ #{module:=logger_simple_h} = SimpleC = find(simple,Hs),
+ all = maps:get(level,SimpleC),
+ notice = maps:get(level,P),
+ SimpleFilters = maps:get(filters,SimpleC),
+ {domain,{_,{log,super,[otp,sasl]}}} = lists:keyfind(domain,1,SimpleFilters),
+ false = exists(sasl,Hs),
ok.
-
-
-dest_disk_log(Config) ->
- {ok,{Log,_Hs}} = setup(Config,?FUNCTION_NAME,
- logger_dest,
- disk_log, % dest
- undefined, % level
- undefined, % sasl comp (default=false)
- undefined), % progress (default=false)
- check_log(Log,
- disk_log, % dest
- 0), % progress in std logger
+
+
+%% Test that we can add multiple handlers with the default first
+logger_many_handlers_default_first(Config) ->
+ LogErr = file(Config,logger_many_handlers_default_first_error),
+ LogInfo = file(Config,logger_many_handlers_default_first_info),
+
+ logger_many_handlers(
+ Config,[{logger,
+ [{handler,?STANDARD_HANDLER,logger_std_h,
+ #{level=>error,
+ filters=>[],
+ formatter=>{logger_formatter,#{}},
+ config=>#{type=>{file,LogErr}}}
+ },
+ {handler,info,logger_std_h,
+ #{level=>info,
+ filters=>[{level,{fun logger_filters:level/2,{stop,gteq,error}}}],
+ config=>#{type=>{file,LogInfo}}}
+ }
+ ]},
+ {logger_level,info}], LogErr, LogInfo, 6).
+
+%% Test that we can add multiple handlers with the default last
+logger_many_handlers_default_last(Config) ->
+ LogErr = file(Config,logger_many_handlers_default_last_error),
+ LogInfo = file(Config,logger_many_handlers_default_last_info),
+ logger_many_handlers(
+ Config,[{logger,
+ [{handler,info,logger_std_h,
+ #{level=>info,
+ filters=>[{level,{fun logger_filters:level/2,{stop,gteq,error}}}],
+ config=>#{type=>{file,LogInfo}}}
+ },
+ {handler,?STANDARD_HANDLER,logger_std_h,
+ #{level=>error,
+ filters=>[],
+ formatter=>{logger_formatter,#{}},
+ config=>#{type=>{file,LogErr}}}
+ }
+ ]},
+ {logger_level,info}], LogErr, LogInfo, 7).
+
+%% Check that we can handle that an added logger has a broken filter
+%% This used to cause a deadlock.
+logger_many_handlers_default_last_broken_filter(Config) ->
+ LogErr = file(Config,logger_many_handlers_default_first_broken_filter_error),
+ LogInfo = file(Config,logger_many_handlers_default_first_broken_filter_info),
+
+ logger_many_handlers(
+ Config,[{logger,
+ [{handler,info,logger_std_h,
+ #{level=>info,
+ filters=>[{broken,{fun logger_filters:level/2,broken_state}},
+ {level,{fun logger_filters:level/2,{stop,gteq,error}}}],
+ config=>#{type=>{file,LogInfo}}}
+ },
+ {handler,?STANDARD_HANDLER,logger_std_h,
+ #{level=>error,
+ filters=>[],
+ formatter=>{logger_formatter,#{}},
+ config=>#{type=>{file,LogErr}}}
+ }
+ ]},
+ {logger_level,info}], LogErr, LogInfo, 7).
+
+logger_many_handlers(Config, Env, LogErr, LogInfo, NumProgress) ->
+ {ok,_,Node} = setup(Config,Env),
+ check_single_log(Node,LogErr,
+ file,% dest
+ 0,% progress in std logger
+ error), % level
+ ok = rpc:call(Node,logger_std_h,filesync,[info]),
+ {ok, Bin} = file:read_file(LogInfo),
+ ct:log("Log content:~n~s",[Bin]),
+ match(Bin,<<"info:">>,NumProgress,info,info),
+ match(Bin,<<"notice:">>,1,notice,info),
+ match(Bin,<<"alert:">>,0,alert,info),
+
ok.
-
sasl_compatible_false(Config) ->
- {ok,{Log,_Hs}} = setup(Config,?FUNCTION_NAME,
- logger_dest,
- file, % dest
- undefined, % level
- false, % sasl comp
- true), % progress
- check_log(Log,
- file, % dest
- 4), % progress in std logger
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,_,Node} = setup(Config,
+ [{error_logger,{file,Log}},
+ {logger_sasl_compatible,false},
+ {logger_level,info}]), % to get progress
+ check_default_log(Node,Log,
+ file,% dest
+ 6,% progress in std logger
+ info),
ok.
sasl_compatible_false_no_progress(Config) ->
- {ok,{Log,_Hs}} = setup(Config,?FUNCTION_NAME,
- logger_dest,
- file, % dest
- undefined, % level
- false, % sasl comp
- false), % progress
- check_log(Log,
- file, % dest
- 0), % progress in std logger
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,_,Node} = setup(Config,
+ [{error_logger,{file,Log}},
+ {logger_sasl_compatible,false}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 0),% progress in std logger
ok.
sasl_compatible(Config) ->
- {ok,{Log,_Hs}} = setup(Config,?FUNCTION_NAME,
- logger_dest,
- file, % dest
- undefined, % level
- true, % sasl comp
- undefined), % progress
- check_log(Log,
- file, % dest
- 0), % progress in std logger
+ Log = file(Config,?FUNCTION_NAME),
+ {ok,_,Node} = setup(Config,
+ [{error_logger,{file,Log}},
+ {sasl_compatible,true}]),
+ check_default_log(Node,Log,
+ file,% dest
+ 0),% progress in std logger
ok.
-bad_dest(Config) ->
- {error,{bad_config,{kernel,{logger_dest,baddest}}}} =
- setup(Config,?FUNCTION_NAME,
- logger_dest,
- baddest,
- undefined,
- undefined,
- undefined).
+all_logger_level(Config) ->
+ [all_logger_level(Config,Level) || Level <- [none,
+ emergency,
+ alert,
+ critical,
+ error,
+ warning,
+ notice,
+ info,
+ debug,
+ all]],
+ ok.
+
+all_logger_level(Config,Level) ->
+ {ok,#{primary:=#{level:=Level}},Node} = setup(Config,[{logger_level,Level}]),
+ true = test_server:stop_node(Node),
+ ok.
+
+bad_error_logger(Config) ->
+ error = setup(Config,[{error_logger,baddest}]).
bad_level(Config) ->
- error =
- setup(Config,?FUNCTION_NAME,
- logger_dest,
- tty,
- badlevel,
- undefined,
- undefined).
+ error = setup(Config,[{logger_level,badlevel}]).
bad_sasl_compatibility(Config) ->
- error =
- setup(Config,?FUNCTION_NAME,
- logger_dest,
- tty,
- info,
- badcomp,
- undefined).
-
-bad_progress(Config) ->
- error =
- setup(Config,?FUNCTION_NAME,
- logger_dest,
- tty,
- info,
- undefined,
- badprogress).
+ error = setup(Config,[{logger_sasl_compatible,badcomp}]).
%%%-----------------------------------------------------------------
%%% Internal
-setup(Config,Func,DestVar,Dest,Level,SaslComp,Progress) ->
- ok = logger:add_handler(logger_simple,logger_simple,
- #{filter_default=>log,
- logger_simple=>#{buffer=>true}}),
- Dir = ?config(priv_dir,Config),
- File = lists:concat([?MODULE,"_",Func,".log"]),
- Log = filename:join(Dir,File),
- case Dest of
- undefined ->
- ok;
- F when F==file; F==disk_log ->
- application:set_env(kernel,DestVar,{Dest,Log});
- _ ->
- application:set_env(kernel,DestVar,Dest)
- end,
- case Level of
- undefined ->
- ok;
- _ ->
- application:set_env(kernel,logger_level,Level)
- end,
- case SaslComp of
- undefined ->
- ok;
- _ ->
- application:set_env(kernel,logger_sasl_compatible,SaslComp)
- end,
- case Progress of
- undefined ->
- ok;
- _ ->
- application:set_env(kernel,logger_log_progress,Progress)
- end,
- case logger:setup_standard_handler() of
- ok ->
- application:start(sasl),
- StdH = case Dest of
- NoH when NoH==false; NoH==silent -> false;
- _ -> true
- end,
- StdH = is_pid(whereis(?STANDARD_HANDLER)),
- SaslH = if SaslComp -> true;
- true -> false
- end,
- SaslH = is_pid(whereis(sasl_h)),
- {ok,{Log,maps:get(handlers,logger:i())}};
- Error ->
- Error
- end.
+file(Config,Func) ->
+ filename:join(proplists:get_value(priv_dir,Config),
+ lists:concat([Func,".log"])).
+
+check_default_log(Node,Log,Dest,NumProgress) ->
+ check_default_log(Node,Log,Dest,NumProgress,notice).
+check_default_log(Node,Log,Dest,NumProgress,Level) ->
-check_log(Log,Dest,NumProgress) ->
- ok = logger:alert("dummy1"),
- ok = logger:debug("dummy1"),
+ {ok,Bin1,Bin2} = check_log(Node,Log,Dest),
+
+ match(Bin1,<<"PROGRESS REPORT">>,NumProgress,info,Level),
+ match(Bin1,<<"ALERT REPORT">>,1,alert,Level),
+ match(Bin1,<<"INFO REPORT">>,0,notice,Level),
+ match(Bin1,<<"DEBUG REPORT">>,0,debug,Level),
+
+ match(Bin2,<<"INFO REPORT">>,1,notice,Level),
+ match(Bin2,<<"DEBUG REPORT">>,0,debug,Level),
+ ok.
+
+check_single_log(Node,Log,Dest,NumProgress) ->
+ check_single_log(Node,Log,Dest,NumProgress,notice).
+check_single_log(Node,Log,Dest,NumProgress,Level) ->
+
+ {ok,Bin1,Bin2} = check_log(Node,Log,Dest),
+
+ match(Bin1,<<"info:">>,NumProgress,info,Level),
+ match(Bin1,<<"alert:">>,1,alert,Level),
+ match(Bin1,<<"debug:">>,0,debug,Level),
+
+ match(Bin2,<<"info:">>,NumProgress+1,info,Level),
+ match(Bin2,<<"debug:">>,0,debug,Level),
+
+ ok.
+
+check_log(Node,Log,Dest) ->
+
+ ok = log(Node,alert,["dummy1"]),
+ ok = log(Node,debug,["dummy1"]),
%% Check that there are progress reports (supervisor and
%% application_controller) and an error report (the call above) in
%% the log. There should not be any info reports yet.
- {ok,Bin1} = sync_and_read(Dest,Log),
+ {ok,Bin1} = sync_and_read(Node,Dest,Log),
ct:log("Log content:~n~s",[Bin1]),
- match(Bin1,<<"PROGRESS REPORT">>,NumProgress),
- match(Bin1,<<"ALERT REPORT">>,1),
- match(Bin1,<<"INFO REPORT">>,0),
- match(Bin1,<<"DEBUG REPORT">>,0),
%% Then stop sasl and see that the info report from
%% application_controller is there
- ok = application:stop(sasl),
- {ok,Bin2} = sync_and_read(Dest,Log),
+ ok = rpc:call(Node,application,stop,[sasl]),
+ {ok,Bin2} = sync_and_read(Node,Dest,Log),
ct:log("Log content:~n~s",[Bin2]),
- match(Bin2,<<"INFO REPORT">>,1),
- match(Bin1,<<"DEBUG REPORT">>,0),
- ok.
+ {ok,Bin1,Bin2}.
-match(Bin,Pattern,0) ->
+match(Bin,Pattern,0,_,_) ->
nomatch = re:run(Bin,Pattern,[{capture,none}]);
-match(Bin,Pattern,N) ->
- {match,M} = re:run(Bin,Pattern,[{capture,all},global]),
- N = length(M).
-
-sync_and_read(disk_log,Log) ->
- logger_disk_log_h:disk_log_sync(?STANDARD_HANDLER),
- file:read_file(Log ++ ".1");
-sync_and_read(file,Log) ->
- logger_std_h:filesync(?STANDARD_HANDLER),
- file:read_file(Log).
-
-cleanup() ->
- application:stop(sasl),
- [application:unset_env(App,Key) || {App,Key} <- ?all_vars],
- #{handlers:=Hs0} = logger:i(),
- Hs = lists:keydelete(cth_log_redirect,1,Hs0),
- [ok = logger:remove_handler(Id) || {Id,_,_} <- Hs],
- Hs.
+match(Bin,Pattern,N,LogLevel,ConfLevel) ->
+ case logger:compare_levels(LogLevel,ConfLevel) of
+ lt -> match(Bin,Pattern,0,LogLevel,ConfLevel);
+ _ ->
+ {match,M} = re:run(Bin,Pattern,[{capture,all},global]),
+ N = length(M)
+ end.
+
+find(Id,Handlers) ->
+ case lists:search(fun(#{id:=Id0}) when Id0=:=Id-> true;
+ (_) -> false end,
+ Handlers) of
+ {value,Config} ->
+ Config;
+ false ->
+ false
+ end.
+
+exists(Id,Handlers) ->
+ case find(Id,Handlers) of
+ false ->
+ false;
+ _ ->
+ true
+ end.
diff --git a/lib/kernel/test/logger_filters_SUITE.erl b/lib/kernel/test/logger_filters_SUITE.erl
index 21f14bbc02..11cce8fd20 100644
--- a/lib/kernel/test/logger_filters_SUITE.erl
+++ b/lib/kernel/test/logger_filters_SUITE.erl
@@ -75,66 +75,79 @@ all() ->
remote_gl].
domain(_Config) ->
- L1 = logger_filters:domain(L1=?dlog([]),{log,prefix_of,[]}),
- stop = logger_filters:domain(?dlog([]),{stop,prefix_of,[]}),
- L2 = logger_filters:domain(L2=?dlog([]),{log,starts_with,[]}),
- stop = logger_filters:domain(?dlog([]),{stop,starts_with,[]}),
- L3 = logger_filters:domain(L3=?dlog([]),{log,equals,[]}),
- stop = logger_filters:domain(?dlog([]),{stop,equals,[]}),
- ignore = logger_filters:domain(?dlog([]),{log,no_domain,[]}),
- ignore = logger_filters:domain(?dlog([]),{stop,no_domain,[]}),
-
- L4 = logger_filters:domain(L4=?dlog([a]),{log,prefix_of,[a,b]}),
- stop = logger_filters:domain(?dlog([a]),{stop,prefix_of,[a,b]}),
- ignore = logger_filters:domain(?dlog([a]),{log,starts_with,[a,b]}),
- ignore = logger_filters:domain(?dlog([a]),{stop,starts_with,[a,b]}),
- ignore = logger_filters:domain(?dlog([a]),{log,equals,[a,b]}),
- ignore = logger_filters:domain(?dlog([a]),{stop,equals,[a,b]}),
- ignore = logger_filters:domain(?dlog([a]),{log,no_domain,[a,b]}),
- ignore = logger_filters:domain(?dlog([a]),{stop,no_domain,[a,b]}),
-
- ignore = logger_filters:domain(?dlog([a,b]),{log,prefix_of,[a]}),
- ignore = logger_filters:domain(?dlog([a,b]),{stop,prefix_of,[a]}),
- L5 = logger_filters:domain(L5=?dlog([a,b]),{log,starts_with,[a]}),
- stop = logger_filters:domain(?dlog([a,b]),{stop,starts_with,[a]}),
- ignore = logger_filters:domain(?dlog([a,b]),{log,equals,[a]}),
- ignore = logger_filters:domain(?dlog([a,b]),{stop,equals,[a]}),
- ignore = logger_filters:domain(?dlog([a,b]),{log,no_domain,[a]}),
- ignore = logger_filters:domain(?dlog([a,b]),{stop,no_domain,[a]}),
-
- ignore = logger_filters:domain(?ndlog,{log,prefix_of,[a]}),
- ignore = logger_filters:domain(?ndlog,{stop,prefix_of,[a]}),
- ignore = logger_filters:domain(?ndlog,{log,starts_with,[a]}),
- ignore = logger_filters:domain(?ndlog,{stop,starts_with,[a]}),
- ignore = logger_filters:domain(?ndlog,{log,equals,[a]}),
- ignore = logger_filters:domain(?ndlog,{stop,equals,[a]}),
- L6 = logger_filters:domain(L6=?ndlog,{log,no_domain,[a]}),
- stop = logger_filters:domain(?ndlog,{stop,no_domain,[a]}),
-
- L7 = logger_filters:domain(L7=?dlog([a,b,c,d]),{log,prefix_of,[a,b,c,d]}),
- stop = logger_filters:domain(?dlog([a,b,c,d]),{stop,prefix_of,[a,b,c,d]}),
- L8 = logger_filters:domain(L8=?dlog([a,b,c,d]),{log,starts_with,[a,b,c,d]}),
- stop = logger_filters:domain(?dlog([a,b,c,d]),{stop,starts_with,[a,b,c,d]}),
- L9 = logger_filters:domain(L9=?dlog([a,b,c,d]),{log,equals,[a,b,c,d]}),
- stop = logger_filters:domain(?dlog([a,b,c,d]),{stop,equals,[a,b,c,d]}),
- ignore = logger_filters:domain(?dlog([a,b,c,d]),{log,no_domain,[a,b,c,d]}),
- ignore = logger_filters:domain(?dlog([a,b,c,d]),{stop,no_domain,[a,b,c,d]}),
+ L1 = logger_filters:domain(L1=?dlog([]),{log,super,[]}),
+ stop = logger_filters:domain(?dlog([]),{stop,super,[]}),
+ L2 = logger_filters:domain(L2=?dlog([]),{log,sub,[]}),
+ stop = logger_filters:domain(?dlog([]),{stop,sub,[]}),
+ L3 = logger_filters:domain(L3=?dlog([]),{log,equal,[]}),
+ stop = logger_filters:domain(?dlog([]),{stop,equal,[]}),
+ ignore = logger_filters:domain(?dlog([]),{log,not_equal,[]}),
+ ignore = logger_filters:domain(?dlog([]),{stop,not_equal,[]}),
+ ignore = logger_filters:domain(?dlog([]),{log,undefined,[]}),
+ ignore = logger_filters:domain(?dlog([]),{stop,undefined,[]}),
+
+ L4 = logger_filters:domain(L4=?dlog([a]),{log,super,[a,b]}),
+ stop = logger_filters:domain(?dlog([a]),{stop,super,[a,b]}),
+ ignore = logger_filters:domain(?dlog([a]),{log,sub,[a,b]}),
+ ignore = logger_filters:domain(?dlog([a]),{stop,sub,[a,b]}),
+ ignore = logger_filters:domain(?dlog([a]),{log,equal,[a,b]}),
+ ignore = logger_filters:domain(?dlog([a]),{stop,equal,[a,b]}),
+ L5 = logger_filters:domain(L5=?dlog([a]),{log,not_equal,[a,b]}),
+ stop = logger_filters:domain(?dlog([a]),{stop,not_equal,[a,b]}),
+ ignore = logger_filters:domain(?dlog([a]),{log,undefined,[a,b]}),
+ ignore = logger_filters:domain(?dlog([a]),{stop,undefined,[a,b]}),
+
+ ignore = logger_filters:domain(?dlog([a,b]),{log,super,[a]}),
+ ignore = logger_filters:domain(?dlog([a,b]),{stop,super,[a]}),
+ L6 = logger_filters:domain(L6=?dlog([a,b]),{log,sub,[a]}),
+ stop = logger_filters:domain(?dlog([a,b]),{stop,sub,[a]}),
+ ignore = logger_filters:domain(?dlog([a,b]),{log,equal,[a]}),
+ ignore = logger_filters:domain(?dlog([a,b]),{stop,equal,[a]}),
+ L7 = logger_filters:domain(L7=?dlog([a,b]),{log,not_equal,[a]}),
+ stop = logger_filters:domain(?dlog([a,b]),{stop,not_equal,[a]}),
+ ignore = logger_filters:domain(?dlog([a,b]),{log,undefined,[a]}),
+ ignore = logger_filters:domain(?dlog([a,b]),{stop,undefined,[a]}),
+
+ ignore = logger_filters:domain(?ndlog,{log,super,[a]}),
+ ignore = logger_filters:domain(?ndlog,{stop,super,[a]}),
+ ignore = logger_filters:domain(?ndlog,{log,sub,[a]}),
+ ignore = logger_filters:domain(?ndlog,{stop,sub,[a]}),
+ ignore = logger_filters:domain(?ndlog,{log,equal,[a]}),
+ ignore = logger_filters:domain(?ndlog,{stop,equal,[a]}),
+ L8 = logger_filters:domain(L8=?ndlog,{log,not_equal,[a]}),
+ stop = logger_filters:domain(?ndlog,{stop,not_equal,[a]}),
+ L9 = logger_filters:domain(L9=?ndlog,{log,undefined,[a]}),
+ stop = logger_filters:domain(?ndlog,{stop,undefined,[a]}),
+
+ L10 = logger_filters:domain(L10=?dlog([a,b,c,d]),{log,super,[a,b,c,d]}),
+ stop = logger_filters:domain(?dlog([a,b,c,d]),{stop,super,[a,b,c,d]}),
+ L11 = logger_filters:domain(L11=?dlog([a,b,c,d]),{log,sub,[a,b,c,d]}),
+ stop = logger_filters:domain(?dlog([a,b,c,d]),{stop,sub,[a,b,c,d]}),
+ L12 = logger_filters:domain(L12=?dlog([a,b,c,d]),{log,equal,[a,b,c,d]}),
+ stop = logger_filters:domain(?dlog([a,b,c,d]),{stop,equal,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog([a,b,c,d]),{log,not_equal,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog([a,b,c,d]),{stop,not_equal,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog([a,b,c,d]),{log,undefined,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog([a,b,c,d]),{stop,undefined,[a,b,c,d]}),
%% A domain field in meta which is not a list is allowed by the
- %% filter, but it will never match.
- ignore = logger_filters:domain(?dlog(dummy),{log,prefix_of,[a,b,c,d]}),
- ignore = logger_filters:domain(?dlog(dummy),{stop,prefix_of,[a,b,c,d]}),
- ignore = logger_filters:domain(?dlog(dummy),{log,starts_with,[a,b,c,d]}),
- ignore = logger_filters:domain(?dlog(dummy),{stop,starts_with,[a,b,c,d]}),
- ignore = logger_filters:domain(?dlog(dummy),{log,equals,[a,b,c,d]}),
- ignore = logger_filters:domain(?dlog(dummy),{stop,equals,[a,b,c,d]}),
- ignore = logger_filters:domain(?dlog(dummy),{log,no_domain,[a,b,c,d]}),
- ignore = logger_filters:domain(?dlog(dummy),{stop,no_domain,[a,b,c,d]}),
+ %% filter, but since MatchDomain is always a list of atoms, only
+ %% Action=not_equal can ever match.
+ ignore = logger_filters:domain(?dlog(dummy),{log,super,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog(dummy),{stop,super,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog(dummy),{log,sub,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog(dummy),{stop,sub,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog(dummy),{log,equal,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog(dummy),{stop,equal,[a,b,c,d]}),
+ L13 = logger_filters:domain(L13=?dlog(dummy),{log,not_equal,[a,b,c,d]}),
+ stop = logger_filters:domain(?dlog(dummy),{stop,not_equal,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog(dummy),{log,undefined,[a,b,c,d]}),
+ ignore = logger_filters:domain(?dlog(dummy),{stop,undefined,[a,b,c,d]}),
{error,badarg} = ?TRY(logger_filters:domain(?ndlog,bad)),
- {error,badarg} = ?TRY(logger_filters:domain(?ndlog,{bad,prefix_of,[]})),
+ {error,badarg} = ?TRY(logger_filters:domain(?ndlog,{bad,super,[]})),
{error,badarg} = ?TRY(logger_filters:domain(?ndlog,{log,bad,[]})),
- {error,badarg} = ?TRY(logger_filters:domain(?ndlog,{log,prefix_of,bad})),
+ {error,badarg} = ?TRY(logger_filters:domain(?ndlog,{log,super,bad})),
ok.
diff --git a/lib/kernel/test/logger_formatter_SUITE.erl b/lib/kernel/test/logger_formatter_SUITE.erl
index 7d1f33746d..2ec4b243cf 100644
--- a/lib/kernel/test/logger_formatter_SUITE.erl
+++ b/lib/kernel/test/logger_formatter_SUITE.erl
@@ -56,6 +56,7 @@ groups() ->
all() ->
[default,
legacy_header,
+ error_logger_notice_header,
single_line,
template,
format_msg,
@@ -68,12 +69,14 @@ all() ->
level_or_msg_in_meta,
faulty_log,
faulty_config,
- faulty_msg].
+ faulty_msg,
+ check_config,
+ update_config].
default(_Config) ->
String1 = format(info,{"~p",[term]},#{},#{}),
ct:log(String1),
- [_Date,_Time,"info:","term\n"] = string:lexemes(String1," "),
+ [_DateTime,"info:","term\n"] = string:lexemes(String1," "),
Time = timestamp(),
ExpectedTimestamp = default_time_format(Time),
@@ -123,6 +126,34 @@ legacy_header(_Config) ->
"=INFO REPORT==== "++_ = String5,
ok.
+error_logger_notice_header(_Config) ->
+ Meta1 = #{error_logger=>#{tag => info_report,type => std_info}},
+ String1 = format(notice,{"~p",[term]},Meta1,
+ #{legacy_header=>true,
+ error_logger_notice_header=>notice}),
+ ct:log(String1),
+ "=NOTICE REPORT==== "++_ = String1,
+
+ String2 = format(notice,{"~p",[term]},Meta1,
+ #{legacy_header=>true,
+ error_logger_notice_header=>info}),
+ ct:log(String2),
+ "=INFO REPORT==== "++_ = String2,
+
+ String3 = format(notice,{"~p",[term]},#{},
+ #{legacy_header=>true,
+ error_logger_notice_header=>notice}),
+ ct:log(String3),
+ "=NOTICE REPORT==== "++_ = String3,
+
+ String4 = format(notice,{"~p",[term]},#{},
+ #{legacy_header=>true,
+ error_logger_notice_header=>info}),
+ ct:log(String4),
+ "=NOTICE REPORT==== "++_ = String4,
+
+ ok.
+
single_line(_Config) ->
Time = timestamp(),
ExpectedTimestamp = default_time_format(Time),
@@ -135,6 +166,56 @@ single_line(_Config) ->
" info:\nterm\n" = string:prefix(String2,ExpectedTimestamp),
String2 = format(info,{"~p",[term]},#{time=>Time},#{single_line=>bad}),
+
+
+ %% Test that no extra commas/spaces are added when removing
+ %% newlines, especially not after "=>" in a map association (as
+ %% was the case in OTP-21.0, when the only single_line adjustment
+ %% was done by regexp replacement of "\n" by ", ").
+ Prefix =
+ "Some characters to fill the line ------------------------------------- ",
+ String3 = format(info,{"~s~p~n~s~p~n",[Prefix,
+ lists:seq(1,10),
+ Prefix,
+ #{a=>map,with=>a,few=>accociations}]},
+ #{time=>Time},
+ #{single_line=>true}),
+ ct:log(String3),
+ match = re:run(String3,"\\[1,2,3,4,5,6,7,8,9,10\\]",[{capture,none}]),
+ match = re:run(String3,
+ "#{a => map,few => accociations,with => a}",
+ [{capture,none}]),
+
+ %% This part is added to make sure that the previous test made
+ %% sense, i.e. that there would actually be newlines inside the
+ %% list and map.
+ String4 = format(info,{"~s~p~n~s~p~n",[Prefix,
+ lists:seq(1,10),
+ Prefix,
+ #{a=>map,with=>a,few=>accociations}]},
+ #{time=>Time},
+ #{single_line=>false}),
+ ct:log(String4),
+ match = re:run(String4,"\\[1,2,3,\n",[global,{capture,none}]),
+ {match,Match4} = re:run(String4,"=>\n",[global,{capture,all}]),
+ 3 = length(Match4),
+
+ %% Test that big metadata fields do not get line breaks
+ String5 = format(info,"",
+ #{mymeta=>lists:seq(1,100)},
+ #{single_line=>true,template=>[mymeta,"\n"]}),
+ ct:log(String5),
+ [_] = string:lexemes(String5,"\n"),
+
+ %% Ensure that the previous test made sense, i.e. that the
+ %% metadata field does produce multiple lines if
+ %% single_line==false.
+ String6 = format(info,"",
+ #{mymeta=>lists:seq(1,100)},
+ #{single_line=>false,template=>[mymeta,"\n"]}),
+ ct:log(String6),
+ [_,_|_] = string:lexemes(String6,"\n"),
+
ok.
template(_Config) ->
@@ -157,7 +238,7 @@ template(_Config) ->
Template4 = ["string\nnewline"],
String4 = format(info,{"~p",[term]},#{time=>Time},#{template=>Template4,
- single_line=>true}),
+ single_line=>true}),
ct:log(String4),
"string\nnewline" = String4,
@@ -177,8 +258,8 @@ template(_Config) ->
time=>Time,
tuple=>{1,atom,"list"},
nested=>#{subkey=>subvalue}},
- Template6 = lists:join(";",maps:keys(maps:remove(nested,Meta6)) ++
- [{nested,subkey}]),
+ Template6 = lists:join(";",lists:sort(maps:keys(maps:remove(nested,Meta6))) ++
+ [[nested,subkey]]),
String6 = format(info,{"~p",[term]},Meta6,#{template=>Template6,
single_line=>true}),
ct:log(String6),
@@ -201,16 +282,16 @@ template(_Config) ->
nested=>#{key1=>#{subkey1=>value1},
key2=>value2}},
Template7 = lists:join(";",[nested,
- {nested,key1},
- {nested,key1,subkey1},
- {nested,key2},
- {nested,key2,subkey2},
- {nested,key3},
- {nested,key3,subkey3}]),
+ [nested,key1],
+ [nested,key1,subkey1],
+ [nested,key2],
+ [nested,key2,subkey2],
+ [nested,key3],
+ [nested,key3,subkey3]]),
String7 = format(info,{"~p",[term]},Meta7,#{template=>Template7,
single_line=>true}),
ct:log(String7),
- [MultipleKeysStr,
+ [MultipleKeysStr7,
"#{subkey1 => value1}",
"value1",
"value2",
@@ -218,11 +299,42 @@ template(_Config) ->
"",
""] = string:split(String7,";",all),
%% Order of keys is not fixed
- case MultipleKeysStr of
+ case MultipleKeysStr7 of
"#{key2 => value2,key1 => #{subkey1 => value1}}" -> ok;
"#{key1 => #{subkey1 => value1},key2 => value2}" -> ok;
- _ -> ct:fail({full_nested_map_unexpected,MultipleKeysStr})
+ _ -> ct:fail({full_nested_map_unexpected,MultipleKeysStr7})
end,
+
+ Meta8 = #{time=>Time,
+ nested=>#{key1=>#{subkey1=>value1},
+ key2=>value2}},
+ Template8 =
+ lists:join(
+ ";",
+ [{nested,["exist:",nested],["noexist"]},
+ {[nested,key1],["exist:",[nested,key1]],["noexist"]},
+ {[nested,key1,subkey1],["exist:",[nested,key1,subkey1]],["noexist"]},
+ {[nested,key2],["exist:",[nested,key2]],["noexist"]},
+ {[nested,key2,subkey2],["exist:",[nested,key2,subkey2]],["noexist"]},
+ {[nested,key3],["exist:",[nested,key3]],["noexist"]},
+ {[nested,key3,subkey3],["exist:",[nested,key3,subkey3]],["noexist"]}]),
+ String8 = format(info,{"~p",[term]},Meta8,#{template=>Template8,
+ single_line=>true}),
+ ct:log(String8),
+ [MultipleKeysStr8,
+ "exist:#{subkey1 => value1}",
+ "exist:value1",
+ "exist:value2",
+ "noexist",
+ "noexist",
+ "noexist"] = string:split(String8,";",all),
+ %% Order of keys is not fixed
+ case MultipleKeysStr8 of
+ "exist:#{key2 => value2,key1 => #{subkey1 => value1}}" -> ok;
+ "exist:#{key1 => #{subkey1 => value1},key2 => value2}" -> ok;
+ _ -> ct:fail({full_nested_map_unexpected,MultipleKeysStr8})
+ end,
+
ok.
format_msg(_Config) ->
@@ -250,30 +362,48 @@ format_msg(_Config) ->
#{report_cb=>fun(_)-> faulty_return end},
#{template=>Template}),
ct:log(String5),
- "REPORT_CB ERROR: term; Returned: faulty_return" = String5,
+ "REPORT_CB/1 ERROR: term; Returned: faulty_return" = String5,
String6 = format(info,{report,term},
#{report_cb=>fun(_)-> erlang:error(fun_crashed) end},
#{template=>Template}),
ct:log(String6),
- "REPORT_CB CRASH: term; Reason: {error,fun_crashed}" = String6,
+ "REPORT_CB/1 CRASH: term; Reason: {error,fun_crashed,"++_ = String6,
- %% strings are not formatted
- String7 = format(info,{string,"string"},
- #{report_cb=>fun(_)-> {"formatted",[]} end},
+ String7 = format(info,{report,term},
+ #{report_cb=>fun(_,_)-> ['not',a,string] end},
#{template=>Template}),
ct:log(String7),
- "string" = String7,
+ "REPORT_CB/2 ERROR: term; Returned: ['not',a,string]" = String7,
- String8 = format(info,{string,['not',printable,list]},
- #{report_cb=>fun(_)-> {"formatted",[]} end},
+ String8 = format(info,{report,term},
+ #{report_cb=>fun(_,_)-> faulty_return end},
#{template=>Template}),
ct:log(String8),
- "INVALID STRING: ['not',printable,list]" = String8,
+ "REPORT_CB/2 ERROR: term; Returned: faulty_return" = String8,
- String9 = format(info,{string,"string"},#{},#{template=>Template}),
+ String9 = format(info,{report,term},
+ #{report_cb=>fun(_,_)-> erlang:error(fun_crashed) end},
+ #{template=>Template}),
ct:log(String9),
- "string" = String9,
+ "REPORT_CB/2 CRASH: term; Reason: {error,fun_crashed,"++_ = String9,
+
+ %% strings are not formatted
+ String10 = format(info,{string,"string"},
+ #{report_cb=>fun(_)-> {"formatted",[]} end},
+ #{template=>Template}),
+ ct:log(String10),
+ "string" = String10,
+
+ String11 = format(info,{string,['not',printable,list]},
+ #{report_cb=>fun(_)-> {"formatted",[]} end},
+ #{template=>Template}),
+ ct:log("~ts",[String11]), % avoiding ct_log crash
+ "FORMAT ERROR: \"~ts\" - [['not',printable,list]]" = String11,
+
+ String12 = format(info,{string,"string"},#{},#{template=>Template}),
+ ct:log(String12),
+ "string" = String12,
ok.
@@ -297,22 +427,22 @@ max_size(_Config) ->
single_line=>false},
"12345678901234567890" =
format(info,{"12345678901234567890",[]},#{},Cfg),
- application:set_env(kernel,logger_max_size,11),
- "12345678901234567890" = % min value is 50, so this is not limited
- format(info,{"12345678901234567890",[]},#{},Cfg),
- "12345678901234567890123456789012345678901234567..." = % 50
- format(info,
- {"123456789012345678901234567890123456789012345678901234567890",
- []},
- #{},
- Cfg),
- application:set_env(kernel,logger_max_size,53),
- "12345678901234567890123456789012345678901234567890..." = %53
- format(info,
- {"123456789012345678901234567890123456789012345678901234567890",
- []},
- #{},
- Cfg),
+ %% application:set_env(kernel,logger_max_size,11),
+ %% "12345678901234567890" = % min value is 50, so this is not limited
+ %% format(info,{"12345678901234567890",[]},#{},Cfg),
+ %% "12345678901234567890123456789012345678901234567..." = % 50
+ %% format(info,
+ %% {"123456789012345678901234567890123456789012345678901234567890",
+ %% []},
+ %% #{},
+ %% Cfg),
+ %% application:set_env(kernel,logger_max_size,53),
+ %% "12345678901234567890123456789012345678901234567890..." = %53
+ %% format(info,
+ %% {"123456789012345678901234567890123456789012345678901234567890",
+ %% []},
+ %% #{},
+ %% Cfg),
"123456789012..." =
format(info,{"12345678901234567890",[]},#{},Cfg#{max_size=>15}),
"12345678901234567890" =
@@ -341,12 +471,6 @@ depth(_Config) ->
{"~p",[[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0]]},
#{},
#{template=>Template}),
- application:set_env(kernel,logger_format_depth,12),
- "[1,2,3,4,5,6,7,8,9,0,1|...]" =
- format(info,
- {"~p",[[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0]]},
- #{},
- #{template=>Template}),
"[1,2,3,4,5,6,7,8,9,0,1,2|...]" =
format(info,
{"~p",[[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0]]},
@@ -361,7 +485,7 @@ depth(_Config) ->
depth=>unlimited}),
ok.
depth(cleanup,_Config) ->
- application:unset_env(kernel,logger_format_depth),
+ application:unset_env(kernel,error_logger_format_depth),
ok.
chars_limit(_Config) ->
@@ -370,7 +494,7 @@ chars_limit(_Config) ->
lists:seq(1,100),
maps:from_list(lists:zip(lists:seq(1,100),
lists:duplicate(100,value)))]},
- Meta = #{time=>"2018-04-26 9:15:40.449879"},
+ Meta = #{time=>timestamp()},
Template = [time," - ", msg, "\n"],
FC = #{template=>Template,
depth=>unlimited,
@@ -382,7 +506,7 @@ chars_limit(_Config) ->
L1 = string:length(String1),
ct:log("String1: ~p~nLength1: ~p~n",[lists:flatten(String1),L1]),
true = L1 > CL1,
- true = L1 < CL1 + 10,
+ true = L1 < CL1 + 15,
String2 = format(info,FA,Meta,FC#{chars_limit=>CL1,depth=>10}),
L2 = string:length(String2),
@@ -394,13 +518,13 @@ chars_limit(_Config) ->
L3 = string:length(String3),
ct:log("String3: ~p~nLength3: ~p~n",[lists:flatten(String3),L3]),
true = L3 > CL3,
- true = L3 < CL3 + 10,
+ true = L3 < CL3 + 15,
String4 = format(info,FA,Meta,FC#{chars_limit=>CL3,depth=>10}),
L4 = string:length(String4),
ct:log("String4: ~p~nLength4: ~p~n",[lists:flatten(String4),L4]),
true = L4 > CL3,
- true = L4 < CL3 + 10,
+ true = L4 < CL3 + 15,
%% Test that max_size truncates the string which is limited by
%% depth and chars_limit
@@ -411,6 +535,14 @@ chars_limit(_Config) ->
L5 = MS5,
true = lists:prefix(lists:sublist(String5,L5-4),String4),
+ %% Test that chars_limit limits string also
+ Str = "123456789012345678901234567890123456789012345678901234567890123456789",
+ CL6 = 80,
+ String6 = format(info,{string,Str},Meta,FC#{chars_limit=>CL6}),
+ L6 = string:length(String6),
+ ct:log("String6: ~p~nLength6: ~p~n",[String6,L6]),
+ L6 = CL6,
+
ok.
format_mfa(_Config) ->
@@ -439,29 +571,58 @@ format_mfa(_Config) ->
ok.
format_time(_Config) ->
- Time1 = timestamp(),
- ExpectedTimestamp1 = default_time_format(Time1),
- String1 = format(info,{"~p",[term]},#{time=>Time1},#{}),
- ct:log(String1),
- " info: term\n" = string:prefix(String1,ExpectedTimestamp1),
-
- Time2 = timestamp(),
- ExpectedTimestamp2 = default_time_format(Time2,true),
- String2 = format(info,{"~p",[term]},#{time=>Time2},#{utc=>true}),
- ct:log(String2),
- " info: term\n" = string:prefix(String2,ExpectedTimestamp2),
-
- application:set_env(kernel,logger_utc,true),
- Time3 = timestamp(),
- ExpectedTimestamp3 = default_time_format(Time3,true),
- String3 = format(info,{"~p",[term]},#{time=>Time3},#{}),
- ct:log(String3),
- " info: term\n" = string:prefix(String3,ExpectedTimestamp3),
+ Time = timestamp(),
+ Meta = #{time=>Time},
+ FC = #{template=>[time]},
+ Msg = {string,""},
+ ExpectedLocal = default_time_format(Time,false),
+ ExpectedUtc = default_time_format(Time,true),
+
+ %% default - local time
+ ExpectedLocal = format(info,Msg,Meta,FC),
+
+ %% time_offset config parameter to formatter
+ ExpectedLocal = format(info,Msg,Meta,FC#{time_offset=>""}),
+ ExpectedUtc = format(info,Msg,Meta,FC#{time_offset=>"Z"}),
+
+ %% stdlib utc_log works when time_offset parameter is not set
+ application:set_env(stdlib,utc_log,true),
+ ExpectedUtc = format(info,Msg,Meta,FC),
+
+ %% sasl utc_log overwrites stdlib utc_log
+ application:set_env(sasl,utc_log,false),
+ ExpectedLocal = format(info,Msg,Meta,FC),
+
+ %% sasl utc_log overwrites stdlib utc_log
+ application:set_env(sasl,utc_log,true),
+ application:set_env(stdlib,utc_log,false),
+ ExpectedUtc = format(info,Msg,Meta,FC),
+
+ %% time_offset config parameter to formatter
+ %% overwrites sasl and stdlib utc_log
+ application:set_env(sasl,utc_log,false),
+ ExpectedUtc = format(info,Msg,Meta,FC#{time_offset=>"Z"}),
+
+ %% time_offset config parameter to formatter
+ %% overwrites sasl and stdlib utc_log
+ application:set_env(sasl,utc_log,true),
+ application:set_env(stdlib,utc_log,true),
+ ExpectedLocal = format(info,Msg,Meta,FC#{time_offset=>""}),
+
+ %% time_designator config parameter to formatter
+ ExpectedLocalS = default_time_format(Time,false,$\s),
+ ExpectedUtcS = default_time_format(Time,true,$\s),
+
+ ExpectedLocalS = format(info,Msg,Meta,FC#{time_offset=>"",
+ time_designator=>$\s}),
+ ExpectedUtcS = format(info,Msg,Meta,FC#{time_offset=>"Z",
+ time_designator=>$\s}),
ok.
format_time(cleanup,_Config) ->
- application:unset_env(kernel,logger_utc),
+ application:unset_env(sasl,utc_log),
+ application:unset_env(stdlib,utc_log),
ok.
level_or_msg_in_meta(_Config) ->
@@ -482,7 +643,7 @@ level_or_msg_in_meta(_Config) ->
ok.
faulty_log(_Config) ->
- %% Unexpected log (should be type logger:log()) - print error
+ %% Unexpected log (should be type logger:log_event()) - print error
{error,
function_clause,
{logger_formatter,format,[_,_],_}} =
@@ -509,6 +670,160 @@ faulty_msg(_Config) ->
#{})),
ok.
+-define(cfgerr(X), {error,{invalid_formatter_config,logger_formatter,X}}).
+check_config(_Config) ->
+ ok = logger_formatter:check_config(#{}),
+ ?cfgerr(bad) = logger_formatter:check_config(bad),
+
+ C1 = #{chars_limit => 1,
+ depth => 1,
+ legacy_header => true,
+ error_logger_notice_header => info,
+ max_size => 1,
+ report_cb => fun(R) -> {"~p",[R]} end,
+ single_line => false,
+ template => [],
+ time_designator => $T,
+ time_offset => 0},
+ ok = logger_formatter:check_config(C1),
+
+ ok = logger_formatter:check_config(#{chars_limit => unlimited}),
+ ?cfgerr({chars_limit,bad}) =
+ logger_formatter:check_config(#{chars_limit => bad}),
+
+ ok = logger_formatter:check_config(#{depth => unlimited}),
+ ?cfgerr({depth,bad}) =
+ logger_formatter:check_config(#{depth => bad}),
+
+ ok = logger_formatter:check_config(#{legacy_header => false}),
+ ?cfgerr({legacy_header,bad}) =
+ logger_formatter:check_config(#{legacy_header => bad}),
+
+ ok = logger_formatter:check_config(#{error_logger_notice_header => notice}),
+ ?cfgerr({error_logger_notice_header,bad}) =
+ logger_formatter:check_config(#{error_logger_notice_header => bad}),
+
+ ok = logger_formatter:check_config(#{max_size => unlimited}),
+ ?cfgerr({max_size,bad}) =
+ logger_formatter:check_config(#{max_size => bad}),
+
+ ok =
+ logger_formatter:check_config(#{report_cb => fun(_,_) -> "" end}),
+ ?cfgerr({report_cb,F}) =
+ logger_formatter:check_config(#{report_cb => F=fun(_,_,_) -> {"",[]} end}),
+ ?cfgerr({report_cb,bad}) =
+ logger_formatter:check_config(#{report_cb => bad}),
+
+ ok = logger_formatter:check_config(#{single_line => true}),
+ ?cfgerr({single_line,bad}) =
+ logger_formatter:check_config(#{single_line => bad}),
+
+ Ts = [[key],
+ [[key1,key2]],
+ [{key,[key],[]}],
+ [{[key1,key2],[[key1,key2]],["noexist"]}],
+ ["string"]],
+ [begin
+ ct:log("check template: ~p",[T]),
+ ok = logger_formatter:check_config(#{template => T})
+ end
+ || T <- Ts],
+
+ ETs = [bad,
+ [{key,bad}],
+ [{key,[key],bad}],
+ [{key,[key],"bad"}],
+ "bad",
+ [[key,$a,$b,$c]],
+ [[$a,$b,$c,key]]],
+ [begin
+ ct:log("check template: ~p",[T]),
+ {error,{invalid_formatter_template,logger_formatter,T}} =
+ logger_formatter:check_config(#{template => T})
+ end
+ || T <- ETs],
+
+ ?cfgerr({time_designator,bad}) =
+ logger_formatter:check_config(#{time_designator => bad}),
+ ?cfgerr({time_designator,"b"}) =
+ logger_formatter:check_config(#{time_designator => "b"}),
+
+ ok = logger_formatter:check_config(#{time_offset => -1}),
+ ok = logger_formatter:check_config(#{time_offset => "+02:00"}),
+ ok = logger_formatter:check_config(#{time_offset => "-23:59"}),
+ ok = logger_formatter:check_config(#{time_offset => "+24:00"}),
+ ok = logger_formatter:check_config(#{time_offset => "-25:00"}),
+ ?cfgerr({time_offset,bad}) =
+ logger_formatter:check_config(#{time_offset => bad}),
+ ?cfgerr({time_offset,"02:00"}) =
+ logger_formatter:check_config(#{time_offset => "02:00"}),
+ ?cfgerr({time_offset,"+02"}) =
+ logger_formatter:check_config(#{time_offset => "+02"}),
+
+ ok.
+
+%% Test that formatter config can be changed, and that the default
+%% template is updated accordingly
+update_config(_Config) ->
+ logger:add_handler_filter(default,silence,{fun(_,_) -> stop end,ok}),
+ ok = logger:add_handler(?MODULE,?MODULE,#{}),
+ D = lists:seq(1,1000),
+ logger:notice("~p~n",[D]),
+ {Lines1,C1} = check_log(),
+ [ct:log(L) || L <- Lines1],
+ ct:log("~p",[C1]),
+ [Line1] = Lines1,
+ [_Time,"notice: "++D1] = string:split(Line1," "),
+ true = length(D1)>3000,
+ true = #{}==C1,
+
+ ok = logger:update_formatter_config(?MODULE,single_line,false),
+ logger:notice("~p~n",[D]),
+ {Lines2,C2} = check_log(),
+ [ct:log(L) || L <- Lines2],
+ ct:log("~p",[C2]),
+ true = length(Lines2)>50,
+ true = #{single_line=>false}==C2,
+
+ ok = logger:update_formatter_config(?MODULE,#{legacy_header=>true}),
+ logger:notice("~p~n",[D]),
+ {Lines3,C3} = check_log(),
+ [ct:log(L) || L <- Lines3],
+ ct:log("~p",[C3]),
+ ["=NOTICE REPORT==== "++_|D3] = Lines3,
+ true = length(D3)>50,
+ true = #{legacy_header=>true,single_line=>false}==C3,
+
+ ok = logger:update_formatter_config(?MODULE,single_line,true),
+ logger:notice("~p~n",[D]),
+ {Lines4,C4} = check_log(),
+ [ct:log(L) || L <- Lines4],
+ ct:log("~p",[C4]),
+ ["=NOTICE REPORT==== "++_,D4] = Lines4,
+ true = length(D4)>3000,
+ true = #{legacy_header=>true,single_line=>true}==C4,
+
+ %% Finally, check that error_logger_notice_header works, default=info
+ error_logger:info_msg("~p",[D]),
+ {Lines5,C5} = check_log(),
+ [ct:log(L) || L <- Lines5],
+ ct:log("~p",[C5]),
+ ["=INFO REPORT==== "++_,_D5] = Lines5,
+
+ ok=logger:update_formatter_config(?MODULE,error_logger_notice_header,notice),
+ error_logger:info_msg("~p",[D]),
+ {Lines6,C6} = check_log(),
+ [ct:log(L) || L <- Lines6],
+ ct:log("~p",[C6]),
+ ["=NOTICE REPORT==== "++_,_D6] = Lines6,
+
+ ok.
+
+update_config(cleanup,_Config) ->
+ _ = logger:remove_handler(?MODULE),
+ _ = logger:remove_handler_filter(default,silence),
+ ok.
+
%%%-----------------------------------------------------------------
%%% Internal
format(Level,Msg,Meta,Config) ->
@@ -520,22 +835,16 @@ format(Log,Config) ->
default_time_format(Timestamp) ->
default_time_format(Timestamp,false).
-default_time_format(Timestamp0,Utc) when is_integer(Timestamp0) ->
- Timestamp=Timestamp0+erlang:time_offset(microsecond),
- %% calendar:system_time_to_rfc3339(Time,[{unit,microsecond}]).
- Micro = Timestamp rem 1000000,
- Sec = Timestamp div 1000000,
- UniversalTime = erlang:posixtime_to_universaltime(Sec),
- {Date,Time} =
- if Utc -> UniversalTime;
- true -> erlang:universaltime_to_localtime(UniversalTime)
- end,
- default_time_format(Date,Time,Micro).
-
-default_time_format({Y,M,D},{H,Min,S},Micro) ->
- lists:flatten(
- io_lib:format("~4w-~2..0w-~2..0w ~2w:~2..0w:~2..0w.~6..0w",
- [Y,M,D,H,Min,S,Micro])).
+default_time_format(Timestamp,Utc) ->
+ default_time_format(Timestamp,Utc,$T).
+
+default_time_format(Timestamp,Utc,Sep) ->
+ Offset = if Utc -> "Z";
+ true -> ""
+ end,
+ calendar:system_time_to_rfc3339(Timestamp,[{unit,microsecond},
+ {time_designator,Sep},
+ {offset,Offset}]).
integer(Str) ->
is_integer(list_to_integer(Str)).
@@ -551,10 +860,20 @@ my_try(Fun) ->
try Fun() catch C:R:S -> {C,R,hd(S)} end.
timestamp() ->
- erlang:monotonic_time(microsecond).
+ erlang:system_time(microsecond).
%% necessary?
add_time(#{time:=_}=Meta) ->
Meta;
add_time(Meta) ->
Meta#{time=>timestamp()}.
+
+%%%-----------------------------------------------------------------
+%%% handler callback
+log(Log,#{formatter:={M,C}}) ->
+ put(log,{M:format(Log,C),C}),
+ ok.
+
+check_log() ->
+ {S,C} = erase(log),
+ {string:lexemes(S,"\n"),C}.
diff --git a/lib/kernel/test/logger_legacy_SUITE.erl b/lib/kernel/test/logger_legacy_SUITE.erl
index b59f5f7758..c3cab07d81 100644
--- a/lib/kernel/test/logger_legacy_SUITE.erl
+++ b/lib/kernel/test/logger_legacy_SUITE.erl
@@ -20,6 +20,8 @@
-module(logger_legacy_SUITE).
-compile(export_all).
+-compile({nowarn_deprecated_function,[{gen_fsm,start,3},
+ {gen_fsm,send_all_state_event,2}]}).
-include_lib("common_test/include/ct.hrl").
-include_lib("kernel/include/logger.hrl").
@@ -67,25 +69,29 @@ end_per_suite(_Config) ->
init_per_group(std, Config) ->
ok = logger:set_handler_config(
error_logger,filters,
- [{domain,{fun logger_filters:domain/2,
- {log,prefix_of,[beam,erlang,otp]}}}]),
+ [{domain,{fun logger_filters:domain/2,{log,super,[otp]}}}]),
Config;
init_per_group(sasl, Config) ->
+ %% Since default level is notice, and progress reports are info,
+ %% we need to raise the global logger level to info in order to
+ %% receive these.
+ ok = logger:set_primary_config(level,info),
ok = logger:set_handler_config(
error_logger,filters,
- [{domain,{fun logger_filters:domain/2,
- {log,prefix_of,[beam,erlang,otp,sasl]}}}]),
+ [{domain,{fun logger_filters:domain/2,{log,super,[otp,sasl]}}}]),
%% cth_log_redirect checks if sasl is started before displaying
%% any sasl reports - so just to see the real sasl reports in tc
%% log:
- application:start(sasl),
- Config;
+ {ok,Apps} = application:ensure_all_started(sasl),
+ [{stop_apps,Apps}|Config];
init_per_group(_Group, Config) ->
Config.
-end_per_group(sasl, _Config) ->
- application:stop(sasl),
+end_per_group(sasl, Config) ->
+ Apps = ?config(stop_apps,Config),
+ [application:stop(App) || App <- Apps],
+ ok = logger:set_primary_config(level,notice),
ok;
end_per_group(_Group, _Config) ->
ok.
@@ -119,7 +125,7 @@ all() ->
gen_server(_Config) ->
{ok,Pid} = gen_server:start(?MODULE,gen_server,[]),
- Msg = fun() -> a=b end,
+ Msg = fun() -> erlang:error({badmatch,b}) end,
Pid ! Msg,
?check({warning_msg,"** Undefined handle_info in ~p"++_,[?MODULE,Msg]}),
ok = gen_server:cast(Pid,Msg),
@@ -129,7 +135,7 @@ gen_server(_Config) ->
gen_event(_Config) ->
{ok,Pid} = gen_event:start(),
ok = gen_event:add_handler(Pid,?MODULE,gen_event),
- Msg = fun() -> a=b end,
+ Msg = fun() -> erlang:error({badmatch,b}) end,
Pid ! Msg,
?check({warning_msg,"** Undefined handle_info in ~tp"++_,[?MODULE,Msg]}),
gen_event:notify(Pid,Msg),
@@ -138,7 +144,7 @@ gen_event(_Config) ->
gen_fsm(_Config) ->
{ok,Pid} = gen_fsm:start(?MODULE,gen_fsm,[]),
- Msg = fun() -> a=b end,
+ Msg = fun() -> erlang:error({badmatch,b}) end,
Pid ! Msg,
?check({warning_msg,"** Undefined handle_info in ~p"++_,[?MODULE,Msg]}),
gen_fsm:send_all_state_event(Pid,Msg),
@@ -147,7 +153,7 @@ gen_fsm(_Config) ->
gen_statem(_Config) ->
{ok,Pid} = gen_statem:start(?MODULE,gen_statem,[]),
- Msg = fun() -> a=b end,
+ Msg = fun() -> erlang:error({badmatch,b}) end,
Pid ! Msg,
?check({error,"** State machine ~tp terminating"++_,
[Pid,{info,Msg},{mystate,gen_statem},error,{badmatch,b}|_]}).
@@ -176,7 +182,7 @@ sasl_reports(Config) ->
ok = gen_server:cast(ChPid, fun() ->
spawn_link(fun() -> receive x->ok end end)
end),
- Msg = fun() -> a=b end,
+ Msg = fun() -> erlang:error({badmatch,b}) end,
ok = gen_server:cast(ChPid,Msg),
?check_no_flush({error,"** Generic server ~tp terminating"++_,
[ChPid,{'$gen_cast',Msg},gen_server,{{badmatch,b},_}]}),
diff --git a/lib/kernel/test/logger_simple_SUITE.erl b/lib/kernel/test/logger_simple_SUITE.erl
deleted file mode 100644
index 5d8d32492d..0000000000
--- a/lib/kernel/test/logger_simple_SUITE.erl
+++ /dev/null
@@ -1,247 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2018. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% 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(logger_simple_SUITE).
-
--compile(export_all).
-
--include_lib("common_test/include/ct.hrl").
--include_lib("kernel/include/logger.hrl").
--include_lib("kernel/src/logger_internal.hrl").
-
--define(check_no_log,[] = test_server:messages_get()).
--define(check(Expected),
- receive {log,Expected} ->
- [] = test_server:messages_get()
- after 1000 ->
- ct:fail({report_not_received,
- {line,?LINE},
- {expected,Expected},
- {got,test_server:messages_get()}})
- end).
-
--define(str,"Log from "++atom_to_list(?FUNCTION_NAME)++
- ":"++integer_to_list(?LINE)).
--define(map_rep,#{function=>?FUNCTION_NAME, line=>?LINE}).
--define(keyval_rep,[{function,?FUNCTION_NAME}, {line,?LINE}]).
-
-suite() ->
- [{timetrap,{seconds,30}}].
-
-init_per_suite(Config) ->
- #{handlers:=Hs0} = logger:i(),
- Hs = lists:keydelete(cth_log_redirect,1,Hs0),
- [ok = logger:remove_handler(Id) || {Id,_,_} <- Hs],
- Env = [{App,Key,application:get_env(App,Key)} ||
- {App,Key} <- [{kernel,logger_dest},
- {kernel,logger_level}]],
- [{env,Env},{logger,Hs}|Config].
-
-end_per_suite(Config) ->
- [application:set_env(App,Key,Val) || {App,Key,Val} <- ?config(env,Config)],
- Hs = ?config(logger,Config),
- [ok = logger:add_handler(Id,Mod,C) || {Id,Mod,C} <- Hs],
- ok.
-
-init_per_group(_Group, Config) ->
- Config.
-
-end_per_group(_Group, _Config) ->
- ok.
-
-init_per_testcase(_TestCase, Config) ->
- Config.
-
-end_per_testcase(Case, Config) ->
- try apply(?MODULE,Case,[cleanup,Config])
- catch error:undef -> ok
- end,
- ok.
-
-groups() ->
- [].
-
-all() ->
- [start_stop,
- get_buffer,
- replace_file,
- replace_disk_log
- ].
-
-start_stop(_Config) ->
- undefined = whereis(logger_simple),
- register(logger_simple,self()),
- {error,_} = logger:add_handler(logger_simple,
- logger_simple,
- #{filter_default=>log}),
- unregister(logger_simple),
- ok = logger:add_handler(logger_simple,logger_simple,#{filter_default=>log}),
- Pid = whereis(logger_simple),
- true = is_pid(Pid),
- ok = logger:remove_handler(logger_simple),
- false = is_pid(whereis(logger_simple)),
- ok.
-start_stop(cleanup,_Config) ->
- logger:remove_handler(logger_simple).
-
-get_buffer(_Config) ->
- %% Start simple without buffer
- ok = logger:add_handler(logger_simple,logger_simple,
- #{filter_default=>log}),
- logger:emergency(?str),
- logger:alert(?str,[]),
- logger:error(?map_rep),
- logger:info(?keyval_rep),
- {ok,[]} = logger_simple:get_buffer(), % no buffer
- ok = logger:remove_handler(logger_simple),
-
- %% Start with buffer
- ok = logger:add_handler(logger_simple,logger_simple,
- #{filter_default=>log,
- logger_simple=>#{buffer=>true}}),
- logger:emergency(M1=?str),
- logger:alert(M2=?str,[]),
- logger:error(M3=?map_rep),
- logger:info(M4=?keyval_rep),
- logger:info(M41=?keyval_rep++[not_key_val]),
- error_logger:error_report(some_type,M5=?map_rep),
- error_logger:warning_report("some_type",M6=?map_rep),
- logger:critical(M7=?str,[A7=?keyval_rep]),
- logger:notice(M8=["fake",string,"line:",?LINE]),
- {ok,Buffered1} = logger_simple:get_buffer(),
- [#{level:=emergency,msg:={string,M1}},
- #{level:=alert,msg:={M2,[]}},
- #{level:=error,msg:={report,M3}},
- #{level:=info,msg:={report,M4}},
- #{level:=info,msg:={report,M41}},
- #{level:=error,msg:={report,#{label:={error_logger,error_report},
- report:=M5}}},
- #{level:=warning,msg:={report,#{label:={error_logger,warning_report},
- report:=M6}}},
- #{level:=critical,msg:={M7,[A7]}},
- #{level:=notice,msg:={string,M8}}] = Buffered1,
-
- %% Keep logging - should not buffer any more
- logger:emergency(?str),
- logger:alert(?str,[]),
- logger:error(?map_rep),
- logger:info(?keyval_rep),
- {ok,[]} = logger_simple:get_buffer(),
- ok = logger:remove_handler(logger_simple),
-
- %% Fill buffer and drop
- ok = logger:add_handler(logger_simple,logger_simple,
- #{filter_default=>log,
- logger_simple=>#{buffer=>true}}),
- logger:emergency(M9=?str),
- M10=?str,
- [logger:info(M10) || _ <- lists:seq(1,8)],
- logger:error(M11=?str),
- logger:error(?str),
- logger:error(?str),
- {ok,Buffered3} = logger_simple:get_buffer(),
- 11 = length(Buffered3),
- [#{level:=emergency,msg:={string,M9}},
- #{level:=info,msg:={string,M10}},
- #{level:=info,msg:={string,M10}},
- #{level:=info,msg:={string,M10}},
- #{level:=info,msg:={string,M10}},
- #{level:=info,msg:={string,M10}},
- #{level:=info,msg:={string,M10}},
- #{level:=info,msg:={string,M10}},
- #{level:=info,msg:={string,M10}},
- #{level:=error,msg:={string,M11}},
- #{level:=info,msg:={"Simple handler buffer full, dropped ~w messages",[2]}}]
- = Buffered3,
- ok.
-get_buffer(cleanup,_Config) ->
- logger:remove_handler(logger_simple).
-
-replace_file(Config) ->
- ok = logger:add_handler(logger_simple,logger_simple,
- #{filter_default=>log,
- logger_simple=>#{buffer=>true}}),
- logger:emergency(M1=?str),
- logger:alert(M2=?str,[]),
- logger:error(?map_rep),
- logger:info(?keyval_rep),
- undefined = whereis(?STANDARD_HANDLER),
- PrivDir = ?config(priv_dir,Config),
- File = filename:join(PrivDir,atom_to_list(?FUNCTION_NAME)++".log"),
-
- application:set_env(kernel,logger_dest,{file,File}),
- application:set_env(kernel,logger_level,info),
-
- ok = logger:setup_standard_handler(),
- true = is_pid(whereis(?STANDARD_HANDLER)),
- ok = logger_std_h:filesync(?STANDARD_HANDLER),
- {ok,Bin} = file:read_file(File),
- Lines = [unicode:characters_to_list(L) ||
- L <- binary:split(Bin,<<"\n">>,[global,trim])],
- ["=EMERGENCY REPORT===="++_,
- M1,
- "=ALERT REPORT===="++_,
- M2,
- "=ERROR REPORT===="++_,
- _,
- _,
- "=INFO REPORT===="++_,
- _,
- _] = Lines,
- ok.
-replace_file(cleanup,_Config) ->
- logger:remove_handler(?STANDARD_HANDLER),
- logger:remove_handler(logger_simple).
-
-replace_disk_log(Config) ->
- ok = logger:add_handler(logger_simple,logger_simple,
- #{filter_default=>log,
- logger_simple=>#{buffer=>true}}),
- logger:emergency(M1=?str),
- logger:alert(M2=?str,[]),
- logger:error(?map_rep),
- logger:info(?keyval_rep),
- undefined = whereis(?STANDARD_HANDLER),
- PrivDir = ?config(priv_dir,Config),
- File = filename:join(PrivDir,atom_to_list(?FUNCTION_NAME)),
-
- application:set_env(kernel,logger_dest,{disk_log,File}),
- application:set_env(kernel,logger_level,info),
-
- ok = logger:setup_standard_handler(),
- true = is_pid(whereis(?STANDARD_HANDLER)),
- ok = logger_disk_log_h:disk_log_sync(?STANDARD_HANDLER),
- {ok,Bin} = file:read_file(File++".1"),
- Lines = [unicode:characters_to_list(L) ||
- L <- binary:split(Bin,<<"\n">>,[global,trim])],
- ["=EMERGENCY REPORT===="++_,
- M1,
- "=ALERT REPORT===="++_,
- M2,
- "=ERROR REPORT===="++_,
- _,
- _,
- "=INFO REPORT===="++_,
- _,
- _|_] = Lines, % the tail might be an info report about opening the disk log
- ok.
-replace_disk_log(cleanup,_Config) ->
- logger:remove_handler(?STANDARD_HANDLER),
- logger:remove_handler(logger_simple).
-
diff --git a/lib/kernel/test/logger_simple_h_SUITE.erl b/lib/kernel/test/logger_simple_h_SUITE.erl
new file mode 100644
index 0000000000..79e5c057ad
--- /dev/null
+++ b/lib/kernel/test/logger_simple_h_SUITE.erl
@@ -0,0 +1,210 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% 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(logger_simple_h_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("kernel/include/logger.hrl").
+-include_lib("kernel/src/logger_internal.hrl").
+
+-import(logger_test_lib, [setup/2, log/3, sync_and_read/3]).
+
+-define(check_no_log,[] = test_server:messages_get()).
+-define(check(Expected),
+ receive {log,Expected} ->
+ [] = test_server:messages_get()
+ after 1000 ->
+ ct:fail({report_not_received,
+ {line,?LINE},
+ {expected,Expected},
+ {got,test_server:messages_get()}})
+ end).
+
+-define(str,"Log from "++atom_to_list(?FUNCTION_NAME)++
+ ":"++integer_to_list(?LINE)).
+-define(map_rep,#{function=>?FUNCTION_NAME, line=>?LINE}).
+-define(keyval_rep,[{function,?FUNCTION_NAME}, {line,?LINE}]).
+
+suite() ->
+ [{timetrap,{seconds,30}},
+ {ct_hooks, [logger_test_lib]}].
+
+init_per_suite(Config) ->
+ Hs0 = logger:get_handler_config(),
+ Hs = lists:keydelete(cth_log_redirect,1,Hs0),
+ [ok = logger:remove_handler(Id) || {Id,_,_} <- Hs],
+ Env = [{App,Key,application:get_env(App,Key)} ||
+ {App,Key} <- [{kernel,logger_level}]],
+ [{env,Env},{logger,Hs}|Config].
+
+end_per_suite(Config) ->
+ [application:set_env(App,Key,Val) || {App,Key,Val} <- ?config(env,Config)],
+ Hs = ?config(logger,Config),
+ [ok = logger:add_handler(Id,Mod,C) || {Id,Mod,C} <- Hs],
+ ok.
+
+init_per_group(_Group, Config) ->
+ Config.
+
+end_per_group(_Group, _Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+end_per_testcase(Case, Config) ->
+ try apply(?MODULE,Case,[cleanup,Config])
+ catch error:undef -> ok
+ end,
+ ok.
+
+groups() ->
+ [].
+
+all() ->
+ [start_stop,
+ replace_default,
+ replace_file,
+ replace_disk_log
+ ].
+
+start_stop(_Config) ->
+ undefined = whereis(logger_simple_h),
+ register(logger_simple_h,self()),
+ {error,_} = logger:add_handler(simple,
+ logger_simple_h,
+ #{filter_default=>log}),
+ unregister(logger_simple_h),
+ ok = logger:add_handler(simple,logger_simple_h,#{filter_default=>log}),
+ Pid = whereis(logger_simple_h),
+ true = is_pid(Pid),
+ ok = logger:remove_handler(simple),
+ false = is_pid(whereis(logger_simple_h)),
+ ok.
+start_stop(cleanup,_Config) ->
+ logger:remove_handler(simple).
+
+%% This testcase just tests that it does not crash, the default handler prints
+%% to stdout which we cannot read from in a detached slave.
+replace_default(Config) ->
+
+ {ok, _, Node} = logger_test_lib:setup(Config, [{logger, [{handler, default, undefined}]}]),
+ log(Node, emergency, [?str]),
+ log(Node, alert, [?str,[]]),
+ log(Node, error, [?map_rep]),
+ log(Node, info, [?keyval_rep]),
+ log(Node, info, [?keyval_rep++[not_key_val]]),
+ rpc:call(Node, error_logger, error_report, [some_type,?map_rep]),
+ rpc:call(Node, error_logger, warning_report, ["some_type",?map_rep]),
+ log(Node, critical, [?str,[?keyval_rep]]),
+ log(Node, notice, [["fake",string,"line:",?LINE]]),
+
+ Env = rpc:call(Node, application, get_env, [kernel, logger, []]),
+ ok = rpc:call(Node, logger, add_handlers, [Env]),
+
+ ok.
+
+replace_file(Config) ->
+
+ {ok, _, Node} = logger_test_lib:setup(Config, [{logger, [{handler, default, undefined}]}]),
+ log(Node, emergency, [M1=?str]),
+ log(Node, alert, [M2=?str,[]]),
+ log(Node, error, [?map_rep]),
+ log(Node, warning, [?keyval_rep]),
+ log(Node, warning, [?keyval_rep++[not_key_val]]),
+ log(Node, critical, [?str,[?keyval_rep]]),
+ log(Node, notice, [["fake",string,"line:",?LINE]]),
+
+ File = filename:join(proplists:get_value(priv_dir,Config),
+ atom_to_list(?FUNCTION_NAME)++".log"),
+
+ ok = rpc:call(Node, logger, add_handlers,
+ [[{handler, default, logger_std_h,
+ #{ config => #{ type => {file, File} },
+ formatter => {?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}}}]]),
+
+ {ok,Bin} = sync_and_read(Node, file, File),
+ Lines = [unicode:characters_to_list(L) ||
+ L <- binary:split(Bin,<<"\n">>,[global,trim])],
+ ["=EMERGENCY REPORT===="++_,
+ M1,
+ "=ALERT REPORT===="++_,
+ M2,
+ "=ERROR REPORT===="++_,
+ _,
+ _,
+ "=WARNING REPORT===="++_,
+ _,
+ _,
+ "=WARNING REPORT===="++_,
+ _,
+ _,
+ _,
+ "=CRITICAL REPORT===="++_,
+ _,
+ _,
+ "=NOTICE REPORT===="++_,
+ _
+ ] = Lines,
+ ok.
+
+replace_disk_log(Config) ->
+
+ {ok, _, Node} = logger_test_lib:setup(Config, [{logger, [{handler, default, undefined}]}]),
+ log(Node, emergency, [M1=?str]),
+ log(Node, alert, [M2=?str,[]]),
+ log(Node, error, [?map_rep]),
+ log(Node, warning, [?keyval_rep]),
+ log(Node, warning, [?keyval_rep++[not_key_val]]),
+ log(Node, critical, [?str,[?keyval_rep]]),
+ log(Node, notice, [["fake",string,"line:",?LINE]]),
+
+ File = filename:join(proplists:get_value(priv_dir,Config),
+ atom_to_list(?FUNCTION_NAME)++".log"),
+
+ ok = rpc:call(Node, logger, add_handlers,
+ [[{handler, default, logger_disk_log_h,
+ #{ config => #{ file => File },
+ formatter => {?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}}}]]),
+ {ok,Bin} = sync_and_read(Node, disk_log, File),
+ Lines = [unicode:characters_to_list(L) ||
+ L <- binary:split(Bin,<<"\n">>,[global,trim])],
+ ["=EMERGENCY REPORT===="++_,
+ M1,
+ "=ALERT REPORT===="++_,
+ M2,
+ "=ERROR REPORT===="++_,
+ _,
+ _,
+ "=WARNING REPORT===="++_,
+ _,
+ _,
+ "=WARNING REPORT===="++_,
+ _,
+ _,
+ _,
+ "=CRITICAL REPORT===="++_,
+ _,
+ _,
+ "=NOTICE REPORT===="++_,
+ _
+ ] = Lines,
+ ok.
diff --git a/lib/kernel/test/logger_std_h_SUITE.erl b/lib/kernel/test/logger_std_h_SUITE.erl
index 7c8d63cbbd..0930cd4211 100644
--- a/lib/kernel/test/logger_std_h_SUITE.erl
+++ b/lib/kernel/test/logger_std_h_SUITE.erl
@@ -45,16 +45,13 @@
-define(bin(Msg), list_to_binary(Msg++"\n")).
-define(domain,#{domain=>[?MODULE]}).
--define(FILESYNC_REP_INT, if is_atom(?FILESYNC_REPEAT_INTERVAL) -> 5500;
- true -> ?FILESYNC_REPEAT_INTERVAL + 500
- end).
-
suite() ->
- [{timetrap,{seconds,30}}].
+ [{timetrap,{seconds,30}},
+ {ct_hooks,[logger_test_lib]}].
init_per_suite(Config) ->
timer:start(), % to avoid progress report
- {ok,{?STANDARD_HANDLER,#{formatter:=OrigFormatter}}} =
+ {ok,#{formatter:=OrigFormatter}} =
logger:get_handler_config(?STANDARD_HANDLER),
[{formatter,OrigFormatter}|Config].
@@ -72,12 +69,25 @@ end_per_group(_Group, _Config) ->
init_per_testcase(TestHooksCase, Config) when
TestHooksCase == write_failure;
TestHooksCase == sync_failure ->
- if ?TEST_HOOKS_TAB == undefined ->
+ case (fun() -> ?TEST_HOOKS_TAB == undefined end)() of
+ true ->
{skip,"Define the TEST_HOOKS macro to run this test"};
- true ->
+ false ->
ct:print("********** ~w **********", [TestHooksCase]),
Config
end;
+init_per_testcase(OPCase, Config) when
+ OPCase == qlen_kill_new;
+ OPCase == restart_after ->
+ case re:run(erlang:system_info(system_version),
+ "dirty-schedulers-TEST",
+ [{capture,none}]) of
+ match ->
+ {skip,"Overload protection test skipped on dirty-schedulers-TEST"};
+ nomatch ->
+ ct:print("********** ~w **********", [OPCase]),
+ Config
+ end;
init_per_testcase(TestCase, Config) ->
ct:print("********** ~w **********", [TestCase]),
Config.
@@ -107,7 +117,7 @@ all() ->
info_and_reset,
reconfig,
file_opts,
- filesync,
+ sync,
write_failure,
sync_failure,
op_switch_to_sync_file,
@@ -131,7 +141,7 @@ all() ->
add_remove_instance_tty(_Config) ->
{error,{handler_not_added,{invalid_config,logger_std_h,{type,tty}}}} =
logger:add_handler(?MODULE,logger_std_h,
- #{logger_std_h => #{type => tty},
+ #{config => #{type => tty},
filter_default=>log,
formatter=>{?MODULE,self()}}),
ok.
@@ -165,33 +175,33 @@ add_remove_instance_file2(cleanup,_Config) ->
add_remove_instance_file(Log, Type) ->
ok = logger:add_handler(?MODULE,
logger_std_h,
- #{logger_std_h => #{type => Type},
+ #{config => #{type => Type},
filter_default=>stop,
filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
formatter=>{?MODULE,self()}}),
- Pid = whereis(?MODULE),
+ Pid = whereis(h_proc_name()),
true = is_pid(Pid),
- logger:info(M1=?msg,?domain),
+ logger:notice(M1=?msg,?domain),
?check(M1),
B1 = ?bin(M1),
- try_read_file(Log, {ok,B1}, ?FILESYNC_REP_INT),
+ try_read_file(Log, {ok,B1}, filesync_rep_int()),
ok = logger:remove_handler(?MODULE),
timer:sleep(500),
- undefined = whereis(?MODULE),
- logger:info(?msg,?domain),
+ undefined = whereis(h_proc_name()),
+ logger:notice(?msg,?domain),
?check_no_log,
- try_read_file(Log, {ok,B1}, ?FILESYNC_REP_INT),
+ try_read_file(Log, {ok,B1}, filesync_rep_int()),
ok.
default_formatter(_Config) ->
ok = logger:set_handler_config(?STANDARD_HANDLER,formatter,
{?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}),
ct:capture_start(),
- logger:info(M1=?msg),
+ logger:notice(M1=?msg),
timer:sleep(100),
ct:capture_stop(),
[Msg] = ct:capture_get(),
- match = re:run(Msg,"=INFO REPORT====.*\n"++M1,[{capture,none}]),
+ match = re:run(Msg,"=NOTICE REPORT====.*\n"++M1,[{capture,none}]),
ok.
errors(Config) ->
@@ -211,20 +221,26 @@ errors(Config) ->
{handler_not_added,
{invalid_config,logger_std_h,{type,faulty_type}}}} =
logger:add_handler(?MODULE,logger_std_h,
- #{logger_std_h => #{type => faulty_type}}),
+ #{config => #{type => faulty_type}}),
- NoDir = lists:concat(["/",?MODULE,"_dir"]),
- {error,
- {handler_not_added,{{open_failed,NoDir,eacces},_}}} =
- logger:add_handler(myh2,logger_std_h,
- #{logger_std_h=>#{type=>{file,NoDir}}}),
+ case os:type() of
+ {win32,_} ->
+ %% No use in testing file access on windows
+ ok;
+ _ ->
+ NoDir = lists:concat(["/",?MODULE,"_dir"]),
+ {error,
+ {handler_not_added,{{open_failed,NoDir,eacces},_}}} =
+ logger:add_handler(myh2,logger_std_h,
+ #{config=>#{type=>{file,NoDir}}})
+ end,
{error,
{handler_not_added,{{open_failed,Log,_},_}}} =
logger:add_handler(myh3,logger_std_h,
- #{logger_std_h=>#{type=>{file,Log,[bad_file_opt]}}}),
+ #{config=>#{type=>{file,Log,[bad_file_opt]}}}),
- ok = logger:info(?msg).
+ ok = logger:notice(?msg).
errors(cleanup,_Config) ->
logger:remove_handler(?MODULE).
@@ -236,41 +252,40 @@ formatter_fail(Config) ->
%% no formatter
ok = logger:add_handler(?MODULE,
logger_std_h,
- #{logger_std_h => #{type => {file,Log}},
+ #{config => #{type => {file,Log}},
filter_default=>stop,
filters=>?DEFAULT_HANDLER_FILTERS([?MODULE])}),
- Pid = whereis(?MODULE),
+ Pid = whereis(h_proc_name()),
true = is_pid(Pid),
- {ok,#{handlers:=H}} = logger:get_logger_config(),
+ H = logger:get_handler_ids(),
true = lists:member(?MODULE,H),
%% Formatter is added automatically
- {ok,{_,#{formatter:={logger_formatter,_}}}} =
- logger:get_handler_config(?MODULE),
- logger:info(M1=?msg,?domain),
- Got1 = try_match_file(Log,"=INFO REPORT====.*\n"++M1,5000),
+ {ok,#{formatter:={logger_formatter,_}}} = logger:get_handler_config(?MODULE),
+ logger:notice(M1=?msg,?domain),
+ Got1 = try_match_file(Log,"[0-9\\+\\-T:\\.]* notice: "++M1,5000),
ok = logger:set_handler_config(?MODULE,formatter,{nonexistingmodule,#{}}),
- logger:info(M2=?msg,?domain),
+ logger:notice(M2=?msg,?domain),
Got2 = try_match_file(Log,
- Got1++"=INFO REPORT====.*\nFORMATTER CRASH: .*"++M2,
+ escape(Got1)++"[0-9\\+\\-T:\\.]* notice: FORMATTER CRASH: .*"++M2,
5000),
ok = logger:set_handler_config(?MODULE,formatter,{?MODULE,crash}),
- logger:info(M3=?msg,?domain),
+ logger:notice(M3=?msg,?domain),
Got3 = try_match_file(Log,
- Got2++"=INFO REPORT====.*\nFORMATTER CRASH: .*"++M3,
+ escape(Got2)++"[0-9\\+\\-T:\\.]* notice: FORMATTER CRASH: .*"++M3,
5000),
ok = logger:set_handler_config(?MODULE,formatter,{?MODULE,bad_return}),
- logger:info(?msg,?domain),
+ logger:notice(?msg,?domain),
try_match_file(Log,
- Got3++"FORMATTER ERROR: bad_return_value",
+ escape(Got3)++"FORMATTER ERROR: bad_return_value",
5000),
%% Check that handler is still alive and was never dead
- Pid = whereis(?MODULE),
- {ok,#{handlers:=H}} = logger:get_logger_config(),
+ Pid = whereis(h_proc_name()),
+ H = logger:get_handler_ids(),
ok.
@@ -280,34 +295,41 @@ formatter_fail(cleanup,_Config) ->
config_fail(_Config) ->
{error,{handler_not_added,{invalid_config,logger_std_h,{bad,bad}}}} =
logger:add_handler(?MODULE,logger_std_h,
- #{logger_std_h => #{bad => bad},
+ #{config => #{bad => bad},
filter_default=>log,
formatter=>{?MODULE,self()}}),
{error,{handler_not_added,{invalid_config,logger_std_h,
{restart_type,bad}}}} =
logger:add_handler(?MODULE,logger_std_h,
- #{logger_std_h => #{restart_type => bad},
+ #{config => #{restart_type => bad},
filter_default=>log,
formatter=>{?MODULE,self()}}),
- {error,{handler_not_added,{invalid_levels,{42,42,_}}}} =
+ {error,{handler_not_added,{invalid_levels,{_,1,_}}}} =
+ logger:add_handler(?MODULE,logger_std_h,
+ #{config => #{drop_mode_qlen=>1}}),
+ {error,{handler_not_added,{invalid_levels,{43,42,_}}}} =
+ logger:add_handler(?MODULE,logger_std_h,
+ #{config => #{sync_mode_qlen=>43,
+ drop_mode_qlen=>42}}),
+ {error,{handler_not_added,{invalid_levels,{_,43,42}}}} =
logger:add_handler(?MODULE,logger_std_h,
- #{logger_std_h => #{toggle_sync_qlen=>42,
- drop_new_reqs_qlen=>42}}),
+ #{config => #{drop_mode_qlen=>43,
+ flush_qlen=>42}}),
ok = logger:add_handler(?MODULE,logger_std_h,
#{filter_default=>log,
formatter=>{?MODULE,self()}}),
{error,{illegal_config_change,_,_}} =
- logger:set_handler_config(?MODULE,logger_std_h,
+ logger:set_handler_config(?MODULE,config,
#{type=>{file,"file"}}),
{error,{illegal_config_change,_,_}} =
logger:set_handler_config(?MODULE,id,bad),
{error,{invalid_levels,_}} =
- logger:set_handler_config(?MODULE,logger_std_h,
- #{toggle_sync_qlen=>100,
- flush_reqs_qlen=>99}),
+ logger:set_handler_config(?MODULE,config,
+ #{sync_mode_qlen=>100,
+ flush_qlen=>99}),
{error,{invalid_config,logger_std_h,{filesync_rep_int,2000}}} =
- logger:set_handler_config(?MODULE, logger_std_h,
+ logger:set_handler_config(?MODULE, config,
#{filesync_rep_int => 2000}),
ok.
@@ -315,33 +337,41 @@ config_fail(cleanup,_Config) ->
logger:remove_handler(?MODULE).
crash_std_h_to_file(Config) ->
- crash_std_h(Config,?FUNCTION_NAME,logger_dest,file).
+ Dir = ?config(priv_dir,Config),
+ Log = filename:join(Dir,lists:concat([?MODULE,"_",?FUNCTION_NAME,".log"])),
+ crash_std_h(Config,?FUNCTION_NAME,
+ [{handler,default,logger_std_h,
+ #{ config => #{ type => {file, Log} }}}],
+ file, Log).
crash_std_h_to_file(cleanup,_Config) ->
crash_std_h(cleanup).
crash_std_h_to_disk_log(Config) ->
- crash_std_h(Config,?FUNCTION_NAME,logger_dest,disk_log).
+ Dir = ?config(priv_dir,Config),
+ Log = filename:join(Dir,lists:concat([?MODULE,"_",?FUNCTION_NAME,".log"])),
+ crash_std_h(Config,?FUNCTION_NAME,
+ [{handler,default,logger_disk_log_h,
+ #{ config => #{ file => Log }}}],
+ disk_log,Log).
crash_std_h_to_disk_log(cleanup,_Config) ->
crash_std_h(cleanup).
-crash_std_h(Config,Func,Var,Type) ->
+crash_std_h(Config,Func,Var,Type,Log) ->
Dir = ?config(priv_dir,Config),
- File = lists:concat([?MODULE,"_",Func,".log"]),
- Log = filename:join(Dir,File),
+ SysConfig = filename:join(Dir,lists:concat([?MODULE,"_",Func,".config"])),
+ ok = file:write_file(SysConfig, io_lib:format("[{kernel,[{logger,~p}]}].",[Var])),
Pa = filename:dirname(code:which(?MODULE)),
- TypeAndLog =
- case os:type() of
- {win32,_} ->
- lists:concat([" {",Type,",\\\"",Log,"\\\"}"]);
- _ ->
- lists:concat([" \'{",Type,",\"",Log,"\"}\'"])
- end,
- Args = lists:concat([" -kernel ",Var,TypeAndLog," -pa ",Pa]),
Name = lists:concat([?MODULE,"_",Func]),
+ Args = lists:concat([" -config ",filename:rootname(SysConfig)," -pa ",Pa]),
ct:pal("Starting ~p with ~tp", [Name,Args]),
%% Start a node which prints kernel logs to the destination specified by Type
{ok,Node} = test_server:start_node(Name, peer, [{args, Args}]),
- Pid = rpc:call(Node,erlang,whereis,[?STANDARD_HANDLER]),
+ HProcName =
+ case Type of
+ file -> ?name_to_reg_name(logger_std_h,?STANDARD_HANDLER);
+ disk_log -> ?name_to_reg_name(logger_disk_log_h,?STANDARD_HANDLER)
+ end,
+ Pid = rpc:call(Node,erlang,whereis,[HProcName]),
ok = rpc:call(Node,logger,set_handler_config,[?STANDARD_HANDLER,formatter,
{?MODULE,self()}]),
ok = log_on_remote_node(Node,"dummy1"),
@@ -354,7 +384,7 @@ crash_std_h(Config,Func,Var,Type) ->
%% Wait a bit, then check that it is gone
timer:sleep(2000),
- undefined = rpc:call(Node,erlang,whereis,[?STANDARD_HANDLER]),
+ undefined = rpc:call(Node,erlang,whereis,[HProcName]),
%% Check that file is not empty
{ok,Bin2} = sync_and_read(Node,Type,Log),
@@ -368,7 +398,7 @@ crash_std_h(Config,Func,Var,Type) ->
log_on_remote_node(Node,Msg) ->
_ = spawn_link(Node,
fun() -> erlang:group_leader(whereis(user),self()),
- logger:info(Msg)
+ logger:notice(Msg)
end),
ok.
@@ -378,7 +408,7 @@ crash_std_h(cleanup) ->
[test_server:stop_node(Node) || Node <- Nodes].
sync_and_read(Node,disk_log,Log) ->
- rpc:call(Node,logger_disk_log_h,disk_log_sync,[?STANDARD_HANDLER]),
+ rpc:call(Node,logger_disk_log_h,filesync,[?STANDARD_HANDLER]),
case file:read_file(Log ++ ".1") of
{ok,<<>>} ->
timer:sleep(5000),
@@ -410,51 +440,51 @@ reconfig(Config) ->
Dir = ?config(priv_dir,Config),
ok = logger:add_handler(?MODULE,
logger_std_h,
- #{logger_std_h => #{type => standard_io},
+ #{config => #{type => standard_io},
filter_default=>log,
filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
formatter=>{?MODULE,self()}}),
#{id := ?MODULE,
type := standard_io,
file_ctrl_pid := FileCtrlPid,
- toggle_sync_qlen := ?TOGGLE_SYNC_QLEN,
- drop_new_reqs_qlen := ?DROP_NEW_REQS_QLEN,
- flush_reqs_qlen := ?FLUSH_REQS_QLEN,
- enable_burst_limit := ?ENABLE_BURST_LIMIT,
- burst_limit_size := ?BURST_LIMIT_SIZE,
- burst_window_time := ?BURST_WINDOW_TIME,
- enable_kill_overloaded := ?ENABLE_KILL_OVERLOADED,
- handler_overloaded_qlen := ?HANDLER_OVERLOADED_QLEN,
- handler_overloaded_mem := ?HANDLER_OVERLOADED_MEM,
- handler_restart_after := ?HANDLER_RESTART_AFTER,
+ sync_mode_qlen := ?SYNC_MODE_QLEN,
+ drop_mode_qlen := ?DROP_MODE_QLEN,
+ flush_qlen := ?FLUSH_QLEN,
+ burst_limit_enable := ?BURST_LIMIT_ENABLE,
+ burst_limit_max_count := ?BURST_LIMIT_MAX_COUNT,
+ burst_limit_window_time := ?BURST_LIMIT_WINDOW_TIME,
+ overload_kill_enable := ?OVERLOAD_KILL_ENABLE,
+ overload_kill_qlen := ?OVERLOAD_KILL_QLEN,
+ overload_kill_mem_size := ?OVERLOAD_KILL_MEM_SIZE,
+ overload_kill_restart_after := ?OVERLOAD_KILL_RESTART_AFTER,
filesync_repeat_interval := ?FILESYNC_REPEAT_INTERVAL} =
logger_std_h:info(?MODULE),
- ok = logger:set_handler_config(?MODULE, logger_std_h,
- #{toggle_sync_qlen => 1,
- drop_new_reqs_qlen => 2,
- flush_reqs_qlen => 3,
- enable_burst_limit => false,
- burst_limit_size => 10,
- burst_window_time => 10,
- enable_kill_overloaded => true,
- handler_overloaded_qlen => 100000,
- handler_overloaded_mem => 10000000,
- handler_restart_after => never,
+ ok = logger:set_handler_config(?MODULE, config,
+ #{sync_mode_qlen => 1,
+ drop_mode_qlen => 2,
+ flush_qlen => 3,
+ burst_limit_enable => false,
+ burst_limit_max_count => 10,
+ burst_limit_window_time => 10,
+ overload_kill_enable => true,
+ overload_kill_qlen => 100000,
+ overload_kill_mem_size => 10000000,
+ overload_kill_restart_after => infinity,
filesync_repeat_interval => no_repeat}),
#{id := ?MODULE,
type := standard_io,
file_ctrl_pid := FileCtrlPid,
- toggle_sync_qlen := 1,
- drop_new_reqs_qlen := 2,
- flush_reqs_qlen := 3,
- enable_burst_limit := false,
- burst_limit_size := 10,
- burst_window_time := 10,
- enable_kill_overloaded := true,
- handler_overloaded_qlen := 100000,
- handler_overloaded_mem := 10000000,
- handler_restart_after := never,
+ sync_mode_qlen := 1,
+ drop_mode_qlen := 2,
+ flush_qlen := 3,
+ burst_limit_enable := false,
+ burst_limit_max_count := 10,
+ burst_limit_window_time := 10,
+ overload_kill_enable := true,
+ overload_kill_qlen := 100000,
+ overload_kill_mem_size := 10000000,
+ overload_kill_restart_after := infinity,
filesync_repeat_interval := no_repeat} = logger_std_h:info(?MODULE),
ok.
@@ -469,34 +499,34 @@ file_opts(Config) ->
BadType = {file,Log,BadFileOpts},
{error,{handler_not_added,{{open_failed,Log,enoent},_}}} =
logger:add_handler(?MODULE, logger_std_h,
- #{logger_std_h => #{type => BadType}}),
+ #{config => #{type => BadType}}),
OkFileOpts = [raw,append],
OkType = {file,Log,OkFileOpts},
ok = logger:add_handler(?MODULE,
logger_std_h,
- #{logger_std_h => #{type => OkType},
+ #{config => #{type => OkType},
filter_default=>log,
filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
formatter=>{?MODULE,self()}}),
#{type := OkType} = logger_std_h:info(?MODULE),
- logger:info(M1=?msg,?domain),
+ logger:notice(M1=?msg,?domain),
?check(M1),
B1 = ?bin(M1),
- try_read_file(Log, {ok,B1}, ?FILESYNC_REP_INT),
+ try_read_file(Log, {ok,B1}, filesync_rep_int()),
ok.
file_opts(cleanup, _Config) ->
logger:remove_handler(?MODULE).
-filesync(Config) ->
+sync(Config) ->
Dir = ?config(priv_dir,Config),
Log = filename:join(Dir, lists:concat([?FUNCTION_NAME,".log"])),
Type = {file,Log},
ok = logger:add_handler(?MODULE,
logger_std_h,
- #{logger_std_h => #{type => Type},
+ #{config => #{type => Type},
filter_default=>log,
filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
formatter=>{?MODULE,nl}}),
@@ -509,9 +539,9 @@ filesync(Config) ->
{logger_std_h, sync_dev},
{file,datasync}]),
- logger:info("first", ?domain),
+ logger:notice("first", ?domain),
%% wait for automatic filesync
- check_tracer(?FILESYNC_REP_INT*2),
+ check_tracer(filesync_rep_int()*2),
%% check that explicit filesync is only done once
start_tracer([{logger_std_h, write_to_dev, 5},
@@ -522,16 +552,16 @@ filesync(Config) ->
{file,datasync},
{no_more,500}
]),
- logger:info("second", ?domain),
- %% do explicit filesync
+ logger:notice("second", ?domain),
+ %% do explicit sync
logger_std_h:filesync(?MODULE),
- %% a second filesync should be ignored
+ %% a second sync should be ignored
logger_std_h:filesync(?MODULE),
check_tracer(100),
%% check that if there's no repeated filesync active,
%% a filesync is still performed when handler goes idle
- logger:set_handler_config(?MODULE, logger_std_h,
+ logger:set_handler_config(?MODULE, config,
#{filesync_repeat_interval => no_repeat}),
no_repeat = maps:get(filesync_repeat_interval, logger_std_h:info(?MODULE)),
%% The following timer is to make sure the time from last log
@@ -547,10 +577,10 @@ filesync(Config) ->
{logger_std_h, write_to_dev, <<"fourth\n">>},
{logger_std_h, sync_dev},
{file,datasync}]),
- logger:info("third", ?domain),
+ logger:notice("third", ?domain),
%% wait for automatic filesync
timer:sleep(?IDLE_DETECT_TIME_MSEC*2),
- logger:info("fourth", ?domain),
+ logger:notice("fourth", ?domain),
%% wait for automatic filesync
check_tracer(?IDLE_DETECT_TIME_MSEC*2),
@@ -562,15 +592,15 @@ filesync(Config) ->
start_tracer([{logger_std_h,handle_cast,2}],
[OneSync || _ <- lists:seq(1, 1 + trunc(WaitT/SyncInt))]),
- logger:set_handler_config(?MODULE, logger_std_h,
+ logger:set_handler_config(?MODULE, config,
#{filesync_repeat_interval => SyncInt}),
SyncInt = maps:get(filesync_repeat_interval, logger_std_h:info(?MODULE)),
timer:sleep(WaitT),
- logger:set_handler_config(?MODULE, logger_std_h,
+ logger:set_handler_config(?MODULE, config,
#{filesync_repeat_interval => no_repeat}),
check_tracer(100),
ok.
-filesync(cleanup, _Config) ->
+sync(cleanup, _Config) ->
dbg:stop_clear(),
logger:remove_handler(?MODULE).
@@ -578,7 +608,7 @@ write_failure(Config) ->
Dir = ?config(priv_dir, Config),
File = lists:concat([?MODULE,"_",?FUNCTION_NAME,".log"]),
Log = filename:join(Dir, File),
- Node = start_std_h_on_new_node(Config, ?FUNCTION_NAME, Log),
+ Node = start_std_h_on_new_node(Config, Log),
false = (undefined == rpc:call(Node, ets, whereis, [?TEST_HOOKS_TAB])),
rpc:call(Node, ets, insert, [?TEST_HOOKS_TAB,{tester,self()}]),
rpc:call(Node, ?MODULE, set_internal_log, [?MODULE,internal_log]),
@@ -587,7 +617,7 @@ write_failure(Config) ->
ok = log_on_remote_node(Node, "Logged1"),
rpc:call(Node, logger_std_h, filesync, [?STANDARD_HANDLER]),
?check_no_log,
- try_read_file(Log, {ok,<<"Logged1\n">>}, ?FILESYNC_REP_INT),
+ try_read_file(Log, {ok,<<"Logged1\n">>}, filesync_rep_int()),
rpc:call(Node, ?MODULE, set_result, [file_write,{error,terminated}]),
ok = log_on_remote_node(Node, "Cause simple error printout"),
@@ -605,7 +635,7 @@ write_failure(Config) ->
ok = log_on_remote_node(Node, "Logged2"),
rpc:call(Node, logger_std_h, filesync, [?STANDARD_HANDLER]),
?check_no_log,
- try_read_file(Log, {ok,<<"Logged1\nLogged2\n">>}, ?FILESYNC_REP_INT),
+ try_read_file(Log, {ok,<<"Logged1\nLogged2\n">>}, filesync_rep_int()),
ok.
write_failure(cleanup, _Config) ->
Nodes = nodes(),
@@ -615,7 +645,7 @@ sync_failure(Config) ->
Dir = ?config(priv_dir, Config),
File = lists:concat([?MODULE,"_",?FUNCTION_NAME,".log"]),
Log = filename:join(Dir, File),
- Node = start_std_h_on_new_node(Config, ?FUNCTION_NAME, Log),
+ Node = start_std_h_on_new_node(Config, Log),
false = (undefined == rpc:call(Node, ets, whereis, [?TEST_HOOKS_TAB])),
rpc:call(Node, ets, insert, [?TEST_HOOKS_TAB,{tester,self()}]),
rpc:call(Node, ?MODULE, set_internal_log, [?MODULE,internal_log]),
@@ -623,7 +653,7 @@ sync_failure(Config) ->
SyncInt = 500,
ok = rpc:call(Node, logger, set_handler_config,
- [?STANDARD_HANDLER, logger_std_h,
+ [?STANDARD_HANDLER, config,
#{filesync_repeat_interval => SyncInt}]),
Info = rpc:call(Node, logger_std_h, info, [?STANDARD_HANDLER]),
SyncInt = maps:get(filesync_repeat_interval, Info),
@@ -651,30 +681,21 @@ sync_failure(cleanup, _Config) ->
Nodes = nodes(),
[test_server:stop_node(Node) || Node <- Nodes].
-start_std_h_on_new_node(_Config, Func, Log) ->
- Pa = filename:dirname(code:which(?MODULE)),
- Dest =
- case os:type() of
- {win32,_} ->
- lists:concat([" {file,\\\"",Log,"\\\"}"]);
- _ ->
- lists:concat([" \'{file,\"",Log,"\"}\'"])
- end,
- Args = lists:concat([" -kernel ",logger_dest,Dest," -pa ",Pa]),
- Name = lists:concat([?MODULE,"_",Func]),
- ct:pal("Starting ~s with ~tp", [Name,Args]),
- {ok,Node} = test_server:start_node(Name, peer, [{args, Args}]),
- Pid = rpc:call(Node,erlang,whereis,[?STANDARD_HANDLER]),
- true = is_pid(Pid),
+start_std_h_on_new_node(Config, Log) ->
+ {ok,_,Node} =
+ logger_test_lib:setup(
+ Config,
+ [{logger,[{handler,default,logger_std_h,
+ #{ config => #{ type => {file,Log}}}}]}]),
ok = rpc:call(Node,logger,set_handler_config,[?STANDARD_HANDLER,formatter,
{?MODULE,nl}]),
Node.
%% functions for test hook macros to be called by rpc
-set_internal_log(Mod, Func) ->
- ?set_internal_log({Mod,Func}).
-set_result(Op, Result) ->
- ?set_result(Op, Result).
+set_internal_log(_Mod, _Func) ->
+ ?set_internal_log({_Mod,_Func}).
+set_result(_Op, _Result) ->
+ ?set_result(_Op, _Result).
set_defaults() ->
?set_defaults().
@@ -691,16 +712,16 @@ internal_log(Type, Term) ->
op_switch_to_sync_file(Config) ->
{Log,HConfig,StdHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ NumOfReqs = 500,
NewHConfig =
- HConfig#{logger_std_h => StdHConfig#{toggle_sync_qlen => 3,
- drop_new_reqs_qlen => 501,
- flush_reqs_qlen => 2000,
- enable_burst_limit => false}},
+ HConfig#{config => StdHConfig#{sync_mode_qlen => 2,
+ drop_mode_qlen => NumOfReqs+1,
+ flush_qlen => 2*NumOfReqs,
+ burst_limit_enable => false}},
ok = logger:set_handler_config(?MODULE, NewHConfig),
%% TRecvPid = start_op_trace(),
- NumOfReqs = 500,
- send_burst({n,NumOfReqs}, seq, {chars,79}, info),
- NumOfReqs = count_lines(Log),
+ send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
+ Lines = count_lines(Log),
%% true = analyse_trace(TRecvPid,
%% fun(Events) -> find_mode(async,Events) end),
%% true = analyse_trace(TRecvPid,
@@ -711,102 +732,141 @@ op_switch_to_sync_file(Config) ->
%% fun(Events) -> find_mode(drop,Events) end),
%% false = analyse_trace(TRecvPid,
%% fun(Events) -> find_mode(flush,Events) end),
- ok = file:delete(Log),
%% stop_op_trace(TRecvPid),
+ NumOfReqs = Lines,
+ ok = file_delete(Log),
ok.
op_switch_to_sync_file(cleanup, _Config) ->
ok = stop_handler(?MODULE).
op_switch_to_sync_tty(Config) ->
{HConfig,StdHConfig} = start_handler(?MODULE, standard_io, Config),
+ NumOfReqs = 500,
NewHConfig =
- HConfig#{logger_std_h => StdHConfig#{toggle_sync_qlen => 3,
- drop_new_reqs_qlen => 501,
- flush_reqs_qlen => 2000,
- enable_burst_limit => false}},
+ HConfig#{config => StdHConfig#{sync_mode_qlen => 3,
+ drop_mode_qlen => NumOfReqs+1,
+ flush_qlen => 2*NumOfReqs,
+ burst_limit_enable => false}},
ok = logger:set_handler_config(?MODULE, NewHConfig),
- NumOfReqs = 500,
- send_burst({n,NumOfReqs}, seq, {chars,79}, info),
+ send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
ok.
op_switch_to_sync_tty(cleanup, _Config) ->
ok = stop_handler(?MODULE).
+op_switch_to_drop_file() ->
+ [{timetrap,{seconds,180}}].
op_switch_to_drop_file(Config) ->
- {Log,HConfig,StdHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
-
- NewHConfig =
- HConfig#{logger_std_h => StdHConfig#{toggle_sync_qlen => 2,
- drop_new_reqs_qlen => 3,
- flush_reqs_qlen => 600,
- enable_burst_limit => false}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
- %% TRecvPid = start_op_trace(),
- NumOfReqs = 500,
- send_burst({n,NumOfReqs}, seq, {chars,79}, info),
- Logged = count_lines(Log),
- ct:pal("Number of messages dropped = ~w (~w)",
- [NumOfReqs-Logged,NumOfReqs]),
- true = (Logged < NumOfReqs),
- %% true = analyse_trace(TRecvPid,
- %% fun(Events) -> find_mode(async,Events) end),
- %% true = analyse_trace(TRecvPid,
- %% fun(Events) -> find_mode(drop,Events) end),
- %% false = analyse_trace(TRecvPid,
- %% fun(Events) -> find_mode(flush,Events) end),
- %% true = analyse_trace(TRecvPid,
- %% fun(Events) -> find_switch(async,drop,Events)
- %% orelse find_switch(sync,drop,Events)
- %% end),
- ok = file:delete(Log),
- %% stop_op_trace(TRecvPid),
- ok.
+ Test =
+ fun() ->
+ {Log,HConfig,StdHConfig} =
+ start_handler(?MODULE, ?FUNCTION_NAME, Config),
+ NumOfReqs = 300,
+ Procs = 2,
+ Bursts = 10,
+ NewHConfig =
+ HConfig#{config =>
+ StdHConfig#{sync_mode_qlen => 1,
+ drop_mode_qlen => 2,
+ flush_qlen =>
+ Procs*NumOfReqs*Bursts,
+ burst_limit_enable => false}},
+ ok = logger:set_handler_config(?MODULE, NewHConfig),
+ %% It sometimes happens that the handler gets the
+ %% requests in a slow enough pace so that dropping
+ %% never occurs. Therefore, lets generate a number of
+ %% bursts to increase the chance of message buildup.
+ [send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice) ||
+ _ <- lists:seq(1, Bursts)],
+ Logged = count_lines(Log),
+ ok = stop_handler(?MODULE),
+ ct:pal("Number of messages dropped = ~w (~w)",
+ [Procs*NumOfReqs*Bursts-Logged,Procs*NumOfReqs*Bursts]),
+ true = (Logged < (Procs*NumOfReqs*Bursts)),
+ true = (Logged > 0),
+ _ = file_delete(Log),
+ ok
+ end,
+ %% As it's tricky to get the timing right in only one go, we perform the
+ %% test repeatedly, hoping that will generate a successful result.
+ case repeat_until_ok(Test, 10) of
+ {ok,{Failures,_Result}} ->
+ ct:log("Failed ~w times before success!", [Failures]);
+ {fails,Reason} ->
+ ct:fail(Reason)
+ end.
op_switch_to_drop_file(cleanup, _Config) ->
- ok = stop_handler(?MODULE).
+ _ = stop_handler(?MODULE).
op_switch_to_drop_tty(Config) ->
{HConfig,StdHConfig} = start_handler(?MODULE, standard_io, Config),
+ NumOfReqs = 300,
+ Procs = 2,
NewHConfig =
- HConfig#{logger_std_h => StdHConfig#{toggle_sync_qlen => 2,
- drop_new_reqs_qlen => 3,
- flush_reqs_qlen => 600,
- enable_burst_limit => false}},
+ HConfig#{config => StdHConfig#{sync_mode_qlen => 1,
+ drop_mode_qlen => 2,
+ flush_qlen =>
+ Procs*NumOfReqs+1,
+ burst_limit_enable => false}},
ok = logger:set_handler_config(?MODULE, NewHConfig),
- NumOfReqs = 500,
- send_burst({n,NumOfReqs}, seq, {chars,79}, info),
+ send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice),
ok.
op_switch_to_drop_tty(cleanup, _Config) ->
ok = stop_handler(?MODULE).
op_switch_to_flush_file() ->
- [{timetrap,{minutes,3}}].
+ [{timetrap,{minutes,5}}].
op_switch_to_flush_file(Config) ->
- {Log,HConfig,StdHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
-
- %% it's important that both async and sync requests have been queued
- %% when the flush happens (verify with coverage of flush_log_requests/2)
-
- NewHConfig =
- HConfig#{logger_std_h => StdHConfig#{toggle_sync_qlen => 2,
- drop_new_reqs_qlen => 99,
- flush_reqs_qlen => 100,
- enable_burst_limit => false}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
- NumOfReqs = 10000,
- Procs = 100,
- send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, info),
- Logged = count_lines(Log),
- ct:pal("Number of messages flushed/dropped = ~w (~w)",
- [(NumOfReqs*Procs)-Logged,NumOfReqs*Procs]),
- true = (Logged < (NumOfReqs*Procs)),
-
- %%! --- Thu Apr 12 13:46:00 2018 --- peppe was here!
- %%! TODO: Verify that handler has switched to flush mode
-
- ok = file:delete(Log),
- ok.
+ Test =
+ fun() ->
+ {Log,HConfig,StdHConfig} =
+ start_handler(?MODULE, ?FUNCTION_NAME, Config),
+
+ %% NOTE: it's important that both async and sync
+ %% requests have been queued when the flush happens
+ %% (verify with coverage of flush_log_requests/2)
+
+ NewHConfig =
+ HConfig#{config =>
+ StdHConfig#{sync_mode_qlen => 2,
+ %% disable drop mode
+ drop_mode_qlen => 300,
+ flush_qlen => 300,
+ burst_limit_enable => false}},
+ ok = logger:set_handler_config(?MODULE, NewHConfig),
+ NumOfReqs = 1500,
+ Procs = 10,
+ Bursts = 10,
+ %% It sometimes happens that the handler either gets
+ %% the requests in a slow enough pace so that flushing
+ %% never occurs, or it gets all messages at once,
+ %% causing all messages to get flushed (no dropping of
+ %% sync messages gets tested). Therefore, lets
+ %% generate a number of bursts to increase the chance
+ %% of message buildup in some random fashion.
+ [send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice) ||
+ _ <- lists:seq(1,Bursts)],
+ Logged = count_lines(Log),
+ ok = stop_handler(?MODULE),
+ ct:pal("Number of messages flushed/dropped = ~w (~w)",
+ [NumOfReqs*Procs*Bursts-Logged,NumOfReqs*Procs*Bursts]),
+ true = (Logged < (NumOfReqs*Procs*Bursts)),
+ true = (Logged > 0),
+ _ = file_delete(Log),
+ ok
+ end,
+ %% As it's tricky to get the timing right in only one go, we perform the
+ %% test repeatedly, hoping that will generate a successful result.
+ case repeat_until_ok(Test, 10) of
+ {ok,{Failures,_Result}} ->
+ ct:log("Failed ~w times before success!", [Failures]);
+ {fails,Reason} ->
+ ct:fail(Reason)
+ end.
op_switch_to_flush_file(cleanup, _Config) ->
- ok = stop_handler(?MODULE).
+ _ = stop_handler(?MODULE).
+op_switch_to_flush_tty() ->
+ [{timetrap,{minutes,5}}].
op_switch_to_flush_tty(Config) ->
{HConfig,StdHConfig} = start_handler(?MODULE, standard_io, Config),
@@ -814,14 +874,15 @@ op_switch_to_flush_tty(Config) ->
%% when the flush happens (verify with coverage of flush_log_requests/2)
NewHConfig =
- HConfig#{logger_std_h => StdHConfig#{toggle_sync_qlen => 2,
- drop_new_reqs_qlen => 99,
- flush_reqs_qlen => 100,
- enable_burst_limit => false}},
+ HConfig#{config => StdHConfig#{sync_mode_qlen => 2,
+ %% disable drop mode
+ drop_mode_qlen => 100,
+ flush_qlen => 100,
+ burst_limit_enable => false}},
ok = logger:set_handler_config(?MODULE, NewHConfig),
- NumOfReqs = 10000,
- Procs = 10,
- send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, info),
+ NumOfReqs = 1000,
+ Procs = 100,
+ send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice),
ok.
op_switch_to_flush_tty(cleanup, _Config) ->
ok = stop_handler(?MODULE).
@@ -829,18 +890,19 @@ op_switch_to_flush_tty(cleanup, _Config) ->
limit_burst_disabled(Config) ->
{Log,HConfig,StdHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
NewHConfig =
- HConfig#{logger_std_h => StdHConfig#{enable_burst_limit => false,
- burst_limit_size => 10,
- burst_window_time => 2000,
- drop_new_reqs_qlen => 200,
- flush_reqs_qlen => 300}},
+ HConfig#{config => StdHConfig#{burst_limit_enable => false,
+ burst_limit_max_count => 10,
+ burst_limit_window_time => 2000,
+ drop_mode_qlen => 200,
+ flush_qlen => 300}},
ok = logger:set_handler_config(?MODULE, NewHConfig),
NumOfReqs = 100,
- send_burst({n,NumOfReqs}, seq, {chars,79}, info),
+ send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
Logged = count_lines(Log),
ct:pal("Number of messages logged = ~w", [Logged]),
- ok = file:delete(Log),
- NumOfReqs = Logged.
+ NumOfReqs = Logged,
+ ok = file_delete(Log),
+ ok.
limit_burst_disabled(cleanup, _Config) ->
ok = stop_handler(?MODULE).
@@ -848,18 +910,19 @@ limit_burst_enabled_one(Config) ->
{Log,HConfig,StdHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
ReqLimit = 10,
NewHConfig =
- HConfig#{logger_std_h => StdHConfig#{enable_burst_limit => true,
- burst_limit_size => ReqLimit,
- burst_window_time => 2000,
- drop_new_reqs_qlen => 200,
- flush_reqs_qlen => 300}},
+ HConfig#{config => StdHConfig#{burst_limit_enable => true,
+ burst_limit_max_count => ReqLimit,
+ burst_limit_window_time => 2000,
+ drop_mode_qlen => 200,
+ flush_qlen => 300}},
ok = logger:set_handler_config(?MODULE, NewHConfig),
NumOfReqs = 100,
- send_burst({n,NumOfReqs}, seq, {chars,79}, info),
+ send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
Logged = count_lines(Log),
ct:pal("Number of messages logged = ~w", [Logged]),
- ok = file:delete(Log),
- ReqLimit = Logged.
+ ReqLimit = Logged,
+ ok = file_delete(Log),
+ ok.
limit_burst_enabled_one(cleanup, _Config) ->
ok = stop_handler(?MODULE).
@@ -868,57 +931,58 @@ limit_burst_enabled_period(Config) ->
ReqLimit = 10,
BurstTWin = 1000,
NewHConfig =
- HConfig#{logger_std_h => StdHConfig#{enable_burst_limit => true,
- burst_limit_size => ReqLimit,
- burst_window_time => BurstTWin,
- drop_new_reqs_qlen => 20000,
- flush_reqs_qlen => 20001}},
+ HConfig#{config => StdHConfig#{burst_limit_enable => true,
+ burst_limit_max_count => ReqLimit,
+ burst_limit_window_time => BurstTWin,
+ drop_mode_qlen => 20000,
+ flush_qlen => 20001}},
ok = logger:set_handler_config(?MODULE, NewHConfig),
Windows = 3,
- Sent = send_burst({t,BurstTWin*Windows}, seq, {chars,79}, info),
+ Sent = send_burst({t,BurstTWin*Windows}, seq, {chars,79}, notice),
Logged = count_lines(Log),
ct:pal("Number of messages sent = ~w~nNumber of messages logged = ~w",
[Sent,Logged]),
- ok = file:delete(Log),
true = (Logged > (ReqLimit*Windows)) andalso
- (Logged < (ReqLimit*(Windows+2))).
+ (Logged < (ReqLimit*(Windows+2))),
+ ok = file_delete(Log),
+ ok.
limit_burst_enabled_period(cleanup, _Config) ->
ok = stop_handler(?MODULE).
kill_disabled(Config) ->
{Log,HConfig,StdHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
NewHConfig =
- HConfig#{logger_std_h=>StdHConfig#{enable_kill_overloaded=>false,
- handler_overloaded_qlen=>10,
- handler_overloaded_mem=>100}},
+ HConfig#{config=>StdHConfig#{overload_kill_enable=>false,
+ overload_kill_qlen=>10,
+ overload_kill_mem_size=>100}},
ok = logger:set_handler_config(?MODULE, NewHConfig),
NumOfReqs = 100,
- send_burst({n,NumOfReqs}, seq, {chars,79}, info),
+ send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
Logged = count_lines(Log),
ct:pal("Number of messages logged = ~w", [Logged]),
- ok = file:delete(Log),
- true = is_pid(whereis(?MODULE)),
+ ok = file_delete(Log),
+ true = is_pid(whereis(h_proc_name())),
ok.
kill_disabled(cleanup, _Config) ->
ok = stop_handler(?MODULE).
qlen_kill_new(Config) ->
{Log,HConfig,StdHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
- Pid0 = whereis(?MODULE),
+ Pid0 = whereis(h_proc_name()),
{_,Mem0} = process_info(Pid0, memory),
- RestartAfter = 2000,
+ RestartAfter = ?OVERLOAD_KILL_RESTART_AFTER,
NewHConfig =
- HConfig#{logger_std_h=>StdHConfig#{enable_kill_overloaded=>true,
- handler_overloaded_qlen=>10,
- handler_overloaded_mem=>Mem0+50000,
- handler_restart_after=>RestartAfter}},
+ HConfig#{config=>StdHConfig#{overload_kill_enable=>true,
+ overload_kill_qlen=>10,
+ overload_kill_mem_size=>Mem0+50000,
+ overload_kill_restart_after=>RestartAfter}},
ok = logger:set_handler_config(?MODULE, NewHConfig),
MRef = erlang:monitor(process, Pid0),
NumOfReqs = 100,
- Procs = 2,
- send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, info),
- %% send_burst({n,NumOfReqs}, seq, {chars,79}, info),
+ Procs = 4,
+ send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice),
+ %% send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
receive
{'DOWN', MRef, _, _, Info} ->
case Info of
@@ -927,8 +991,8 @@ qlen_kill_new(Config) ->
killed ->
ct:pal("Slow shutdown, handler process was killed!", [])
end,
- timer:sleep(RestartAfter + 1000),
- true = is_pid(whereis(?MODULE)),
+ file_delete(Log),
+ {ok,_} = wait_for_process_up(RestartAfter * 3),
ok
after
5000 ->
@@ -941,35 +1005,35 @@ qlen_kill_new(cleanup, _Config) ->
%% choke the standard handler on remote node to verify the termination
%% works as expected
-qlen_kill_std(Config) ->
+qlen_kill_std(_Config) ->
%%! HERE
%% Dir = ?config(priv_dir, Config),
%% File = lists:concat([?MODULE,"_",?FUNCTION_NAME,".log"]),
%% Log = filename:join(Dir, File),
%% Node = start_std_h_on_new_node(Config, ?FUNCTION_NAME, Log),
%% ok = rpc:call(Node, logger, set_handler_config,
- %% [?STANDARD_HANDLER, logger_std_h,
- %% #{enable_kill_overloaded=>true,
- %% handler_overloaded_qlen=>10,
- %% handler_overloaded_mem=>100000}]),
+ %% [?STANDARD_HANDLER, config,
+ %% #{overload_kill_enable=>true,
+ %% overload_kill_qlen=>10,
+ %% overload_kill_mem_size=>100000}]),
{skip,"Not done yet"}.
mem_kill_new(Config) ->
{Log,HConfig,StdHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
- Pid0 = whereis(?MODULE),
+ Pid0 = whereis(h_proc_name()),
{_,Mem0} = process_info(Pid0, memory),
- RestartAfter = 2000,
+ RestartAfter = ?OVERLOAD_KILL_RESTART_AFTER,
NewHConfig =
- HConfig#{logger_std_h=>StdHConfig#{enable_kill_overloaded=>true,
- handler_overloaded_qlen=>50000,
- handler_overloaded_mem=>Mem0+500,
- handler_restart_after=>RestartAfter}},
+ HConfig#{config=>StdHConfig#{overload_kill_enable=>true,
+ overload_kill_qlen=>50000,
+ overload_kill_mem_size=>Mem0+500,
+ overload_kill_restart_after=>RestartAfter}},
ok = logger:set_handler_config(?MODULE, NewHConfig),
MRef = erlang:monitor(process, Pid0),
NumOfReqs = 100,
- Procs = 2,
- send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, info),
- %% send_burst({n,NumOfReqs}, seq, {chars,79}, info),
+ Procs = 4,
+ send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice),
+ %% send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
receive
{'DOWN', MRef, _, _, Info} ->
case Info of
@@ -978,8 +1042,8 @@ mem_kill_new(Config) ->
killed ->
ct:pal("Slow shutdown, handler process was killed!", [])
end,
- timer:sleep(RestartAfter * 2),
- true = is_pid(whereis(?MODULE)),
+ file_delete(Log),
+ {ok,_} = wait_for_process_up(RestartAfter * 3),
ok
after
5000 ->
@@ -992,56 +1056,61 @@ mem_kill_new(cleanup, _Config) ->
%% choke the standard handler on remote node to verify the termination
%% works as expected
-mem_kill_std(Config) ->
+mem_kill_std(_Config) ->
{skip,"Not done yet"}.
+restart_after() ->
+ [{timetrap,{minutes,2}}].
restart_after(Config) ->
{Log,HConfig,StdHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
NewHConfig1 =
- HConfig#{logger_std_h=>StdHConfig#{enable_kill_overloaded=>true,
- handler_overloaded_qlen=>10,
- handler_restart_after=>never}},
+ HConfig#{config=>StdHConfig#{overload_kill_enable=>true,
+ overload_kill_qlen=>10,
+ overload_kill_restart_after=>infinity}},
ok = logger:set_handler_config(?MODULE, NewHConfig1),
- MRef1 = erlang:monitor(process, whereis(?MODULE)),
+ MRef1 = erlang:monitor(process, whereis(h_proc_name())),
%% kill handler
- send_burst({n,100}, {spawn,2,0}, {chars,79}, info),
+ send_burst({n,100}, {spawn,4,0}, {chars,79}, notice),
receive
- {'DOWN', MRef1, _, _, _Info1} ->
- timer:sleep(?HANDLER_RESTART_AFTER + 1000),
- undefined = whereis(?MODULE),
+ {'DOWN', MRef1, _, _, _Reason1} ->
+ file_delete(Log),
+ error = wait_for_process_up(?OVERLOAD_KILL_RESTART_AFTER * 3),
ok
after
5000 ->
+ Info1 = logger_std_h:info(?MODULE),
+ ct:pal("Handler state = ~p", [Info1]),
ct:fail("Handler not dead! It should not have survived this!")
end,
{Log,_,_} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
- RestartAfter = 2000,
+ RestartAfter = ?OVERLOAD_KILL_RESTART_AFTER,
NewHConfig2 =
- HConfig#{logger_std_h=>StdHConfig#{enable_kill_overloaded=>true,
- handler_overloaded_qlen=>10,
- handler_restart_after=>RestartAfter}},
+ HConfig#{config=>StdHConfig#{overload_kill_enable=>true,
+ overload_kill_qlen=>10,
+ overload_kill_restart_after=>RestartAfter}},
ok = logger:set_handler_config(?MODULE, NewHConfig2),
- Pid0 = whereis(?MODULE),
+ Pid0 = whereis(h_proc_name()),
MRef2 = erlang:monitor(process, Pid0),
%% kill handler
- send_burst({n,100}, {spawn,2,0}, {chars,79}, info),
+ send_burst({n,100}, {spawn,4,0}, {chars,79}, notice),
receive
- {'DOWN', MRef2, _, _, _Info2} ->
- timer:sleep(RestartAfter + 1000),
- Pid1 = whereis(?MODULE),
- true = is_pid(Pid1),
+ {'DOWN', MRef2, _, _, _Reason2} ->
+ file_delete(Log),
+ {ok,Pid1} = wait_for_process_up(RestartAfter * 3),
false = (Pid1 == Pid0),
ok
after
5000 ->
+ Info2 = logger_std_h:info(?MODULE),
+ ct:pal("Handler state = ~p", [Info2]),
ct:fail("Handler not dead! It should not have survived this!")
end,
ok.
restart_after(cleanup, _Config) ->
ok = stop_handler(?MODULE).
-%% send handler requests (filesync, info, reset, change_config)
+%% send handler requests (sync, info, reset, change_config)
%% during high load to verify that sync, dropping and flushing is
%% handled correctly.
handler_requests_under_load() ->
@@ -1050,17 +1119,17 @@ handler_requests_under_load(Config) ->
{Log,HConfig,StdHConfig} =
start_handler(?MODULE, ?FUNCTION_NAME, Config),
NewHConfig =
- HConfig#{logger_std_h => StdHConfig#{toggle_sync_qlen => 2,
- drop_new_reqs_qlen => 1000,
- flush_reqs_qlen => 2000,
- enable_burst_limit => false}},
+ HConfig#{config => StdHConfig#{sync_mode_qlen => 2,
+ drop_mode_qlen => 1000,
+ flush_qlen => 2000,
+ burst_limit_enable => false}},
ok = logger:set_handler_config(?MODULE, NewHConfig),
Pid = spawn_link(fun() -> send_requests(?MODULE, 1, [{filesync,[]},
{info,[]},
{reset,[]},
{change_config,[]}])
end),
- Sent = send_burst({t,10000}, seq, {chars,79}, info),
+ Sent = send_burst({t,10000}, seq, {chars,79}, notice),
Pid ! {self(),finish},
ReqResult = receive {Pid,Result} -> Result end,
Logged = count_lines(Log),
@@ -1073,8 +1142,8 @@ handler_requests_under_load(Config) ->
Errors = [{Req,FindError(Res)} || {Req,Res} <- ReqResult],
NoOfReqs = lists:foldl(fun({_,Res}, N) -> N + length(Res) end, 0, ReqResult),
ct:pal("~w requests made. Errors: ~n~p", [NoOfReqs,Errors]),
- ok = file:delete(Log).
-handler_requests_under_load(cleanup, Config) ->
+ ok = file_delete(Log).
+handler_requests_under_load(cleanup, _Config) ->
ok = stop_handler(?MODULE).
send_requests(HName, TO, Reqs = [{Req,Res}|Rs]) ->
@@ -1086,8 +1155,8 @@ send_requests(HName, TO, Reqs = [{Req,Res}|Rs]) ->
Result =
case Req of
change_config ->
- logger:set_handler_config(HName, logger_std_h,
- #{enable_kill_overloaded =>
+ logger:set_handler_config(HName, config,
+ #{overload_kill_enable =>
false});
Func ->
logger_std_h:Func(HName)
@@ -1102,12 +1171,11 @@ start_handler(Name, TTY, Config) when TTY == standard_io;
TTY == standard_error->
ok = logger:add_handler(Name,
logger_std_h,
- #{logger_std_h => #{type => TTY},
+ #{config => #{type => TTY},
filter_default=>log,
filters=>?DEFAULT_HANDLER_FILTERS([Name]),
formatter=>{?MODULE,op}}),
- {ok,{_,HConfig = #{logger_std_h := StdHConfig}}} =
- logger:get_handler_config(Name),
+ {ok,HConfig = #{config := StdHConfig}} = logger:get_handler_config(Name),
{HConfig,StdHConfig};
start_handler(Name, FuncName, Config) ->
@@ -1115,19 +1183,20 @@ start_handler(Name, FuncName, Config) ->
Log = filename:join(Dir, lists:concat([FuncName,".log"])),
ct:pal("Logging to ~tp", [Log]),
Type = {file,Log},
+ _ = file_delete(Log),
ok = logger:add_handler(Name,
logger_std_h,
- #{logger_std_h => #{type => Type},
+ #{config => #{type => Type},
filter_default=>log,
filters=>?DEFAULT_HANDLER_FILTERS([Name]),
formatter=>{?MODULE,op}}),
- {ok,{_,HConfig = #{logger_std_h := StdHConfig}}} =
- logger:get_handler_config(Name),
+ {ok,HConfig = #{config := StdHConfig}} = logger:get_handler_config(Name),
{Log,HConfig,StdHConfig}.
stop_handler(Name) ->
- ok = logger:remove_handler(Name),
- ct:pal("Handler ~p stopped!", [Name]).
+ R = logger:remove_handler(Name),
+ ct:pal("Handler ~p stopped! Result: ~p", [Name,R]),
+ R.
count_lines(File) ->
wait_until_written(File, -1),
@@ -1139,27 +1208,31 @@ wait_until_written(File, Sz) ->
{ok,#file_info{size = Sz}} ->
timer:sleep(1000),
case file:read_file_info(File) of
- {ok,#file_info{size = Sz1}} ->
+ {ok,#file_info{size = Sz}} ->
ok;
- {ok,#file_info{size = Sz2}} ->
- wait_until_written(File, Sz2)
+ {ok,#file_info{size = Sz1}} ->
+ wait_until_written(File, Sz1)
end;
{ok,#file_info{size = Sz1}} ->
wait_until_written(File, Sz1)
end.
count_lines1(File) ->
- Counter = fun Cnt(Dev,LC) ->
- case file:read_line(Dev) of
- eof -> LC;
- _ -> Cnt(Dev,LC+1)
- end
- end,
{_,Dev} = file:open(File, [read]),
- Lines = Counter(Dev, 0),
+ Lines = count_lines2(Dev, 0),
file:close(Dev),
Lines.
+count_lines2(Dev, LC) ->
+ case file:read_line(Dev) of
+ {ok,"Handler logger_std_h_SUITE " ++_} ->
+ %% Not counting handler info
+ count_lines2(Dev,LC);
+ {ok,_} ->
+ count_lines2(Dev,LC+1);
+ eof -> LC
+ end.
+
send_burst(NorT, Type, {chars,Sz}, Class) ->
Text = [34 + rand:uniform(126-34) || _ <- lists:seq(1,Sz)],
case NorT of
@@ -1181,12 +1254,9 @@ send_n_burst(N, seq, Text, Class) ->
send_n_burst(N-1, seq, Text, Class);
send_n_burst(N, {spawn,Ps,TO}, Text, Class) ->
ct:pal("~w processes each sending ~w messages", [Ps,N]),
- PerProc = fun() ->
- send_n_burst(N, seq, Text, Class)
- end,
MRefs = [begin if TO == 0 -> ok; true -> timer:sleep(TO) end,
- monitor(process,spawn_link(PerProc)) end ||
- _ <- lists:seq(1,Ps)],
+ monitor(process,spawn_link(per_proc_fun(N,Text,Class,X)))
+ end || X <- lists:seq(1,Ps)],
lists:foreach(fun(MRef) ->
receive
{'DOWN', MRef, _, _, _} ->
@@ -1205,6 +1275,16 @@ send_t_burst(T0, T, Text, Class, N) ->
send_t_burst(T0, T, Text, Class, N+1)
end.
+per_proc_fun(N,Text,Class,X) when X rem 2 == 0 ->
+ fun() ->
+ process_flag(priority,high),
+ send_n_burst(N, seq, Text, Class)
+ end;
+per_proc_fun(N,Text,Class,_) ->
+ fun() ->
+ send_n_burst(N, seq, Text, Class)
+ end.
+
%%%-----------------------------------------------------------------
%%% Formatter callback
%%% Using this to send the formatted string back to the test case
@@ -1228,9 +1308,11 @@ format(#{msg:={report,#{label:={gen_server,terminate}}}},op) ->
"";
format(#{msg:={report,#{label:={proc_lib,crash}}}},op) ->
"";
-format(#{msg:={F,A}},Pid) when is_list(F), is_list(A) ->
+format(#{msg:={F,A}},OpOrPid) when is_list(F), is_list(A) ->
String = lists:flatten(io_lib:format(F,A)),
- Pid ! {log,String},
+ if is_pid(OpOrPid) -> OpOrPid ! {log,String};
+ true -> ok
+ end,
String++"\n";
format(#{msg:={string,String0}},Pid) ->
String = unicode:characters_to_list(String0),
@@ -1239,21 +1321,21 @@ format(#{msg:={string,String0}},Pid) ->
add_remove_instance_nofile(Type) ->
ok = logger:add_handler(?MODULE,logger_std_h,
- #{logger_std_h => #{type => Type},
+ #{config => #{type => Type},
filter_default=>stop,
filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
formatter=>{?MODULE,self()}}),
- Pid = whereis(?MODULE),
+ Pid = whereis(h_proc_name()),
true = is_pid(Pid),
group_leader(group_leader(),Pid), % to get printouts in test log
- logger:info(M1=?msg,?domain),
+ logger:notice(M1=?msg,?domain),
?check(M1),
- %% check that filesync doesn't do damage even if not relevant
+ %% check that sync doesn't do damage even if not relevant
ok = logger_std_h:filesync(?MODULE),
ok = logger:remove_handler(?MODULE),
timer:sleep(500),
- undefined = whereis(?MODULE),
- logger:info(?msg,?domain),
+ undefined = whereis(h_proc_name()),
+ logger:notice(?msg,?domain),
?check_no_log,
ok.
@@ -1299,6 +1381,30 @@ try_match_file(_,Pattern,_,Incorrect) ->
[Pattern,Incorrect]),
erlang:error({error,not_matching_pattern,Pattern,Incorrect}).
+repeat_until_ok(Fun, N) ->
+ repeat_until_ok(Fun, 0, N, undefined).
+
+repeat_until_ok(_Fun, Stop, Stop, Reason) ->
+ {fails,Reason};
+
+repeat_until_ok(Fun, C, Stop, FirstReason) ->
+ if C > 0 -> timer:sleep(5000);
+ true -> ok
+ end,
+ try Fun() of
+ Result ->
+ {ok,{C,Result}}
+ catch
+ _:Reason:Stack ->
+ ct:pal("Test fails: ~p (~p)~n", [Reason,hd(Stack)]),
+ if FirstReason == undefined ->
+ repeat_until_ok(Fun, C+1, Stop, {Reason,Stack});
+ true ->
+ repeat_until_ok(Fun, C+1, Stop, FirstReason)
+ end
+ end.
+
+
%%%-----------------------------------------------------------------
%%%
start_op_trace() ->
@@ -1312,7 +1418,7 @@ start_op_trace() ->
TRecvPid = spawn_link(fun() -> trace_receiver(5000) end),
{ok,_} = dbg:tracer(process, {TraceFun, TRecvPid}),
- {ok,_} = dbg:p(whereis(?MODULE), [c]),
+ {ok,_} = dbg:p(whereis(h_proc_name()), [c]),
{ok,_} = dbg:p(self(), [c]),
MS1 = dbg:fun2ms(fun([_]) -> return_trace() end),
@@ -1339,17 +1445,17 @@ find_mode(flush, Events) ->
find_mode(Mode, Events) ->
lists:keymember([{mode,Mode}], 3, Events).
-find_switch(From, To, Events) ->
- try lists:foldl(fun({trace_return,check_load,{To,_,_,_}},
- {trace_call,check_load,[#{mode := From}]}) ->
- throw(match);
- (Event, _) ->
- Event
- end, undefined, Events) of
- _ -> false
- catch
- throw:match -> true
- end.
+%% find_switch(_From, To, Events) ->
+%% try lists:foldl(fun({trace_return,check_load,{To,_,_,_}},
+%% {trace_call,check_load,[#{mode := From}]}) ->
+%% throw(match);
+%% (Event, _) ->
+%% Event
+%% end, undefined, Events) of
+%% _ -> false
+%% catch
+%% throw:match -> true
+%% end.
analyse_trace(TRecvPid, TestFun) ->
TRecvPid ! {test,self(),TestFun},
@@ -1392,7 +1498,7 @@ start_tracer(Trace,Expected) ->
Pid = self(),
FileCtrlPid = maps:get(file_ctrl_pid, logger_std_h:info(?MODULE)),
dbg:tracer(process,{fun tracer/2,{Pid,Expected}}),
- dbg:p(whereis(?MODULE),[c]),
+ dbg:p(whereis(h_proc_name()),[c]),
dbg:p(FileCtrlPid,[c]),
tpl(Trace),
ok.
@@ -1411,7 +1517,7 @@ tpl([{M,F,A}|Trace]) ->
tpl([]) ->
ok.
-tracer({trace,_,call,{logger_std_h,handle_cast,[{Op,_}|_]}},
+tracer({trace,_,call,{logger_std_h,handle_cast,[Op|_]}},
{Pid,[{Mod,Func,Op}|Expected]}) ->
maybe_tracer_done(Pid,Expected,{Mod,Func,Op});
tracer({trace,_,call,{Mod=logger_std_h,Func=write_to_dev,[_,Data,_,_,_]}},
@@ -1451,3 +1557,51 @@ check_tracer(T,TimeoutFun) ->
dbg:stop_clear(),
TimeoutFun()
end.
+
+escape([$+|Rest]) ->
+ [$\\,$+|escape(Rest)];
+escape([H|T]) ->
+ [H|escape(T)];
+escape([]) ->
+ [].
+
+h_proc_name() ->
+ h_proc_name(?MODULE).
+h_proc_name(Name) ->
+ ?name_to_reg_name(logger_std_h,Name).
+
+wait_for_process_up(T) ->
+ wait_for_process_up(?MODULE, h_proc_name(), T).
+
+wait_for_process_up(Name, RegName, T) ->
+ N = (T div 500) + 1,
+ wait_for_process_up1(Name, RegName, N).
+
+wait_for_process_up1(_Name, _RegName, 0) ->
+ error;
+wait_for_process_up1(Name, RegName, N) ->
+ timer:sleep(500),
+ case whereis(RegName) of
+ Pid when is_pid(Pid) ->
+ case logger:get_handler_config(Name) of
+ {ok,_} ->
+ %% ct:pal("Process ~p up (~p tries left)",[Name,N]),
+ {ok,Pid};
+ _ ->
+ wait_for_process_up1(Name, RegName, N-1)
+ end;
+ undefined ->
+ %% ct:pal("Waiting for process ~p (~p tries left)",[Name,N]),
+ wait_for_process_up1(Name, RegName, N-1)
+ end.
+
+filesync_rep_int() ->
+ case (fun() -> is_atom(?FILESYNC_REPEAT_INTERVAL) end)() of
+ true -> 5500;
+ false -> ?FILESYNC_REPEAT_INTERVAL + 500
+ end.
+
+
+file_delete(Log) ->
+ file:delete(Log).
+
diff --git a/lib/kernel/test/logger_test_lib.erl b/lib/kernel/test/logger_test_lib.erl
new file mode 100644
index 0000000000..81eb9ce5eb
--- /dev/null
+++ b/lib/kernel/test/logger_test_lib.erl
@@ -0,0 +1,82 @@
+%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% 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(logger_test_lib).
+
+-include_lib("kernel/src/logger_internal.hrl").
+
+-export([setup/2, log/3, sync_and_read/3]).
+
+-export([init/2,
+ pre_init_per_suite/3, pre_init_per_testcase/4,
+ post_end_per_testcase/5, post_end_per_suite/3]).
+
+setup(Config,Vars) ->
+ FuncStr = lists:concat([proplists:get_value(suite, Config), "_",
+ proplists:get_value(tc, Config)]),
+ ConfigFileName = filename:join(proplists:get_value(priv_dir, Config), FuncStr),
+ file:write_file(ConfigFileName ++ ".config", io_lib:format("[{kernel, ~p}].",[Vars])),
+ case test_server:start_node(proplists:get_value(tc, Config), slave,
+ [{args, ["-pa ",filename:dirname(code:which(?MODULE)),
+ " -boot start_sasl -kernel start_timer true "
+ "-config ",ConfigFileName]}]) of
+ {ok, Node} ->
+ L = rpc:call(Node, logger, get_config, []),
+ ct:log("~p",[L]),
+ {ok, L, Node};
+ {error, Reason} ->
+ ct:log("Failed to start node: ~p",[Reason]),
+ error
+ end.
+
+log(Node, F, A) ->
+ log(Node, logger, F, A).
+log(Node, M, F, A) ->
+ MD = #{ gl => rpc:call(Node, erlang, whereis, [logger]) },
+ rpc:call(Node, M, F, A ++ [MD]).
+
+sync_and_read(Node,disk_log,Log) ->
+ rpc:call(Node,logger_disk_log_h,filesync,[?STANDARD_HANDLER]),
+ file:read_file(Log ++ ".1");
+sync_and_read(Node, file,Log) ->
+ ok = rpc:call(Node,logger_std_h,filesync,[?STANDARD_HANDLER]),
+ file:read_file(Log).
+
+
+init(_, _) ->
+ {ok, []}.
+
+pre_init_per_suite(_Suite, Config, State) ->
+ {[{nodes, nodes()} | Config], State}.
+
+pre_init_per_testcase(Suite, TC, Config, State) ->
+ cleanup(Config),
+ {[{suite, Suite}, {tc, TC} | Config], State}.
+
+post_end_per_testcase(_, _TC, Config, Res, State) ->
+ cleanup(Config),
+ {Res, State}.
+
+post_end_per_suite(_, Config, State) ->
+ cleanup(Config),
+ {Config, State}.
+
+cleanup(Config) ->
+ [test_server:stop_node(N) || N <- nodes(),
+ not lists:member(N, proplists:get_value(nodes, Config))].
diff --git a/lib/kernel/test/os_SUITE.erl b/lib/kernel/test/os_SUITE.erl
index 591fbb2125..710b9b115c 100644
--- a/lib/kernel/test/os_SUITE.erl
+++ b/lib/kernel/test/os_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -227,8 +227,8 @@ find_executable(Config) when is_list(Config) ->
DataDir = proplists:get_value(data_dir, Config),
%% Smoke test.
- case lib:progname() of
- erl ->
+ case ct:get_progname() of
+ "erl" ->
ErlPath = os:find_executable("erl"),
true = is_list(ErlPath),
true = filelib:is_regular(ErlPath);
@@ -388,7 +388,7 @@ comp(Expected, Got) ->
ct:fail(failed)
end.
-%% Like lib:nonl/1, but strips \r as well as \n.
+%% strips \n and \r\n from end of string
strip_nl([$\r, $\n]) -> [];
strip_nl([$\n]) -> [];
diff --git a/lib/kernel/test/pdict_SUITE.erl b/lib/kernel/test/pdict_SUITE.erl
index a891451c82..3685e51c10 100644
--- a/lib/kernel/test/pdict_SUITE.erl
+++ b/lib/kernel/test/pdict_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl
index 5bb230d1c4..a02b5f87d1 100644
--- a/lib/kernel/test/prim_file_SUITE.erl
+++ b/lib/kernel/test/prim_file_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/test/seq_trace_SUITE.erl b/lib/kernel/test/seq_trace_SUITE.erl
index aae8a83304..cf4bf11328 100644
--- a/lib/kernel/test/seq_trace_SUITE.erl
+++ b/lib/kernel/test/seq_trace_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -783,6 +783,24 @@ do_shrink(N) ->
erlang:garbage_collect(),
do_shrink(N-1).
+%% Test that messages from a port does not clear the token
+port_clean_token(Config) when is_list(Config) ->
+ seq_trace:reset_trace(),
+ Label = make_ref(),
+ seq_trace:set_token(label, Label),
+ {label,Label} = seq_trace:get_token(label),
+
+ %% Create a port and get messages from it
+ %% We use os:cmd as a convenience as it does
+ %% open_port, port_command, port_close and receives replies.
+ %% Maybe it is not ideal to rely on the internal implementation
+ %% of os:cmd but it will have to do.
+ os:cmd("ls"),
+
+ %% Make sure that the seq_trace token is still there
+ {label,Label} = seq_trace:get_token(label),
+
+ ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/kernel/test/wrap_log_reader_SUITE.erl b/lib/kernel/test/wrap_log_reader_SUITE.erl
index b1ee29a11f..59b088ca73 100644
--- a/lib/kernel/test/wrap_log_reader_SUITE.erl
+++ b/lib/kernel/test/wrap_log_reader_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/test/wrap_log_reader_SUITE_data/wrap_log_test.erl b/lib/kernel/test/wrap_log_reader_SUITE_data/wrap_log_test.erl
index 2b24ccc66f..d2bac40192 100644
--- a/lib/kernel/test/wrap_log_reader_SUITE_data/wrap_log_test.erl
+++ b/lib/kernel/test/wrap_log_reader_SUITE_data/wrap_log_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/test/zlib_SUITE.erl b/lib/kernel/test/zlib_SUITE.erl
index f203ef878f..52ae1b3ae6 100644
--- a/lib/kernel/test/zlib_SUITE.erl
+++ b/lib/kernel/test/zlib_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index 60a1b0bff8..aa8e4dc119 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 5.4.3
+KERNEL_VSN = 6.0
diff --git a/lib/megaco/doc/src/Makefile b/lib/megaco/doc/src/Makefile
index 43704cddf4..72feb9d2b3 100644
--- a/lib/megaco/doc/src/Makefile
+++ b/lib/megaco/doc/src/Makefile
@@ -114,6 +114,7 @@ clean_man:
clean_html:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
imgs: $(IMG_FILES:%=$(HTMLDIR)/%)
diff --git a/lib/mnesia/doc/src/Makefile b/lib/mnesia/doc/src/Makefile
index aed46d50db..d9647fc081 100644
--- a/lib/mnesia/doc/src/Makefile
+++ b/lib/mnesia/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2017. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -118,6 +118,7 @@ html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/mnesia/doc/src/Mnesia_chap2.xmlsrc b/lib/mnesia/doc/src/Mnesia_chap2.xmlsrc
index 914e0e509c..8135e14301 100644
--- a/lib/mnesia/doc/src/Mnesia_chap2.xmlsrc
+++ b/lib/mnesia/doc/src/Mnesia_chap2.xmlsrc
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/mnesia/doc/src/Mnesia_chap5.xmlsrc b/lib/mnesia/doc/src/Mnesia_chap5.xmlsrc
index 0265e0efa0..481e6651e6 100644
--- a/lib/mnesia/doc/src/Mnesia_chap5.xmlsrc
+++ b/lib/mnesia/doc/src/Mnesia_chap5.xmlsrc
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/mnesia/doc/src/company.erl b/lib/mnesia/doc/src/company.erl
index 5a3b122394..fc04aa77bf 100644
--- a/lib/mnesia/doc/src/company.erl
+++ b/lib/mnesia/doc/src/company.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/doc/src/company_o.erl b/lib/mnesia/doc/src/company_o.erl
index 650b6cdeca..b4b3638596 100644
--- a/lib/mnesia/doc/src/company_o.erl
+++ b/lib/mnesia/doc/src/company_o.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/doc/src/mnesia_frag_hash.xml b/lib/mnesia/doc/src/mnesia_frag_hash.xml
index 51b32129b6..2fae542c86 100644
--- a/lib/mnesia/doc/src/mnesia_frag_hash.xml
+++ b/lib/mnesia/doc/src/mnesia_frag_hash.xml
@@ -130,7 +130,7 @@
<name>key_to_frag_number(State, Key) -> FragNum | abort(Reason)</name>
<fsummary>Resolves the key of a record into a fragment number.</fsummary>
<type>
- <v>FragNum = integer()()</v>
+ <v>FragNum = integer()</v>
<v>Reason = term()</v>
</type>
<desc>
diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml
index ba94e913f5..8a7dab739e 100644
--- a/lib/mnesia/doc/src/notes.xml
+++ b/lib/mnesia/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -39,7 +39,48 @@
thus constitutes one section in this document. The title of each
section is the version number of Mnesia.</p>
- <section><title>Mnesia 4.15.3</title>
+ <section><title>Mnesia 4.15.4</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Calls to <c>erlang:get_stacktrace()</c> are removed.
+ </p>
+ <p>
+ Own Id: OTP-14861</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Mnesia 4.15.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ When master node is set do not force a load from
+ ram_copies replica when there are no available
+ disc_copies, since that would load an empty table. Wait
+ until a disk replica is available or until user
+ explicitly force_loads the table.</p>
+ <p>
+ Own Id: OTP-15221 Aux Id: ERIERL-217 </p>
+ </item>
+ <item>
+ <p>
+ Allow to add replicas even if all other replicas are down
+ when the other replicase are not stored on disk.</p>
+ <p>
+ Own Id: OTP-15226 Aux Id: ERIERL-221 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Mnesia 4.15.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
@@ -648,7 +689,7 @@
<p>
Returns the same value for
mnesia_loader:disc_load_table/2 as
- mnesia_loader:net_load_table/4 if a table copy can not be
+ mnesia_loader:net_load_table/4 if a table copy cannot be
found. (Thanks to Uwe Dauernheim)</p>
<p>
Own Id: OTP-10015</p>
diff --git a/lib/mnesia/src/mnesia.erl b/lib/mnesia/src/mnesia.erl
index 6d87544bd2..223dba3f90 100644
--- a/lib/mnesia/src/mnesia.erl
+++ b/lib/mnesia/src/mnesia.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -168,6 +168,9 @@
-type snmp_struct() :: [{atom(), snmp_type() | tuple_of(snmp_type())}].
-type snmp_type() :: 'fix_string' | 'string' | 'integer'.
-type tuple_of(_T) :: tuple().
+-type config_key() :: extra_db_nodes | dc_dump_limit.
+-type config_value() :: [node()] | number().
+-type config_result() :: {ok, config_value()} | {error, term()}.
-define(DEFAULT_ACCESS, ?MODULE).
@@ -278,7 +281,8 @@ stop() ->
Other -> Other
end.
--spec change_config(Config::atom(), Value::_) -> ok | {error, term()}.
+-spec change_config(Config::config_key(), Value::config_value()) ->
+ config_result().
change_config(extra_db_nodes, Ns) when is_list(Ns) ->
mnesia_controller:connect_nodes(Ns);
change_config(dc_dump_limit, N) when is_number(N), N > 0 ->
@@ -779,12 +783,16 @@ do_delete_object(Tid, Ts, Tab, Val, LockKind) ->
?ets_insert(Store, {Oid, Val, delete_object});
_ ->
case ?ets_match_object(Store, {Oid, '_', write}) of
- [] ->
- ?ets_match_delete(Store, {Oid, Val, '_'}),
- ?ets_insert(Store, {Oid, Val, delete_object});
- _ ->
- ?ets_delete(Store, Oid),
- ?ets_insert(Store, {Oid, Oid, delete})
+ [] ->
+ ?ets_match_delete(Store, {Oid, Val, '_'}),
+ ?ets_insert(Store, {Oid, Val, delete_object});
+ Ops ->
+ case lists:member({Oid, Val, write}, Ops) of
+ true ->
+ ?ets_delete(Store, Oid),
+ ?ets_insert(Store, {Oid, Oid, delete});
+ false -> ok
+ end
end
end,
ok;
diff --git a/lib/mnesia/src/mnesia.hrl b/lib/mnesia/src/mnesia.hrl
index e36222d098..fe48a6fe3d 100644
--- a/lib/mnesia/src/mnesia.hrl
+++ b/lib/mnesia/src/mnesia.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/src/mnesia_bup.erl b/lib/mnesia/src/mnesia_bup.erl
index 9dda340333..e57fc5199d 100644
--- a/lib/mnesia/src/mnesia_bup.erl
+++ b/lib/mnesia/src/mnesia_bup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/src/mnesia_checkpoint.erl b/lib/mnesia/src/mnesia_checkpoint.erl
index 8290237908..3273d3d27e 100644
--- a/lib/mnesia/src/mnesia_checkpoint.erl
+++ b/lib/mnesia/src/mnesia_checkpoint.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017
+%% Copyright Ericsson AB 1996-2018
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl
index 77e67a59db..882de0d613 100644
--- a/lib/mnesia/src/mnesia_controller.erl
+++ b/lib/mnesia/src/mnesia_controller.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -772,22 +772,6 @@ handle_call({unannounce_add_table_copy, [Tab, Node], From}, ReplyTo, State) ->
noreply(State#state{early_msgs = [{call, Msg, undefined} | Msgs]})
end;
-handle_call({net_load, Tab, Cs}, From, State) ->
- State2 =
- case State#state.schema_is_merged of
- true ->
- Worker = #net_load{table = Tab,
- opt_reply_to = From,
- reason = {dumper,{add_table_copy, unknown}},
- cstruct = Cs
- },
- add_worker(Worker, State);
- false ->
- reply(From, {not_loaded, schema_not_merged}),
- State
- end,
- noreply(State2);
-
handle_call(Msg, From, State) when State#state.schema_is_merged /= true ->
%% Buffer early messages
Msgs = State#state.early_msgs,
@@ -1457,7 +1441,8 @@ orphan_tables([Tab | Tabs], Node, Ns, Local, Remote) ->
L = [Tab | Local],
orphan_tables(Tabs, Node, Ns, L, Remote);
Masters ->
- R = [{Tab, Masters} | Remote],
+ %% Do not disc_load table from RamCopyHolders
+ R = [{Tab, Masters -- RamCopyHolders} | Remote],
orphan_tables(Tabs, Node, Ns, Local, R)
end;
_ ->
@@ -2162,6 +2147,15 @@ load_table_fun(#net_load{cstruct=Cs, table=Tab, reason=Reason, opt_reply_to=Repl
{dumper,{add_table_copy,_}} -> true;
_ -> false
end,
+
+ OnlyRamCopies = case Cs of
+ #cstruct{disc_copies = DC,
+ disc_only_copies = DOC,
+ external_copies = Ext} ->
+ [] =:= (DC ++ (DOC ++ Ext)) -- [node()];
+ _ ->
+ false
+ end,
if
ReadNode == node() ->
%% Already loaded locally
@@ -2173,6 +2167,8 @@ load_table_fun(#net_load{cstruct=Cs, table=Tab, reason=Reason, opt_reply_to=Repl
end;
AccessMode == read_only, not AddTableCopy ->
fun() -> disc_load_table(Tab, Reason, ReplyTo) end;
+ Active =:= [], AddTableCopy, OnlyRamCopies ->
+ fun() -> disc_load_table(Tab, Reason, ReplyTo) end;
true ->
fun() ->
%% Either we cannot read the table yet
diff --git a/lib/mnesia/src/mnesia_dumper.erl b/lib/mnesia/src/mnesia_dumper.erl
index 31bcc1451f..a2880d6cf4 100644
--- a/lib/mnesia/src/mnesia_dumper.erl
+++ b/lib/mnesia/src/mnesia_dumper.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/src/mnesia_frag.erl b/lib/mnesia/src/mnesia_frag.erl
index 63fb4981fe..8f7dd321b0 100644
--- a/lib/mnesia/src/mnesia_frag.erl
+++ b/lib/mnesia/src/mnesia_frag.erl
@@ -1,7 +1,7 @@
%%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/src/mnesia_index.erl b/lib/mnesia/src/mnesia_index.erl
index d121bd01e9..917ada65df 100644
--- a/lib/mnesia/src/mnesia_index.erl
+++ b/lib/mnesia/src/mnesia_index.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/src/mnesia_late_loader.erl b/lib/mnesia/src/mnesia_late_loader.erl
index e4f8dcf2b9..45afda6e4b 100644
--- a/lib/mnesia/src/mnesia_late_loader.erl
+++ b/lib/mnesia/src/mnesia_late_loader.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/src/mnesia_lib.erl b/lib/mnesia/src/mnesia_lib.erl
index 56f6926df0..6abc05fade 100644
--- a/lib/mnesia/src/mnesia_lib.erl
+++ b/lib/mnesia/src/mnesia_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -929,7 +929,7 @@ error_desc(no_transaction) -> "Operation not allowed outside transactions";
error_desc(combine_error) -> "Table options were ilegally combined";
error_desc(bad_index) -> "Index already exists or was out of bounds";
error_desc(already_exists) -> "Some schema option we try to set is already on";
-error_desc(index_exists)-> "Some ops can not be performed on tabs with index";
+error_desc(index_exists)-> "Some ops cannot be performed on tabs with index";
error_desc(no_exists)-> "Tried to perform op on non-existing (non alive) item";
error_desc(system_limit) -> "Some system_limit was exhausted";
error_desc(mnesia_down) -> "A transaction involving objects at some remote "
diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl
index bbceb9ba66..2cdae0c906 100644
--- a/lib/mnesia/src/mnesia_loader.erl
+++ b/lib/mnesia/src/mnesia_loader.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -67,7 +67,7 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_copies ->
EtsOpts = proplists:get_value(ets, StorageProps, []),
Args = [{keypos, 2}, public, named_table, Type | EtsOpts],
case Reason of
- {dumper, _} -> %% Resources already allocated
+ {dumper, DR} when is_atom(DR) -> %% Resources already allocated
ignore;
_ ->
mnesia_monitor:mktab(Tab, Args),
@@ -91,8 +91,8 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == ram_copies ->
EtsOpts = proplists:get_value(ets, StorageProps, []),
Args = [{keypos, 2}, public, named_table, Type | EtsOpts],
case Reason of
- {dumper, _} -> %% Resources allready allocated
- ignore;
+ {dumper, DR} when is_atom(DR) ->
+ ignore; %% Resources already allocated
_ ->
mnesia_monitor:mktab(Tab, Args),
Fname = mnesia_lib:tab2dcd(Tab),
@@ -131,7 +131,7 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_only_copies -
{repair, mnesia_monitor:get_env(auto_repair)}
| DetsOpts],
case Reason of
- {dumper, _} ->
+ {dumper, DR} when is_atom(DR) ->
mnesia_index:init_index(Tab, Storage),
snmpify(Tab, Storage),
set({Tab, load_node}, node()),
diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl
index 710bf38cb5..f68626413e 100644
--- a/lib/mnesia/src/mnesia_locker.erl
+++ b/lib/mnesia/src/mnesia_locker.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/src/mnesia_log.erl b/lib/mnesia/src/mnesia_log.erl
index a2de23a2a3..03411ace41 100644
--- a/lib/mnesia/src/mnesia_log.erl
+++ b/lib/mnesia/src/mnesia_log.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/src/mnesia_recover.erl b/lib/mnesia/src/mnesia_recover.erl
index 475bf3c327..2ccea1ea6d 100644
--- a/lib/mnesia/src/mnesia_recover.erl
+++ b/lib/mnesia/src/mnesia_recover.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/src/mnesia_schema.erl b/lib/mnesia/src/mnesia_schema.erl
index de6c3fb4ee..ef38adca1e 100644
--- a/lib/mnesia/src/mnesia_schema.erl
+++ b/lib/mnesia/src/mnesia_schema.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/src/mnesia_subscr.erl b/lib/mnesia/src/mnesia_subscr.erl
index dfaa20d2d3..21a308cfb6 100644
--- a/lib/mnesia/src/mnesia_subscr.erl
+++ b/lib/mnesia/src/mnesia_subscr.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/src/mnesia_text.erl b/lib/mnesia/src/mnesia_text.erl
index 7d24d09472..cc21621ff4 100644
--- a/lib/mnesia/src/mnesia_text.erl
+++ b/lib/mnesia/src/mnesia_text.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl
index 3f6f6c98d8..cbf7db28f0 100644
--- a/lib/mnesia/src/mnesia_tm.erl
+++ b/lib/mnesia/src/mnesia_tm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1661,7 +1661,7 @@ commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) ->
?eval_debug_fun({?MODULE, commit_participant, pre}, [{tid, Tid}]),
try mnesia_schema:prepare_commit(Tid, C0, {part, Coord}) of
{Modified, C = #commit{}, DumperMode} ->
- %% If we can not find any local unclear decision
+ %% If we cannot find any local unclear decision
%% we should presume abort at startup recovery
case lists:member(node(), DiscNs) of
false ->
diff --git a/lib/mnesia/test/mnesia_SUITE.erl b/lib/mnesia/test/mnesia_SUITE.erl
index 279744dbb0..24c1def6da 100644
--- a/lib/mnesia/test/mnesia_SUITE.erl
+++ b/lib/mnesia/test/mnesia_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_atomicity_test.erl b/lib/mnesia/test/mnesia_atomicity_test.erl
index 58a5dc1d40..4764f9e7c0 100644
--- a/lib/mnesia/test/mnesia_atomicity_test.erl
+++ b/lib/mnesia/test/mnesia_atomicity_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_bench_SUITE.erl b/lib/mnesia/test/mnesia_bench_SUITE.erl
index 5cc01867c4..8a225629e6 100644
--- a/lib/mnesia/test/mnesia_bench_SUITE.erl
+++ b/lib/mnesia/test/mnesia_bench_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_consistency_test.erl b/lib/mnesia/test/mnesia_consistency_test.erl
index 7a2678cee3..46bafaf65c 100644
--- a/lib/mnesia/test/mnesia_consistency_test.erl
+++ b/lib/mnesia/test/mnesia_consistency_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_cost.erl b/lib/mnesia/test/mnesia_cost.erl
index 4d0dd7b0ee..b5d5253147 100644
--- a/lib/mnesia/test/mnesia_cost.erl
+++ b/lib/mnesia/test/mnesia_cost.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_dirty_access_test.erl b/lib/mnesia/test/mnesia_dirty_access_test.erl
index 92124ebc65..67ef1fe901 100644
--- a/lib/mnesia/test/mnesia_dirty_access_test.erl
+++ b/lib/mnesia/test/mnesia_dirty_access_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_durability_test.erl b/lib/mnesia/test/mnesia_durability_test.erl
index 2fac5cac82..ccbfdc9738 100644
--- a/lib/mnesia/test/mnesia_durability_test.erl
+++ b/lib/mnesia/test/mnesia_durability_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -46,6 +46,7 @@
master_nodes/1, starting_master_nodes/1,
master_on_non_local_tables/1,
remote_force_load_with_local_master_node/1,
+ master_node_with_ram_copy_2/1, master_node_with_ram_copy_3/1,
dump_ram_copies/1, dump_disc_copies/1, dump_disc_only/1]).
-include("mnesia_test_lib.hrl").
@@ -91,7 +92,8 @@ groups() ->
{load_tables_with_master_tables, [],
[master_nodes, starting_master_nodes,
master_on_non_local_tables,
- remote_force_load_with_local_master_node]},
+ remote_force_load_with_local_master_node,
+ master_node_with_ram_copy_2, master_node_with_ram_copy_3]},
{durability_of_dump_tables, [],
[dump_ram_copies, dump_disc_copies, dump_disc_only]}].
@@ -1165,6 +1167,107 @@ remote_force_load_with_local_master_node(Config) when is_list(Config) ->
?verify_mnesia(Nodes, []).
+master_node_with_ram_copy_2(Config) when is_list(Config) ->
+ [A, B] = Nodes = ?acquire_nodes(2, Config),
+ Tab = ?FUNCTION_NAME,
+ ?match({atomic,ok}, mnesia:create_table(Tab, [{disc_copies, [A]}, {ram_copies, [B]}])),
+ ?match({atomic,ok}, mnesia:sync_transaction(?SDwrite({Tab, 1, init}))),
+
+ %% Test that we don't load from ram_copies
+ ?match(stopped, rpc:call(A, mnesia, stop, [])),
+ ?match(stopped, rpc:call(B, mnesia, stop, [])),
+ ?match(ok, rpc:call(B, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 1000])),
+ ?match(ok, rpc:call(A, mnesia, start, [])),
+ ?match(ok, rpc:call(B, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match([{Tab, 1, init}], rpc:call(A, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, init}], rpc:call(B, mnesia, dirty_read, [{Tab, 1}])),
+
+ %% Test that master_nodes set to ram_copy node require force_load
+ ?match(ok, rpc:call(A, mnesia, set_master_nodes, [[B]])),
+ ?match(stopped, rpc:call(A, mnesia, stop, [])),
+ ?match(stopped, rpc:call(B, mnesia, stop, [])),
+ ?match(ok, rpc:call(B, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 1000])),
+ ?match(ok, rpc:call(A, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 1000])),
+
+ ?match(yes, rpc:call(A, mnesia, force_load_table, [Tab])),
+ ?match(ok, rpc:call(A, mnesia, wait_for_tables, [[Tab], 1000])),
+ ?match(ok, rpc:call(B, mnesia, wait_for_tables, [[Tab], 1000])),
+ ?match([{Tab, 1, init}], rpc:call(A, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, init}], rpc:call(B, mnesia, dirty_read, [{Tab, 1}])),
+
+ ?verify_mnesia(Nodes, []).
+
+
+master_node_with_ram_copy_3(Config) when is_list(Config) ->
+ [A, B, C] = Nodes = ?acquire_nodes(3, Config),
+ Tab = ?FUNCTION_NAME,
+ ?match({atomic,ok}, mnesia:create_table(Tab, [{disc_copies, [A,C]}, {ram_copies, [B]}])),
+ ?match({atomic,ok}, mnesia:sync_transaction(?SDwrite({Tab, 1, init}))),
+
+ %% Test that we don't load from ram_copies
+ ?match(stopped, rpc:call(A, mnesia, stop, [])),
+ ?match(stopped, rpc:call(C, mnesia, stop, [])),
+ ?match(stopped, rpc:call(B, mnesia, stop, [])),
+ ?match(ok, rpc:call(B, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 1000])),
+ ?match(ok, rpc:call(A, mnesia, start, [])),
+ ?match(ok, rpc:call(C, mnesia, start, [])),
+ ?match(ok, rpc:call(B, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match(ok, rpc:call(A, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match([{Tab, 1, init}], rpc:call(A, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, init}], rpc:call(B, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, init}], rpc:call(C, mnesia, dirty_read, [{Tab, 1}])),
+
+ %% Test that master_nodes set to ram_copy node will wait until loaded
+ ?match(ok, rpc:call(A, mnesia, set_master_nodes, [[B]])),
+ ?match(stopped, rpc:call(A, mnesia, stop, [])),
+ ?match({atomic,ok}, rpc:call(B, mnesia, sync_transaction, [?SDwrite({Tab, 1, update})])),
+ ?match(stopped, rpc:call(C, mnesia, stop, [])),
+ ?match({atomic,ok}, rpc:call(B, mnesia, sync_transaction, [?SDwrite({Tab, 1, ram_copies})])),
+ ?match(stopped, rpc:call(B, mnesia, stop, [])),
+ ?match(ok, rpc:call(B, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match(ok, rpc:call(A, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(A, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match(ok, rpc:call(C, mnesia, start, [])),
+ ?match(ok, rpc:call(B, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match(ok, rpc:call(A, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match([{Tab, 1, update}], rpc:call(A, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, update}], rpc:call(B, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, update}], rpc:call(C, mnesia, dirty_read, [{Tab, 1}])),
+
+ %% Test that master_nodes set to ram_copy node requires force load
+ ?match({atomic,ok}, mnesia:sync_transaction(?SDwrite({Tab, 1, init}))),
+ ?match(ok, rpc:call(A, mnesia, set_master_nodes, [[B]])),
+ ?match(ok, rpc:call(C, mnesia, set_master_nodes, [[B]])),
+
+ ?match(stopped, rpc:call(A, mnesia, stop, [])),
+ ?match({atomic,ok}, rpc:call(B, mnesia, sync_transaction, [?SDwrite({Tab, 1, update})])),
+ ?match(stopped, rpc:call(C, mnesia, stop, [])),
+ ?match({atomic,ok}, rpc:call(B, mnesia, sync_transaction, [?SDwrite({Tab, 1, ram_copies})])),
+ ?match(stopped, rpc:call(B, mnesia, stop, [])),
+ ?match(ok, rpc:call(B, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match(ok, rpc:call(A, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(A, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match(ok, rpc:call(C, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(A, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match(yes, rpc:call(C, mnesia, force_load_table, [Tab])),
+
+ ?match(ok, rpc:call(A, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match(ok, rpc:call(B, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match(ok, rpc:call(C, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match([{Tab, 1, update}], rpc:call(A, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, update}], rpc:call(B, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, update}], rpc:call(C, mnesia, dirty_read, [{Tab, 1}])),
+
+ ?verify_mnesia(Nodes, []).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1415,7 +1518,7 @@ do_disc_durability(Config,CopyType) ->
[{Tab_bag, 22, a_2222}], [{Tab_bag, 33, a_3333}],
[{Tab_set, counter, 10}]]),
- timer:sleep(1000), %% Debugging strange msgs..
+ timer:sleep(500), %% Debugging strange msgs..
?log("Flushed ~p ~n", [mnesia_test_lib:flush()]),
?verify_mnesia(Nodes, []).
diff --git a/lib/mnesia/test/mnesia_evil_coverage_test.erl b/lib/mnesia/test/mnesia_evil_coverage_test.erl
index 074967469b..77236940d4 100644
--- a/lib/mnesia/test/mnesia_evil_coverage_test.erl
+++ b/lib/mnesia/test/mnesia_evil_coverage_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
db_node_lifecycle/1, evil_delete_db_node/1, start_and_stop/1,
checkpoint/1, table_lifecycle/1, storage_options/1,
add_copy_conflict/1, add_copy_when_going_down/1,
+ add_copy_with_down/1,
replica_management/1, clear_table_during_load/1,
schema_availability/1, local_content/1,
replica_location/1, user_properties/1, unsupp_user_props/1,
@@ -65,7 +66,8 @@ all() ->
db_node_lifecycle, evil_delete_db_node, start_and_stop,
checkpoint, table_lifecycle, storage_options,
add_copy_conflict,
- add_copy_when_going_down, replica_management, clear_table_during_load,
+ add_copy_when_going_down, add_copy_with_down, replica_management,
+ clear_table_during_load,
schema_availability, local_content,
{group, table_access_modifications}, replica_location,
{group, table_sync}, user_properties, unsupp_user_props,
@@ -732,6 +734,49 @@ add_copy_when_going_down(Config) ->
?match_receive({test,{aborted,_}}),
?verify_mnesia([Node2], []).
+add_copy_with_down(suite) -> [];
+add_copy_with_down(Config) ->
+ %% Allow add_table_copy() with ram_copies even all other replicas are down
+ Nodes = [Node1, Node2, Node3] = ?acquire_nodes(3, Config),
+ ?match({atomic, ok}, mnesia:create_table(a, [{ram_copies, [Node3]}, {disc_copies, [Node2]}])),
+ stopped = rpc:call(Node2, mnesia, stop, []),
+ stopped = rpc:call(Node3, mnesia, stop, []),
+ ?match({aborted, _}, mnesia:add_table_copy(a, Node1, ram_copies)),
+ ?match({aborted, _}, mnesia:del_table_copy(a, Node2)),
+ ok = rpc:call(Node3, mnesia, start, []),
+ ?match({aborted, _}, mnesia:add_table_copy(a, Node1, ram_copies)),
+ ?match([], mnesia_test_lib:start_mnesia([Node2], [a])),
+ ?match({atomic, ok}, mnesia:change_table_copy_type(a, Node2, ram_copies)),
+ stopped = rpc:call(Node2, mnesia, stop, []),
+ stopped = rpc:call(Node3, mnesia, stop, []),
+ ?match({atomic, ok}, mnesia:add_table_copy(a, Node1, ram_copies)),
+ ?match(ok, mnesia:dirty_write({a,1,1})),
+ ?match([], mnesia_test_lib:start_mnesia([Node2,Node3], [a])),
+ ?match([{a,1,1}], rpc:call(Node1, mnesia, dirty_read, [{a,1}])),
+ ?match([{a,1,1}], rpc:call(Node2, mnesia, dirty_read, [{a,1}])),
+ ?match([{a,1,1}], rpc:call(Node3, mnesia, dirty_read, [{a,1}])),
+
+ ?match({atomic, ok}, mnesia:del_table_copy(a, Node1)),
+ stopped = rpc:call(Node2, mnesia, stop, []),
+ stopped = rpc:call(Node3, mnesia, stop, []),
+ ?match({atomic, ok}, mnesia:add_table_copy(a, Node1, disc_copies)),
+ ?match(ok, mnesia:dirty_write({a,1,1})),
+ ?match([], mnesia_test_lib:start_mnesia([Node2,Node3], [a])),
+ ?match([{a,1,1}], rpc:call(Node1, mnesia, dirty_read, [{a,1}])),
+ ?match([{a,1,1}], rpc:call(Node2, mnesia, dirty_read, [{a,1}])),
+ ?match([{a,1,1}], rpc:call(Node3, mnesia, dirty_read, [{a,1}])),
+
+ ?match({atomic, ok}, mnesia:del_table_copy(a, Node1)),
+ stopped = rpc:call(Node2, mnesia, stop, []),
+ stopped = rpc:call(Node3, mnesia, stop, []),
+ ?match({atomic, ok}, mnesia:add_table_copy(a, Node1, disc_only_copies)),
+ ?match(ok, mnesia:dirty_write({a,1,1})),
+ ?match([], mnesia_test_lib:start_mnesia([Node2,Node3], [a])),
+ ?match([{a,1,1}], rpc:call(Node1, mnesia, dirty_read, [{a,1}])),
+ ?match([{a,1,1}], rpc:call(Node2, mnesia, dirty_read, [{a,1}])),
+ ?match([{a,1,1}], rpc:call(Node3, mnesia, dirty_read, [{a,1}])),
+
+ ?verify_mnesia(Nodes, []).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Add, drop and move replicas, change storage types
diff --git a/lib/mnesia/test/mnesia_examples_test.erl b/lib/mnesia/test/mnesia_examples_test.erl
index f1259abf90..3bbb6e4d77 100644
--- a/lib/mnesia/test/mnesia_examples_test.erl
+++ b/lib/mnesia/test/mnesia_examples_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_frag_test.erl b/lib/mnesia/test/mnesia_frag_test.erl
index 7371792fda..7b37fcb684 100644
--- a/lib/mnesia/test/mnesia_frag_test.erl
+++ b/lib/mnesia/test/mnesia_frag_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_install_test.erl b/lib/mnesia/test/mnesia_install_test.erl
index 3f67396eb0..2aee5137c3 100644
--- a/lib/mnesia/test/mnesia_install_test.erl
+++ b/lib/mnesia/test/mnesia_install_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_isolation_test.erl b/lib/mnesia/test/mnesia_isolation_test.erl
index 1c3ea5ec92..49bcec14af 100644
--- a/lib/mnesia/test/mnesia_isolation_test.erl
+++ b/lib/mnesia/test/mnesia_isolation_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1563,7 +1563,8 @@ trans_update_visible_inside_trans(Config) when is_list(Config) ->
?match({atomic, ok}, mnesia:create_table([{name, Tab},
{ram_copies, [Node1]}])),
ValPos = 3,
- RecA = {Tab, a, 1},
+ RecA = {Tab, a, 1},
+ RecA2 = {Tab, a, 2},
PatA = {Tab, '$1', 1},
RecB = {Tab, b, 3},
PatB = {Tab, '$1', 3},
@@ -1598,6 +1599,14 @@ trans_update_visible_inside_trans(Config) when is_list(Config) ->
?match([], mnesia:index_read(Tab, 3, ValPos)),
%% delete_object
+ ?match(ok, mnesia:delete_object(RecA2)),
+ ?match([RecA], mnesia:read({Tab, a})),
+ ?match([RecA], mnesia:wread({Tab, a})),
+ ?match([RecA], mnesia:match_object(PatA)),
+ ?match([a], mnesia:all_keys(Tab)),
+ ?match([RecA], mnesia:index_match_object(PatA, ValPos)),
+ ?match([RecA], mnesia:index_read(Tab, 1, ValPos)),
+
?match(ok, mnesia:delete_object(RecA)),
?match([], mnesia:read({Tab, a})),
?match([], mnesia:wread({Tab, a})),
diff --git a/lib/mnesia/test/mnesia_majority_test.erl b/lib/mnesia/test/mnesia_majority_test.erl
index eb82617b60..aae27e069e 100644
--- a/lib/mnesia/test/mnesia_majority_test.erl
+++ b/lib/mnesia/test/mnesia_majority_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_measure_test.erl b/lib/mnesia/test/mnesia_measure_test.erl
index 4e63eaee22..8eb3590168 100644
--- a/lib/mnesia/test/mnesia_measure_test.erl
+++ b/lib/mnesia/test/mnesia_measure_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_nice_coverage_test.erl b/lib/mnesia/test/mnesia_nice_coverage_test.erl
index 7c96d6e6a0..f8c6b2ce20 100644
--- a/lib/mnesia/test/mnesia_nice_coverage_test.erl
+++ b/lib/mnesia/test/mnesia_nice_coverage_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_qlc_test.erl b/lib/mnesia/test/mnesia_qlc_test.erl
index 262a6b4abc..e66fd84995 100644
--- a/lib/mnesia/test/mnesia_qlc_test.erl
+++ b/lib/mnesia/test/mnesia_qlc_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_recovery_test.erl b/lib/mnesia/test/mnesia_recovery_test.erl
index 1783d2ae94..b5749408f8 100644
--- a/lib/mnesia/test/mnesia_recovery_test.erl
+++ b/lib/mnesia/test/mnesia_recovery_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_registry_test.erl b/lib/mnesia/test/mnesia_registry_test.erl
index 08157f1be3..c15b8e97af 100644
--- a/lib/mnesia/test/mnesia_registry_test.erl
+++ b/lib/mnesia/test/mnesia_registry_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_schema_recovery_test.erl b/lib/mnesia/test/mnesia_schema_recovery_test.erl
index 5e7627ca47..e4199758c1 100644
--- a/lib/mnesia/test/mnesia_schema_recovery_test.erl
+++ b/lib/mnesia/test/mnesia_schema_recovery_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_test_lib.erl b/lib/mnesia/test/mnesia_test_lib.erl
index db0e7beac6..1cdac3cde6 100644
--- a/lib/mnesia/test/mnesia_test_lib.erl
+++ b/lib/mnesia/test/mnesia_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_test_lib.hrl b/lib/mnesia/test/mnesia_test_lib.hrl
index 90a3c686b0..b8eeb5783f 100644
--- a/lib/mnesia/test/mnesia_test_lib.hrl
+++ b/lib/mnesia/test/mnesia_test_lib.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/test/mnesia_trans_access_test.erl b/lib/mnesia/test/mnesia_trans_access_test.erl
index c00a1ed51f..723a85fd2c 100644
--- a/lib/mnesia/test/mnesia_trans_access_test.erl
+++ b/lib/mnesia/test/mnesia_trans_access_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk
index 45f811846d..aaa1c3006f 100644
--- a/lib/mnesia/vsn.mk
+++ b/lib/mnesia/vsn.mk
@@ -1 +1 @@
-MNESIA_VSN = 4.15.3
+MNESIA_VSN = 4.15.4
diff --git a/lib/observer/doc/src/Makefile b/lib/observer/doc/src/Makefile
index 11bfee1bdb..e843772f0b 100644
--- a/lib/observer/doc/src/Makefile
+++ b/lib/observer/doc/src/Makefile
@@ -105,6 +105,7 @@ html: gifs $(HTML_REF_MAN_FILE) $(ONLY_HTML_FILE:%=$(HTMLDIR)/%)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN1DIR)/*
rm -f $(MAN3DIR)/*
rm -f $(MAN6DIR)/*
diff --git a/lib/observer/doc/src/notes.xml b/lib/observer/doc/src/notes.xml
index c0b8309af6..67bba37e39 100644
--- a/lib/observer/doc/src/notes.xml
+++ b/lib/observer/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,35 @@
<p>This document describes the changes made to the Observer
application.</p>
+<section><title>Observer 2.8</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Added possibility to garbage collect selected processes
+ and fixed a crash when the saved config file contained
+ bad data.</p>
+ <p>
+ Own Id: OTP-14993 Aux Id: PR-1666 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Use uri_string module instead of http_uri.</p>
+ <p>
+ Own Id: OTP-14902</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Observer 2.7</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/observer/include/etop.hrl b/lib/observer/include/etop.hrl
index f8d370450b..cda68422ab 100644
--- a/lib/observer/include/etop.hrl
+++ b/lib/observer/include/etop.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/cdv_atom_cb.erl b/lib/observer/src/cdv_atom_cb.erl
index 86cdf2fd6d..87f613124c 100644
--- a/lib/observer/src/cdv_atom_cb.erl
+++ b/lib/observer/src/cdv_atom_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/cdv_bin_cb.erl b/lib/observer/src/cdv_bin_cb.erl
index a4a542297c..91d33474c8 100644
--- a/lib/observer/src/cdv_bin_cb.erl
+++ b/lib/observer/src/cdv_bin_cb.erl
@@ -49,7 +49,7 @@ format_bin_fun(Format,Bin) ->
try io_lib:format(Format,[Bin]) of
Str -> plain_html(lists:flatten(Str))
catch error:badarg ->
- Warning = "This binary can not be formatted with " ++ Format,
+ Warning = "This binary cannot be formatted with " ++ Format,
observer_html_lib:warning(Warning)
end
end.
@@ -59,7 +59,7 @@ binary_to_term_fun(Bin) ->
try binary_to_term(Bin) of
Term -> plain_html(io_lib:format("~tp",[Term]))
catch error:badarg ->
- Warning = "This binary can not be converted to an Erlang term",
+ Warning = "This binary cannot be converted to an Erlang term",
observer_html_lib:warning(Warning)
end
end.
diff --git a/lib/observer/src/cdv_detail_wx.erl b/lib/observer/src/cdv_detail_wx.erl
index 6c4739042b..4b1984c394 100644
--- a/lib/observer/src/cdv_detail_wx.erl
+++ b/lib/observer/src/cdv_detail_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/cdv_dist_cb.erl b/lib/observer/src/cdv_dist_cb.erl
index aeb34e5baf..ad1eb6e73c 100644
--- a/lib/observer/src/cdv_dist_cb.erl
+++ b/lib/observer/src/cdv_dist_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/cdv_html_wx.erl b/lib/observer/src/cdv_html_wx.erl
index 77a9d3207b..d9efa7fc2f 100644
--- a/lib/observer/src/cdv_html_wx.erl
+++ b/lib/observer/src/cdv_html_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/cdv_info_wx.erl b/lib/observer/src/cdv_info_wx.erl
index 07c28610e2..0a23d4ae3f 100644
--- a/lib/observer/src/cdv_info_wx.erl
+++ b/lib/observer/src/cdv_info_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/cdv_mem_cb.erl b/lib/observer/src/cdv_mem_cb.erl
index 925487786c..99ffdda765 100644
--- a/lib/observer/src/cdv_mem_cb.erl
+++ b/lib/observer/src/cdv_mem_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/cdv_multi_wx.erl b/lib/observer/src/cdv_multi_wx.erl
index 93f045b1da..79a44245aa 100644
--- a/lib/observer/src/cdv_multi_wx.erl
+++ b/lib/observer/src/cdv_multi_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/cdv_port_cb.erl b/lib/observer/src/cdv_port_cb.erl
index 6bb8f07a74..cbd5f696a6 100644
--- a/lib/observer/src/cdv_port_cb.erl
+++ b/lib/observer/src/cdv_port_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/cdv_proc_cb.erl b/lib/observer/src/cdv_proc_cb.erl
index 0ea23dd7cb..2497b4889e 100644
--- a/lib/observer/src/cdv_proc_cb.erl
+++ b/lib/observer/src/cdv_proc_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/cdv_sched_cb.erl b/lib/observer/src/cdv_sched_cb.erl
index d2696a276f..a3695a9418 100644
--- a/lib/observer/src/cdv_sched_cb.erl
+++ b/lib/observer/src/cdv_sched_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/cdv_table_wx.erl b/lib/observer/src/cdv_table_wx.erl
index ba23758ea6..0f28a51017 100644
--- a/lib/observer/src/cdv_table_wx.erl
+++ b/lib/observer/src/cdv_table_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/cdv_term_cb.erl b/lib/observer/src/cdv_term_cb.erl
index bdcb13f22d..85da1d227a 100644
--- a/lib/observer/src/cdv_term_cb.erl
+++ b/lib/observer/src/cdv_term_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -51,7 +51,7 @@ format_term_fun(Format,Term,Tab) ->
try io_lib:format(Format,[Term]) of
Str -> {expand, plain_html(Str), Tab}
catch error:badarg ->
- Warning = "This term can not be formatted with " ++ Format,
+ Warning = "This term cannot be formatted with " ++ Format,
observer_html_lib:warning(Warning)
after
observer_lib:report_progress({ok,stop_pulse})
diff --git a/lib/observer/src/cdv_virtual_list_wx.erl b/lib/observer/src/cdv_virtual_list_wx.erl
index 33c0c880b1..2702301021 100644
--- a/lib/observer/src/cdv_virtual_list_wx.erl
+++ b/lib/observer/src/cdv_virtual_list_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/cdv_wx.erl b/lib/observer/src/cdv_wx.erl
index 0e33c9e618..78a897111c 100644
--- a/lib/observer/src/cdv_wx.erl
+++ b/lib/observer/src/cdv_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/crashdump_viewer.erl b/lib/observer/src/crashdump_viewer.erl
index d0c14db486..14b086ff58 100644
--- a/lib/observer/src/crashdump_viewer.erl
+++ b/lib/observer/src/crashdump_viewer.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/crashdump_viewer.hrl b/lib/observer/src/crashdump_viewer.hrl
index 252e19379d..856e558e6c 100644
--- a/lib/observer/src/crashdump_viewer.hrl
+++ b/lib/observer/src/crashdump_viewer.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/etop_tr.erl b/lib/observer/src/etop_tr.erl
index 1e48fefca4..c7e62e8332 100644
--- a/lib/observer/src/etop_tr.erl
+++ b/lib/observer/src/etop_tr.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/multitrace.erl b/lib/observer/src/multitrace.erl
index 82aec05e0d..35b70c63a3 100644
--- a/lib/observer/src/multitrace.erl
+++ b/lib/observer/src/multitrace.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/observer.app.src b/lib/observer/src/observer.app.src
index cd4aa2e299..d73293a5f9 100644
--- a/lib/observer/src/observer.app.src
+++ b/lib/observer/src/observer.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/observer_alloc_wx.erl b/lib/observer/src/observer_alloc_wx.erl
index e0f319b6cc..54e246f247 100644
--- a/lib/observer/src/observer_alloc_wx.erl
+++ b/lib/observer/src/observer_alloc_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/observer_html_lib.erl b/lib/observer/src/observer_html_lib.erl
index 8202f91030..0c4e32af49 100644
--- a/lib/observer/src/observer_html_lib.erl
+++ b/lib/observer/src/observer_html_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl
index 0678b64134..7c68b0ebb6 100644
--- a/lib/observer/src/observer_lib.erl
+++ b/lib/observer/src/observer_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -682,7 +682,7 @@ parse_string(Str) ->
{error, {_SLine, SMod, SError}, _} ->
throw(io_lib:format("~ts", [SMod:format_error(SError)]))
end,
- case lib:extended_parse_term(Tokens) of
+ case erl_eval:extended_parse_term(Tokens) of
{error, {_PLine, PMod, PError}} ->
throw(io_lib:format("~ts", [PMod:format_error(PError)]));
Res -> Res
diff --git a/lib/observer/src/observer_perf_wx.erl b/lib/observer/src/observer_perf_wx.erl
index eddb9327f3..21c6d26f49 100644
--- a/lib/observer/src/observer_perf_wx.erl
+++ b/lib/observer/src/observer_perf_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/observer_port_wx.erl b/lib/observer/src/observer_port_wx.erl
index f7ae07fb85..445f3dd6b1 100644
--- a/lib/observer/src/observer_port_wx.erl
+++ b/lib/observer/src/observer_port_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/observer_pro_wx.erl b/lib/observer/src/observer_pro_wx.erl
index e2372cde33..04e654a37e 100644
--- a/lib/observer/src/observer_pro_wx.erl
+++ b/lib/observer/src/observer_pro_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl
index 6a85d29c1e..f436886735 100644
--- a/lib/observer/src/observer_procinfo.erl
+++ b/lib/observer/src/observer_procinfo.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/observer_traceoptions_wx.erl b/lib/observer/src/observer_traceoptions_wx.erl
index ff8c40ce77..ea292b92af 100644
--- a/lib/observer/src/observer_traceoptions_wx.erl
+++ b/lib/observer/src/observer_traceoptions_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/src/observer_tv_wx.erl b/lib/observer/src/observer_tv_wx.erl
index 2e387f7e74..dfd19569fd 100644
--- a/lib/observer/src/observer_tv_wx.erl
+++ b/lib/observer/src/observer_tv_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -147,7 +147,7 @@ handle_event(#wx{event=#wxList{type=command_list_item_activated,
State=#state{holder=Holder, node=Node, opts=#opts{type=Type}, grid=Grid}) ->
case get_table(Holder, Index) of
#tab{protection=private} ->
- self() ! {error, "Table has 'private' protection and can not be read"};
+ self() ! {error, "Table has 'private' protection and cannot be read"};
#tab{}=Table ->
observer_tv_table:start_link(Grid, [{node,Node}, {type,Type}, {table,Table}]);
_ -> ignore
@@ -187,7 +187,7 @@ handle_event(#wx{id=?ID_SHOW_TABLE},
R when is_integer(R) ->
case get_table(Holder, R) of
#tab{protection=private} ->
- self() ! {error, "Table has 'private' protection and can not be read"};
+ self() ! {error, "Table has 'private' protection and cannot be read"};
#tab{}=Table ->
observer_tv_table:start_link(Grid, [{node,Node}, {type,Type}, {table,Table}]);
_ -> ignore
diff --git a/lib/observer/src/observer_wx.erl b/lib/observer/src/observer_wx.erl
index 453e3bdc2d..1f748cb8d2 100644
--- a/lib/observer/src/observer_wx.erl
+++ b/lib/observer/src/observer_wx.erl
@@ -806,7 +806,7 @@ is_rb_compatible(Node) ->
is_rb_server_running(Node, LogState) ->
%% If already started, somebody else may use it.
- %% We can not use it too, as far log file would be overriden. Not fair.
+ %% We cannot use it too, as far log file would be overriden. Not fair.
case rpc:block_call(Node, erlang, whereis, [rb_server]) of
Pid when is_pid(Pid), (LogState == false) ->
throw("Error: rb_server is already started and maybe used by someone.");
diff --git a/lib/observer/src/ttb_et.erl b/lib/observer/src/ttb_et.erl
index 1b828eebc0..f90a7f6dcf 100644
--- a/lib/observer/src/ttb_et.erl
+++ b/lib/observer/src/ttb_et.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/test/crashdump_helper.erl b/lib/observer/test/crashdump_helper.erl
index b5e94a893a..145ff56b71 100644
--- a/lib/observer/test/crashdump_helper.erl
+++ b/lib/observer/test/crashdump_helper.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/test/crashdump_viewer_SUITE.erl b/lib/observer/test/crashdump_viewer_SUITE.erl
index 8bd7ad387b..864454cdff 100644
--- a/lib/observer/test/crashdump_viewer_SUITE.erl
+++ b/lib/observer/test/crashdump_viewer_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/test/crashdump_viewer_SUITE_data/old_format.dump b/lib/observer/test/crashdump_viewer_SUITE_data/old_format.dump
index 2c8944fa9d..2737757bfa 100644
--- a/lib/observer/test/crashdump_viewer_SUITE_data/old_format.dump
+++ b/lib/observer/test/crashdump_viewer_SUITE_data/old_format.dump
@@ -1285,7 +1285,7 @@ sleep
start_prim_loader
erl_prim_loader
set_path
-'can not start loader'
+'cannot start loader'
add_to_kernel
prim_load_flags
'-loader'
@@ -1304,7 +1304,7 @@ path_flags
'-pz'
get_boot
not_found
-'can not get bootfile'
+'cannot get bootfile'
'bootfile format error'
get_file
script
@@ -1349,7 +1349,7 @@ extension
'-boot/1-fun-0-'
'-bs2ss/1-fun-0-'
'-bs2as/1-fun-0-'
-'can not load'
+'cannot load'
'unexpected command in bootfile'
prim_inet
open
@@ -3071,7 +3071,7 @@ change_group
change_time
master
start_slave
-'can not get remote filer '
+'cannot get remote filer '
start_relay
relay
'Port controlling ~w terminated in file_server'
diff --git a/lib/observer/test/observer_SUITE.erl b/lib/observer/test/observer_SUITE.erl
index fd4f93f662..75336cedcc 100644
--- a/lib/observer/test/observer_SUITE.erl
+++ b/lib/observer/test/observer_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -301,7 +301,7 @@ table_win(Config) when is_list(Config) ->
Notebook = setup_whitebox_testing(),
Parent = get_top_level_parent(Notebook),
TObj = observer_tv_table:start_link(Parent, [{node,node()}, {type,ets}, {table,#tab{name=foo, id=Table}}]),
- %% Modal can not test edit..
+ %% Modal cannot test edit..
%% TPid = wx_object:get_pid(TObj),
%% TPid ! #wx{event=#wxList{type=command_list_item_activated, itemIndex=12}},
timer:sleep(3000),
diff --git a/lib/observer/test/ttb_SUITE.erl b/lib/observer/test/ttb_SUITE.erl
index ed62efbb58..33133dd78d 100644
--- a/lib/observer/test/ttb_SUITE.erl
+++ b/lib/observer/test/ttb_SUITE.erl
@@ -2,7 +2,7 @@
%% %CopyrightBegin%
%%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/observer/vsn.mk b/lib/observer/vsn.mk
index 74a6db768e..bf6fd2a421 100644
--- a/lib/observer/vsn.mk
+++ b/lib/observer/vsn.mk
@@ -1 +1 @@
-OBSERVER_VSN = 2.7
+OBSERVER_VSN = 2.8
diff --git a/lib/odbc/doc/src/Makefile b/lib/odbc/doc/src/Makefile
index b3f93a7e9c..553db8a9a4 100644
--- a/lib/odbc/doc/src/Makefile
+++ b/lib/odbc/doc/src/Makefile
@@ -101,6 +101,7 @@ html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/odbc/doc/src/databases.xml b/lib/odbc/doc/src/databases.xml
index a060f87e46..614c327a46 100644
--- a/lib/odbc/doc/src/databases.xml
+++ b/lib/odbc/doc/src/databases.xml
@@ -65,7 +65,7 @@
<p>Another obstacle is that some drivers do not support scrollable
cursors which has the effect that the only way to traverse the
result set is sequentially, with next, from the first row to the
- last, and once you pass a row you can not go back. This means
+ last, and once you pass a row you cannot go back. This means
that some functions in the interface will not work together with
certain drivers. A similar problem is that not all drivers
support "row count" for select queries, hence resulting in that
diff --git a/lib/odbc/doc/src/error_handling.xml b/lib/odbc/doc/src/error_handling.xml
index 4c80cff12f..8d794d2c99 100644
--- a/lib/odbc/doc/src/error_handling.xml
+++ b/lib/odbc/doc/src/error_handling.xml
@@ -138,7 +138,7 @@
should be run through the erlang port was not compiled for
your platform.</item>
<item>Errors discovered by the ODBC driver - If calls to the
- ODBC-driver fails due to circumstances that can not be
+ ODBC-driver fails due to circumstances that cannot be
controlled by the Erlang ODBC application programmer, an
error string will be dug up from the driver. This string
will be the <c>Reason</c> in the <c>{error, Reason} </c>
diff --git a/lib/odbc/doc/src/getting_started.xml b/lib/odbc/doc/src/getting_started.xml
index f2ff8b8993..b27754ff22 100644
--- a/lib/odbc/doc/src/getting_started.xml
+++ b/lib/odbc/doc/src/getting_started.xml
@@ -50,7 +50,7 @@
and paths to appropriate values. This may differ a lot
between different os's, databases and ODBC drivers. This
is a configuration problem related to the third party product
- and hence we can not give you a standard solution in this guide.</item>
+ and hence we cannot give you a standard solution in this guide.</item>
<item>The Erlang ODBC application consists of both <c>Erlang</c>
and <c>C</c> code. The <c>C</c> code is delivered as a
precompiled executable for windows, solaris and linux (SLES10) in the commercial
diff --git a/lib/odbc/doc/src/notes_history.xml b/lib/odbc/doc/src/notes_history.xml
index 22a92f67cd..d0c0a472e7 100644
--- a/lib/odbc/doc/src/notes_history.xml
+++ b/lib/odbc/doc/src/notes_history.xml
@@ -63,7 +63,7 @@
<list type="bulleted">
<item>
<p>The erlang odbc process will now die normally if a
- connection can not be established. No connection no
+ connection cannot be established. No connection no
process it is expected. And as the client has already
received the error message that would be the reason with
which the erlang process would be stopped, the supervisor
@@ -193,7 +193,7 @@
</item>
<item>
<p>The erlang odbc process will now die normally if a
- connection can not be established. No connection no
+ connection cannot be established. No connection no
process it is expected. And as the client has already
received the error message that would be the reason with
which the erlang process would be stopped, the supervisor
diff --git a/lib/odbc/doc/src/odbc.xml b/lib/odbc/doc/src/odbc.xml
index 4bb1f035f9..9760908855 100644
--- a/lib/odbc/doc/src/odbc.xml
+++ b/lib/odbc/doc/src/odbc.xml
@@ -246,7 +246,7 @@
<p>Closes a connection to a database. This will also
terminate all processes that may have been spawned
when the connection was opened. This call will always succeed.
- If the connection can not be disconnected gracefully it will
+ If the connection cannot be disconnected gracefully it will
be brutally killed. However you may receive an error message
as result if you try to disconnect a connection started by another
process.
diff --git a/lib/odbc/test/odbc_connect_SUITE.erl b/lib/odbc/test/odbc_connect_SUITE.erl
index 261dfc6f20..94ca62b3fb 100644
--- a/lib/odbc/test/odbc_connect_SUITE.erl
+++ b/lib/odbc/test/odbc_connect_SUITE.erl
@@ -259,7 +259,7 @@ not_exist_db(_Config) ->
%%-------------------------------------------------------------------------
no_c_executable() ->
- [{doc,"Test what happens if the port-program can not be found"}].
+ [{doc,"Test what happens if the port-program cannot be found"}].
no_c_executable(_Config) ->
process_flag(trap_exit, true),
Dir = filename:nativename(filename:join(code:priv_dir(odbc),
diff --git a/lib/os_mon/doc/src/Makefile b/lib/os_mon/doc/src/Makefile
index 4aa8879a91..354f8ed26b 100644
--- a/lib/os_mon/doc/src/Makefile
+++ b/lib/os_mon/doc/src/Makefile
@@ -98,6 +98,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/os_mon/doc/src/notes.xml b/lib/os_mon/doc/src/notes.xml
index cec0856a8b..4a878dd704 100644
--- a/lib/os_mon/doc/src/notes.xml
+++ b/lib/os_mon/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,22 @@
</header>
<p>This document describes the changes made to the OS_Mon application.</p>
+<section><title>Os_Mon 2.4.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix <c>disksup</c> to handle mount paths with spaces in
+ them.</p>
+ <p>
+ Own Id: OTP-14513</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Os_Mon 2.4.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/os_mon/doc/src/os_mon_mib.xml b/lib/os_mon/doc/src/os_mon_mib.xml
index dcf3649876..e995bf3de1 100644
--- a/lib/os_mon/doc/src/os_mon_mib.xml
+++ b/lib/os_mon/doc/src/os_mon_mib.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -35,7 +35,10 @@
<p>Functions for loading and unloading the OTP-OS-MON-MIB into/from
an SNMP agent. The instrumentation of the OTP-OS-MON-MIB uses
Mnesia, hence Mnesia must be started prior to loading
- the OTP-OS-MON-MIB.</p>
+ the OTP-OS-MON-MIB.</p>
+ <warning>
+ <p>This module has been deprecated and will be removed in a furture release.</p>
+ </warning>
</description>
<funcs>
<func>
diff --git a/lib/os_mon/src/cpu_sup.erl b/lib/os_mon/src/cpu_sup.erl
index c1c972b5b1..81e049ef22 100644
--- a/lib/os_mon/src/cpu_sup.erl
+++ b/lib/os_mon/src/cpu_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/os_mon/src/memsup.erl b/lib/os_mon/src/memsup.erl
index a30d962ad4..9d6447430d 100644
--- a/lib/os_mon/src/memsup.erl
+++ b/lib/os_mon/src/memsup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/os_mon/test/cpu_sup_SUITE.erl b/lib/os_mon/test/cpu_sup_SUITE.erl
index 7122d23503..ba28f31f26 100644
--- a/lib/os_mon/test/cpu_sup_SUITE.erl
+++ b/lib/os_mon/test/cpu_sup_SUITE.erl
@@ -122,19 +122,19 @@ util_api(Config) when is_list(Config) ->
%% util([])
{all, Busy1, NonBusy1, []} = cpu_sup:util([]),
- 100.00 = Busy1 + NonBusy1,
+ true = tiny_diff(100.00, Busy1 + NonBusy1),
%% util([detailed])
{Cpus2, Busy2, NonBusy2, []} = cpu_sup:util([detailed]),
true = lists:all(fun(X) -> is_integer(X) end, Cpus2),
true = lists:all(BusyP, Busy2),
true = lists:all(NonBusyP, NonBusy2),
- 100.00 = lists:foldl(Sum,0,Busy2)+lists:foldl(Sum,0,NonBusy2),
+ true = tiny_diff(100.00, lists:foldl(Sum,0,Busy2)+lists:foldl(Sum,0,NonBusy2)),
%% util([per_cpu])
[{Cpu3, Busy3, NonBusy3, []}|_] = cpu_sup:util([per_cpu]),
true = is_integer(Cpu3),
- 100.00 = Busy3 + NonBusy3,
+ true = tiny_diff(100.00, Busy3 + NonBusy3),
%% util([detailed, per_cpu])
[{Cpu4, Busy4, NonBusy4, []}|_] =
@@ -142,7 +142,7 @@ util_api(Config) when is_list(Config) ->
true = is_integer(Cpu4),
true = lists:all(BusyP, Busy2),
true = lists:all(NonBusyP, NonBusy2),
- 100.00 = lists:foldl(Sum,0,Busy4)+lists:foldl(Sum,0,NonBusy4),
+ true = tiny_diff(100.00, lists:foldl(Sum,0,Busy4)+lists:foldl(Sum,0,NonBusy4)),
%% bad util/1 calls
{'EXIT',{badarg,_}} = (catch cpu_sup:util(detailed)),
@@ -150,6 +150,9 @@ util_api(Config) when is_list(Config) ->
ok.
+tiny_diff(A, B) ->
+ (abs(A - B) < 1.0e-11).
+
-define(SPIN_TIME, 1000).
%% Test utilization values
diff --git a/lib/os_mon/test/disksup_SUITE.erl b/lib/os_mon/test/disksup_SUITE.erl
index d7f2626160..fe27ea9046 100644
--- a/lib/os_mon/test/disksup_SUITE.erl
+++ b/lib/os_mon/test/disksup_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/os_mon/vsn.mk b/lib/os_mon/vsn.mk
index eb4f13ea9e..4a327e5506 100644
--- a/lib/os_mon/vsn.mk
+++ b/lib/os_mon/vsn.mk
@@ -1 +1 @@
-OS_MON_VSN = 2.4.4
+OS_MON_VSN = 2.4.5
diff --git a/lib/otp_mibs/doc/src/Makefile b/lib/otp_mibs/doc/src/Makefile
index c65e2a8e3c..143d9befb8 100644
--- a/lib/otp_mibs/doc/src/Makefile
+++ b/lib/otp_mibs/doc/src/Makefile
@@ -93,6 +93,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/otp_mibs/doc/src/notes.xml b/lib/otp_mibs/doc/src/notes.xml
index c99148a904..ac0777d225 100644
--- a/lib/otp_mibs/doc/src/notes.xml
+++ b/lib/otp_mibs/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,22 @@
<p>This document describes the changes made to the OTP_Mibs
application.</p>
+<section><title>Otp_Mibs 1.2</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The otp_mibs application has been deprecated and will be
+ removed in a future release.</p>
+ <p>
+ Own Id: OTP-15141</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Otp_Mibs 1.1.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/otp_mibs/doc/src/otp_mib.xml b/lib/otp_mibs/doc/src/otp_mib.xml
index 681ce9fa2d..530c529c69 100644
--- a/lib/otp_mibs/doc/src/otp_mib.xml
+++ b/lib/otp_mibs/doc/src/otp_mib.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2003</year><year>2016</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -34,7 +34,10 @@
<p>The SNMP application should be used to start an SNMP agent. Then
the API functions below can be used to load/unload the OTP-MIB
into/from the agent. The instrumentation of the OTP-MIB uses
- Mnesia, hence Mnesia must be started prior to loading the OTP-MIB.</p>
+ Mnesia, hence Mnesia must be started prior to loading the OTP-MIB.</p>
+ <warning>
+ <p>This application has been deprecated and will be removed in a furture release.</p>
+ </warning>
</description>
<funcs>
<func>
diff --git a/lib/otp_mibs/src/otp_mib.erl b/lib/otp_mibs/src/otp_mib.erl
index 1431818be4..ca868f2817 100644
--- a/lib/otp_mibs/src/otp_mib.erl
+++ b/lib/otp_mibs/src/otp_mib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -36,6 +36,9 @@
%% Exported for internal use via rpc
-export([get_erl_node/1, get_appls/1]).
+-deprecated([{load,1,eventually},
+ {unload,1,eventually}]).
+
%% Shadow tables
-record(erlNodeTable,
{erlNodeId, erlNodeName, erlNodeMachine, erlNodeVersion,
diff --git a/lib/otp_mibs/vsn.mk b/lib/otp_mibs/vsn.mk
index 13406cb5b1..2e9e367d98 100644
--- a/lib/otp_mibs/vsn.mk
+++ b/lib/otp_mibs/vsn.mk
@@ -1,4 +1,4 @@
-OTP_MIBS_VSN = 1.1.2
+OTP_MIBS_VSN = 1.2
# Note: The branch 'otp_mibs' is defunct as of otp_mibs-1.0.4 and
# should NOT be used again.
diff --git a/lib/parsetools/doc/src/Makefile b/lib/parsetools/doc/src/Makefile
index e4cd2c0a76..a40ccd0fe7 100644
--- a/lib/parsetools/doc/src/Makefile
+++ b/lib/parsetools/doc/src/Makefile
@@ -89,6 +89,7 @@ html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/parsetools/doc/src/notes.xml b/lib/parsetools/doc/src/notes.xml
index b3370a06ab..3e999c8cd0 100644
--- a/lib/parsetools/doc/src/notes.xml
+++ b/lib/parsetools/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,21 @@
</header>
<p>This document describes the changes made to the Parsetools application.</p>
+<section><title>Parsetools 2.1.7</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Calls to <c>erlang:get_stacktrace()</c> are removed.
+ </p>
+ <p>
+ Own Id: OTP-14861</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Parsetools 2.1.6</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/parsetools/include/yeccpre.hrl b/lib/parsetools/include/yeccpre.hrl
index 53e8124aaa..562f17c19e 100644
--- a/lib/parsetools/include/yeccpre.hrl
+++ b/lib/parsetools/include/yeccpre.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/parsetools/src/yecc.erl b/lib/parsetools/src/yecc.erl
index b4e1cfe5e3..3343a4282b 100644
--- a/lib/parsetools/src/yecc.erl
+++ b/lib/parsetools/src/yecc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -455,10 +455,14 @@ os_process_size() ->
case os:type() of
{unix, sunos} ->
Size = os:cmd("ps -o vsz -p " ++ os:getpid() ++ " | tail -1"),
- list_to_integer(lib:nonl(Size));
+ list_to_integer(nonl(Size));
_ ->
0
- end.
+ end.
+
+nonl([$\n]) -> [];
+nonl([]) -> [];
+nonl([H|T]) -> [H|nonl(T)].
timeit(Name, Fun, St0) ->
Time = runtime,
diff --git a/lib/parsetools/src/yeccparser.erl b/lib/parsetools/src/yeccparser.erl
index 45d91a83a3..0deecc7879 100644
--- a/lib/parsetools/src/yeccparser.erl
+++ b/lib/parsetools/src/yeccparser.erl
@@ -17,7 +17,7 @@ anno_of(Token) ->
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/parsetools/test/yecc_SUITE.erl b/lib/parsetools/test/yecc_SUITE.erl
index 2d3b15326b..715e50c301 100644
--- a/lib/parsetools/test/yecc_SUITE.erl
+++ b/lib/parsetools/test/yecc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/parsetools/vsn.mk b/lib/parsetools/vsn.mk
index b6d2ce0cd4..210723e449 100644
--- a/lib/parsetools/vsn.mk
+++ b/lib/parsetools/vsn.mk
@@ -1 +1 @@
-PARSETOOLS_VSN = 2.1.6
+PARSETOOLS_VSN = 2.1.7
diff --git a/lib/public_key/doc/src/Makefile b/lib/public_key/doc/src/Makefile
index f5157fe87a..03467e9783 100644
--- a/lib/public_key/doc/src/Makefile
+++ b/lib/public_key/doc/src/Makefile
@@ -99,6 +99,7 @@ html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(MAN6DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
diff --git a/lib/public_key/doc/src/notes.xml b/lib/public_key/doc/src/notes.xml
index 11012ee9e5..204520473a 100644
--- a/lib/public_key/doc/src/notes.xml
+++ b/lib/public_key/doc/src/notes.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2017</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -35,6 +35,83 @@
<file>notes.xml</file>
</header>
+<section><title>Public_Key 1.6.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Some of the keylengths in the newly generated moduli file
+ in public_key are not universally supported. This could
+ cause the SSH key exchange
+ diffie-hellman-group-exchange-sha* to fail.</p>
+ <p>
+ Those keylengths are now removed.</p>
+ <p>
+ Own Id: OTP-15151 Aux Id: OTP-15113 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Public_Key 1.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Update calls to the base64 module to conform to that
+ module's type specifications.</p>
+ <p>
+ Own Id: OTP-14788 Aux Id: OTP-14624 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Use uri_string module instead of http_uri.</p>
+ <p>
+ Own Id: OTP-14902</p>
+ </item>
+ <item>
+ <p>
+ A new function -
+ <c>public_key:pkix_verify_hostname_match_fun/1</c> -
+ returns a fun to be given as option <c>match_fun</c> to
+ <c>public_key:pkix_verify_hostname/3</c> or via ssl.</p>
+ <p>
+ The fun makes the verify hostname matching according to
+ the specific rules for the protocol in the argument.
+ Presently only <c>https</c> is supported.</p>
+ <p>
+ Own Id: OTP-14962 Aux Id: ERL-542, OTP-15102 </p>
+ </item>
+ <item>
+ <p>
+ Compleate PKCS-8 encoding support and enhance the
+ decoding of 'PrivateKeyInfo' to conform to the rest of
+ Erlang public_key API.</p>
+ <p>
+ Own Id: OTP-15093</p>
+ </item>
+ <item>
+ <p>
+ A new moduli file is generated. This file is used for the
+ recommended <c>diffie-hellman-group-exchange-sha256</c>
+ key exchange algorithm in SSH.</p>
+ <p>
+ Own Id: OTP-15113</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Public_Key 1.5.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index 7284da0499..aaccb5088b 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2017</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -682,7 +682,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
<tag>{undetermined_details, boolean()}</tag>
<item>
- <p>Defaults to false. When revocation status can not be
+ <p>Defaults to false. When revocation status cannot be
determined, and this option is set to true, details of why no
CRLs where accepted are included in the return value.</p>
</item>
@@ -902,7 +902,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
<note><p>
Note that the generated certificates and keys does not provide a formally correct PKIX-trust-chain
- and they can not be used to achieve real security. This function is provided for testing purposes only.
+ and they cannot be used to achieve real security. This function is provided for testing purposes only.
</p></note>
</desc>
</func>
@@ -969,27 +969,96 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
</type>
<desc>
<p>This function checks that the <i>Presented Identifier</i> (e.g hostname) in a peer certificate
- is in agreement with the <i>Reference Identifier</i> that the client expects to be connected to.
+ is in agreement with at least one of the <i>Reference Identifier</i> that the client expects to be connected to.
The function is intended to be added as an extra client check of the peer certificate when performing
<seealso marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_validation/3</seealso>
</p>
<p>See <url href="https://tools.ietf.org/html/rfc6125">RFC 6125</url>
for detailed information about hostname verification.
- The <seealso marker="using_public_key#verify_hostname">User's Manual</seealso>
+ The <seealso marker="using_public_key#verify_hostname">User's Guide</seealso>
and
<seealso marker="using_public_key#verify_hostname_examples">code examples</seealso>
describes this function more detailed.
</p>
<p>The <c>{OtherRefId,term()}</c> is defined by the user and is passed to the <c>match_fun</c>, if defined.
- If that term is a binary, it will be converted to a string.
+ If the term in <c>OtherRefId</c> is a binary, it will be converted to a string.
</p>
<p>The <c>ip</c> Reference ID takes an <seealso marker="inet:inet#type-ip_address">inet:ip_address()</seealso>
or an ip address in string format (E.g "10.0.1.1" or "1234::5678:9012") as second element.
</p>
+ <p>The options are:</p>
+ <taglist>
+ <tag><c>match_fun</c></tag>
+ <item>
+ The <c>fun/2</c> in this option replaces the default host name matching rules. The fun should return a
+ boolean to tell if the Reference ID and Presented ID matches or not. The fun can also return a third
+ value, the atom <c>default</c>, if the default matching rules shall apply.
+ This makes it possible to augment the tests with a special case:
+ <code>
+fun(....) -> true; % My special case
+ (_, _) -> default % all others falls back to the inherit tests
+end
+ </code>
+ <br/>See <seealso marker="#pkix_verify_hostname_match_fun-1">pkix_verify_hostname_match_fun/1</seealso> for a
+ function that takes a protocol name as argument and returns a <c>fun/2</c> suitable for this option and
+ <seealso marker="using_public_key#redefining_match_op">Re-defining the match operation</seealso>
+ in the User's Guide for an example.
+ </item>
+
+ <tag><c>fail_callback</c></tag>
+ <item>If a matching fails, there could be circumstances when the certificate should be accepted anyway. Think for
+ example of a web browser where you choose to accept an outdated certificate. This option enables implementation
+ of such a function. This <c>fun/1</c> is called when no <c>ReferenceID</c> matches. The return value of the fun
+ (a <c>boolean()</c>) decides the outcome. If <c>true</c> the the certificate is accepted otherwise
+ it is rejected. See
+ <seealso marker="using_public_key#-pinning--a-certificate">"Pinning" a Certificate</seealso>
+ in the User's Guide.
+ </item>
+
+ <tag><c>fqdn_fun</c></tag>
+ <item>This option augments the host name extraction from URIs and other Reference IDs. It could for example be
+ a very special URI that is not standardised. The fun takes a Reference ID as argument and returns one of:
+ <list>
+ <item>the hostname</item>
+ <item>the atom <c>default</c>: the default host name extract function will be used</item>
+ <item>the atom <c>undefined</c>: a host name could not be extracted. The pkix_verify_hostname/3
+ will return <c>false</c>.</item>
+ </list>
+ <br/>For an example, see
+ <seealso marker="using_public_key#hostname_extraction">Hostname extraction</seealso>
+ in the User's Guide.
+ </item>
+ </taglist>
+
</desc>
</func>
<func>
+ <name>pkix_verify_hostname_match_fun(Protcol) -> fun(RefId | FQDN::string(), PresentedID) -> boolean() | default</name>
+ <fsummary>Returns a fun that is intendended as argument to the match_fun option in pkix_verify_hostname/3.
+ </fsummary>
+ <type>
+ <v>Protocol = https</v>
+ <d>The algorithm for wich the fun should implement the special matching rules</d>
+ <v>RefId</v>
+ <d>See <seealso marker="#pkix_verify_hostname-3">pkix_verify_hostname/3</seealso>.</d>
+ <v>FQDN</v>
+ <d>See <seealso marker="#pkix_verify_hostname-3">pkix_verify_hostname/3</seealso>.</d>
+ <v>PresentedID</v>
+ <d>See <seealso marker="#pkix_verify_hostname-3">pkix_verify_hostname/3</seealso>.</d>
+ </type>
+ <desc>
+ <p>The return value of calling this function is intended to be used in the <c>match_fun</c> option in
+ <seealso marker="#pkix_verify_hostname-3">pkix_verify_hostname/3</seealso>.
+ </p>
+ <p>The returned fun augments the verify hostname matching according to the specific rules for
+ the protocol in the argument.
+ </p>
+ </desc>
+ </func>
+
+
+ <func>
<name>sign(Msg, DigestType, Key) -> binary()</name>
<name>sign(Msg, DigestType, Key, Options) -> binary()</name>
<fsummary>Creates a digital signature.</fsummary>
diff --git a/lib/public_key/doc/src/public_key_records.xml b/lib/public_key/doc/src/public_key_records.xml
index 9ebdbb244d..d26867c12f 100644
--- a/lib/public_key/doc/src/public_key_records.xml
+++ b/lib/public_key/doc/src/public_key_records.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2015</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/public_key/doc/src/using_public_key.xml b/lib/public_key/doc/src/using_public_key.xml
index 417d479da3..de0a6596c3 100644
--- a/lib/public_key/doc/src/using_public_key.xml
+++ b/lib/public_key/doc/src/using_public_key.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2011</year><year>2016</year>
+ <year>2011</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -570,6 +570,7 @@ true = public_key:verify(Digest, none, Signature, PublicKey),</code>
<c>fqdn_fun</c> and <c>match_fun</c>.
</p>
<section>
+ <marker id="hostname_extraction"></marker>
<title>Hostname extraction</title>
<p>The <c>fqdn_fun</c> extracts hostnames (Fully Qualified Domain Names) from uri_id
or other ReferenceIDs that are not pre-defined in the public_key function.
@@ -595,7 +596,8 @@ true = public_key:verify(Digest, none, Signature, PublicKey),</code>
</code>
</section>
<section>
- <title>Re-defining the match operations</title>
+ <marker id="redefining_match_op"></marker>
+ <title>Re-defining the match operation</title>
<p>The default matching handles dns_id and uri_id. In an uri_id the value is tested for
equality with a value from the <c>Subject Alternate Name</c>. If som other kind of matching
is needed, use the <c>match_fun</c> option.
diff --git a/lib/public_key/include/public_key.hrl b/lib/public_key/include/public_key.hrl
index 663e1856ac..98d032bfdd 100644
--- a/lib/public_key/include/public_key.hrl
+++ b/lib/public_key/include/public_key.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/public_key/priv/moduli b/lib/public_key/priv/moduli
index 446f4b8bf4..83e8767a5e 100644
--- a/lib/public_key/priv/moduli
+++ b/lib/public_key/priv/moduli
@@ -1,193 +1,240 @@
-20151021104105 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D182EB7
-20151021104106 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D27F94F
-20151021104107 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D398EB7
-20151021104108 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D4B850F
-20151021104108 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D4BF35B
-20151021104108 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D5031DF
-20151021104109 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D5A4933
-20151021104110 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D6434BF
-20151021104111 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D70676B
-20151021104111 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D7235E3
-20151021104113 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9D963493
-20151021104114 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9DAABAA7
-20151021104115 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9DC2E333
-20151021104116 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9DE16A7B
-20151021104117 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9DE2C5D3
-20151021104118 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9DFF382F
-20151021104119 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9E158F13
-20151021104122 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9E4D9FEB
-20151021104123 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9E5C1FDB
-20151021104126 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9E9BB69B
-20151021104126 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9E9F62D3
-20151021104127 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9EAA1C27
-20151021104128 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9EBC3313
-20151021104129 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9EC0733B
-20151021104130 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9EDB7AD3
-20151021104132 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9EF56457
-20151021104132 2 6 100 1023 5 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9EF5A9CF
-20151021104133 2 6 100 1023 2 CF973CD39DC7D62F2C45AAC5180491104C76E0FE5D80A10E6C06AE442F1F373167B0FCBC931F3C157B10A5557008FDE20D68051E6A4DB11CEE0B0749F76D7134B937A59DA998C42BC234A5C1A3CFCD70E624D253D7694076F7B1FD7B8D3427849C9377B3555796ACA58C69DFF542EEEC9859D3ADCE5CC88DF6F7817C9F13CBB3
-20151021104218 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17BAAFFDF
-20151021104222 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17BCB6D93
-20151021104225 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17BE660BB
-20151021104226 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17BE676C3
-20151021104229 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17BF3E23B
-20151021104230 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17BF95757
-20151021104241 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17C59BEA7
-20151021104242 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17C6231B3
-20151021104244 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17C6879BF
-20151021104250 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17C9B678F
-20151021104252 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17CA66A4B
-20151021104253 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17CAB5543
-20151021104256 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17CB96933
-20151021104300 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17CDA8493
-20151021104308 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17D18C0C7
-20151021104310 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17D1DA5BF
-20151021104318 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17D4AB15F
-20151021104325 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17D7DE42F
-20151021104329 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17DA03D3B
-20151021104335 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17DD88BFF
-20151021104338 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17DE82B5F
-20151021104342 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17E07AF43
-20151021104343 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17E091E6F
-20151021104346 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17E28B90F
-20151021104347 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17E2A24F3
-20151021104401 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17EB074A7
-20151021104403 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17EC01B0F
-20151021104406 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17ED2186F
-20151021104407 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17ED55AAB
-20151021104411 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17EF58773
-20151021104414 2 6 100 1535 5 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17F0B3267
-20151021104423 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17F4DF61B
-20151021104434 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17F9BBB0B
-20151021104442 2 6 100 1535 2 CA8FA8EC4B042248C2F4430EE03A77F23899363D2D20972D2BA94033EF18619FD18260B0903BA8B8F385791338369E285FEF46A7FAFF6B02B6888E9810A9C02A3C6FF7F7F85C81205FBE5A387E8A8AA2F42782671F0F86E1C68D3718D03FD517AE44C99FDCD955EF4C762E6245FBA81A9AB492A107A1E72A0FE6A4FE179B00986C4614F66805F921AE05185D52679F3E262B2A0B41812638C7F0421AEDF59BED23860E3FB5A521A11EA2A1E4D483132C857ED7328B9852BB4437C0D17FDD6AFB
-20151021104350 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE5E381EF
-20151021104414 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE641C193
-20151021104422 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE659F523
-20151021104427 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE660E217
-20151021104438 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE6842F73
-20151021104441 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE689683B
-20151021104455 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE6C41E3B
-20151021104512 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE71E3BFF
-20151021104525 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE75C804F
-20151021104527 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE75DC48B
-20151021104535 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE7738983
-20151021104543 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE787027B
-20151021104610 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE8075A1B
-20151021104625 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE84F79B3
-20151021104628 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE859F617
-20151021104641 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE8948E2F
-20151021104646 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE8A571B3
-20151021104659 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE8CEA637
-20151021104705 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE8E590FF
-20151021104707 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE8E7943F
-20151021104731 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE95A975F
-20151021104741 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE985F923
-20151021104745 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE996E20B
-20151021104806 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BE9FACFD7
-20151021104827 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BEA562C43
-20151021104839 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BEA8F25E3
-20151021104939 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BEBB1DA0B
-20151021104941 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BEBB86153
-20151021105002 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BEC1B8883
-20151021105019 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BEC71316F
-20151021105035 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BECB1D113
-20151021105042 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BECC3F3AB
-20151021105045 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BECCC109B
-20151021105101 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BED16353B
-20151021105106 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BED24854F
-20151021105109 2 6 100 2047 2 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BED2AE4B3
-20151021105116 2 6 100 2047 5 F7693FC11FDDEAA493D3BA36F1FFF9264AA9952209203192A88A697BE9D0E306E306A27430BD87AB9EE9DB4BC78C41950C2EB0E5E4C686E8B1BA6D6A2B1FE91EF40C5EA32C51018323E1D305FE637F35ACABDBFC40AD683F779570A76869EB90015A342B2D1F7C81602688081FCAAA8D623090258D9C5C729C8CDDC0C12CA2D561DD987DB79B6AD7A2A509EBC383BF223FD95BC5A2FCC26FB3F3A0DD3FDC1228E338D3290235A596F9465F7BF490974847E616229A9E60B8F4AA161C52F655843CCCAE8821B40C426B535DE087964778652BBD4EC601C0456AE7128B593FCC64402C891227AE6EE88CC839416FBF462B4852999C646BE0BED7D8CF2BED472CF7
-20151021104612 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E360CD0C3
-20151021104628 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3620FBE7
-20151021104701 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E36490F57
-20151021105014 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E377ACADB
-20151021105125 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E37E6DE07
-20151021105320 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E38C2387F
-20151021105649 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3A61E46B
-20151021105815 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3B0A6A4B
-20151021105848 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3B47D2C3
-20151021105948 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3BBBB953
-20151021110011 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3BE3B83B
-20151021110036 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3C0A3F1B
-20151021110201 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3CB1970F
-20151021110208 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3CB70C2B
-20151021110235 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3CE4E4DF
-20151021110424 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3DB68CD7
-20151021110525 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3E290717
-20151021110655 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3ED6DA83
-20151021110731 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3F14C563
-20151021110831 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E3F85477F
-20151021111418 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E420DE56B
-20151021111430 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E421DBA2F
-20151021111624 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E42F39A93
-20151021111916 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E44302363
-20151021112222 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E4585795F
-20151021112245 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E45A1DAFF
-20151021112339 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E4601674F
-20151021112437 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E46691977
-20151021112521 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E46AF3AD3
-20151021112532 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E46BCAE97
-20151021112708 2 6 100 3071 2 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E476520D3
-20151021112724 2 6 100 3071 5 EF9230A29EC5925FD89310E8F3002A60977FBF02543B6BE08667D8E970AD2468FF1B0892B7310073860FA7145250E6FE7A3902CBE70CC7DB0776031A0868780D47644BD8CD714E41B2AC2D744A51ECA4877FE3D2F496D8E6FC03F2F05B29284DA8682F9BCC93CC16846DF724BFAB53FAAC8492CFBFDCBA92A2F12C221E7FAFC4D8AF54156F649C44869592721FDC2AA65BEDC19DCD2CDD9E14F147F18F900A90B48D6D83197BBFE501FC4F19AE7C16D70DDCE3C757970D1CAFB474A0EA215E747E45C05E90935B721058DDF1BFE23C603A367E66C7E096547952663AFFC9A2B8F6292E12E81A6A61A47D032F7EF62DF4A9998D7B21A7917CC89BA68EB1D40BD9625087754618DC06AA486258DBEAA4B177A82ED0D9E2D9442C89D5354B04712F5159CE4EC6EDD608A5BB25700D24EA16E49A20931891C796B53227698132B5E9321905B81BBB7303BAE12DAB4C864A7B305FE9D6B196921F4890229171DE6DF09FA4D1067255F9D0F05F72DDAA6EB55E73F93EEA17B31A46CB33662E477B3317
-20151021105143 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BA7321EB
-20151021105537 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BB3AF34B
-20151021105816 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BBC51883
-20151021110444 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BD1A86C7
-20151021111341 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BEDB7BBB
-20151021111438 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BF0297AB
-20151021111935 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156BFF381FF
-20151021113820 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C433A1BF
-20151021113833 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C43B426B
-20151021113900 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C45007D3
-20151021113921 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C45D8C3B
-20151021113941 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C4685D5F
-20151021114203 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C4F95D97
-20151021114417 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C57ED2FF
-20151021114645 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C612EC33
-20151021114825 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C67219F7
-20151021114922 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C6A942BB
-20151021115945 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156C91E14DB
-20151021120515 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CA5F5DB3
-20151021120715 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CAD0D497
-20151021121027 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CB8F9D6F
-20151021121241 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CC0F677F
-20151021121518 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CC9CC647
-20151021121600 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CCC0ADC3
-20151021121734 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CD1BC68B
-20151021121759 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CD2A7DBF
-20151021122003 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CDA3D323
-20151021122542 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CED8D107
-20151021122856 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156CF8DFEE7
-20151021123548 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D11CAC4F
-20151021123633 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D1426BBB
-20151021124201 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D2A62F0B
-20151021124454 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D353F0FB
-20151021124620 2 6 100 4095 5 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D3AE526F
-20151021125224 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D535C4CB
-20151021130254 2 6 100 4095 2 C8842271626E53546E0C712FA265713F2EE073C20A0723C96B6B182B1EAACC96233D4A199BD0E85F264078A513AD2454F284B8DF543D85019D1E70F2FF54BA43EFBC64AF465C170C3E376F5EC328F98E33E1ED8BED84FA097ABE584152B0E9827ED5CC2B1D4F5ECF2DC46F45C59816D02698EA26F319311E2B6973E83C37021CC8B416AEF653896A1764EE0CEE718A45E8B47CB960BD5907D0E843E8A8E7D4698363C3C3FB3ADC512368B72CAF16510C69052EA2AF51BE00BC8CA04DF1F00A00CC2CA4D74254A1E8738460FD244DDB446CB36554B0A24EEF3710E44DBCF39881E7D3F9AE223388084E7A49A3CB12612AE36416C0EB5628DF1477FEE4A5CF77CDC09AA0E2C989C0B7D1310AFA44B81DA79A65226C7EA510057991EABF9388DC5EA9F52FEA5D3B0872843F50878740794E523E9DC60E0EA1FC8746A7B2AA31FCA89AAA2FA907BED116C69D98F912DD5089BECF28577064225DE96FC214ED1794E7CCE8024F94036D915A123A464C951DA96A5ED7F286F205BEE71BDE2D133FD1891B31178FF25D31611A5B7839F0E68EAF0F8901A571E6917C580F31842A9F19C47E0638483B7947DDCD7864660AC2F8B2C430F1E7FC0F22FA51F96F0499332C5AD3FF9DC7F4332DD5BCCA820CC779B90C0F4C5F0CA52E96FAA187361753FBADC5C80D0492CD80A3EEA5D578772DA9FC1C0E10A0203098AF36D0ED2156D7B5CA43
-20151021111833 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B239959D5A7
-20151021112931 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B239A078C1B
-20151021123021 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B239EC676DF
-20151021131523 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23A2B9FC6B
-20151021141029 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23A7BD762B
-20151021143421 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23A9C3EFDF
-20151021144912 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23AB1077AF
-20151021145200 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23AB49943B
-20151021145825 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23ABE06353
-20151021150910 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23ACDA0223
-20151021153131 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23AE91738F
-20151021154038 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23AF40D013
-20151021154300 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23AF75AD97
-20151021155008 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B01C9553
-20151021162240 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B319431B
-20151021162649 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B35A3D2B
-20151021163640 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B439E263
-20151021171004 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B748B983
-20151021172144 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B8609B5B
-20151021173002 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23B9021E9F
-20151021182612 2 6 100 6143 2 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23BE0C1EDB
-20151021190053 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23C120FF97
-20151021192934 2 6 100 6143 5 FD9E6B52785CD7BE64D396A599DA4B97CD0BB49183F932A97694D80CA553354DBC26E77B8A0EC002257AADDF6AD27819CE64A06416E4A80B6EA92F28EA8D5B96C774109EEE5816B4B18F84368D1B41864C11AA73D6881675D779B174F6B4E344303F3EFD11BD7DE468467242372FD00908F296F5A2B20E2684F9122D08A46D647B05E298F0BCDAB60468349CCA6DA1B9FEBBC69D256FB9A3F1980F68466364FCEF1C98C1405191A6737A3627BA7F7313A8A18FC0B8521BF3430B1C6805CB44BCEB39904DD30130D24B225B598ED83C5FD757B80189FD9D5C2F9596687C40BAB1C6ED6244944629849D074A4C33FB15DDB3F9760FC59C44BEBB0EC032177147F61789769DAAAE2123CE488F7ECF19BDA051925BA9ED11EAA72DF70C9ECC8F714B4C35728E6679E66A1B56CCAE0FBBD3F9EBF950D4D623ED78E77CC3AD604E91F304EA78CE876F036214BD6F1977BD04C9ADD707D7A3BCCE87AD5D5A11C95E7025B0EA9C649DCB37942A3970A4FB04C284E4DDB4DC90163353B98B1C254FFD28443353F17A87C02E0BDB9F05424CC44C86309F1D73706F039CDAAC3EDC1A64F38FB42707D351DB5360C2680ADC1CC8D1C4AD312ACC904382C26BE33DA0E61429A5940820356ED28586BEB629ED1521D12D25B4DA01926295F3DA504DC9F431B719AC63277BE675E6F6DD4F7499CA11A23744577D653941963E8DAB610F7F226DB52CE5C683F72AEED2B6CE35ED07C29410397A6F7F606477CCC0EDE18CD0D96A7863BC4606193A8799B5AC1EEE6AC5EE36AC3077EC8DAB30EE94434B45B78BC13D96F74D6C4056EAA528CD3C68D308344808819B12F2BFB95A5C1A7DEEE188BF139216DDB7D757D7A50D3C46CE18881D776D617DCFFAA62276045373AA4D9446D7570338F99C0CA8A08851B4F9D388B4C275D3F9B7BA25F235D4329F63F7457C2EB5C68CE2A96D19766F0ED8E19F66DF3C5E29A38795B2F92291BB6EAB6F70A7E89DC9691F28486E9CF87FF11D5DF2E6B030A30B5D476AD59A34EE7262712ED96CEF4A5CAC3F08B3563D44683F746DA094C9CDB34427AF8D8CC2AE1B23C3BEB637
+20180605163926 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E3790983687163B
+20180605163926 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098369B52F3
+20180605163926 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098369DE513
+20180605163927 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909836B52273
+20180605163928 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909836C20313
+20180605163928 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909836C9430B
+20180605163929 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909836DA8707
+20180605163929 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909836F54DB3
+20180605163930 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E3790983717A4D3
+20180605163931 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098372B4C9F
+20180605163931 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098372F90F3
+20180605163932 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E3790983730E783
+20180605163932 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098373292DF
+20180605163932 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909837356303
+20180605163933 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E3790983743AE7F
+20180605163933 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098375E7EEB
+20180605163934 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098376750E3
+20180605163934 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098376EC6E7
+20180605163936 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909837A659EF
+20180605163936 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909837AD4BE7
+20180605163937 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909837B64E27
+20180605163937 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909837CB4A7F
+20180605163938 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909837DDDCB3
+20180605163939 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909837FC35C3
+20180605163939 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909837FE3CDB
+20180605163939 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098380C0B83
+20180605163940 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909838128533
+20180605163941 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098383338D7
+20180605163941 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909838450DFF
+20180605163942 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909838487D47
+20180605163942 2 6 100 1023 2 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E379098384CCA3B
+20180605163943 2 6 100 1023 5 C3B299C4B84296166548A199E1A643F5D00EC1A3E5DA6FE1B5A710220B66BF9D991130FE7A1060DA60127D185C4B301F3EFA5FAEC709DCFB84237488F5614314D426009C5A78A50E27B73DC5A642B0733CB216C91B3AD172E74D4F756CD11832F97866AA8E7A415D634A657E7433453DDAB0BC3A261CB7AA8E37909838664DEF
+20180605164241 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC0FCBFECB
+20180605164243 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC0FDD64C3
+20180605164247 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC100666A7
+20180605164250 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC1030926F
+20180605164251 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC1032D8C3
+20180605164256 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC1072924B
+20180605164259 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC1090839F
+20180605164301 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC10A234EB
+20180605164306 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC10DFDBF7
+20180605164309 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC10FA17CB
+20180605164310 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC10FE87E7
+20180605164315 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC11409597
+20180605164318 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC116159DF
+20180605164324 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC11AC1B33
+20180605164327 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC11CA3F3F
+20180605164329 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC11DC7E7B
+20180605164333 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC120452BB
+20180605164335 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC121AA82B
+20180605164336 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC12227373
+20180605164339 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC12408E5B
+20180605164343 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC126E985F
+20180605164343 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC1272F6F3
+20180605164345 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC1279FD67
+20180605164346 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC127EDDEB
+20180605164348 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC129DA56B
+20180605164351 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC12BB0F0B
+20180605164353 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC12CF73D7
+20180605164357 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC12FD603B
+20180605164359 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC13089AEF
+20180605164400 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC131627D3
+20180605164406 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC13547C4F
+20180605164412 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC139D9763
+20180605164412 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC13A041BF
+20180605164416 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC13CDD8EB
+20180605164419 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC13ED0BF3
+20180605164420 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC13EDD913
+20180605164421 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC13F9C1AF
+20180605164423 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC14000907
+20180605164424 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC14109807
+20180605164425 2 6 100 1535 2 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC141232B3
+20180605164426 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC14128AC7
+20180605164426 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC1413D4C7
+20180605164429 2 6 100 1535 5 E0EB69B054B239480F217B62FC7CB9CED55EE1B89CD9EBF68FF762B6FD8EE697715C55A255A32B3B41183E78AF4C28DE8614B1C5DF84C88829625BFEF77BA995868888DFD82E49A069338545170AFEC8D2AEFBBEEB4698BCE4E6D7725848B47661F37361EE3FD6FA8BF99E35E35C94729846E60582D00995663AE1C3666B0AB1AFC9316239DC33438FB72AAE7F760CA5D655706DEF44C2D594D01C9F6AB6F7D0F5EA974D6BE256E518A68A0C8902F10BAF2837E295BADC429BA190AC1427B407
+20180605162024 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820A9B6DBF
+20180605162030 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820AB71C5B
+20180605162033 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820ABF82EF
+20180605162036 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820AC82523
+20180605162048 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820B08B40B
+20180605162113 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820B8A5FA7
+20180605162125 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820BC6A33F
+20180605162128 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820BD10B4B
+20180605162138 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820C01495B
+20180605162215 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820CD1DE2B
+20180605162227 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820D0FD0D3
+20180605162248 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820D7E119F
+20180605162307 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820DE78837
+20180605162313 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820E00124F
+20180605162328 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820E52028B
+20180605162338 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820E83722F
+20180605162405 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820F1A3AE7
+20180605162413 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820F3F4EFF
+20180605162422 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820F6C4983
+20180605162445 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820FE667F3
+20180605162448 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA820FF1635F
+20180605162455 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA8210101C4B
+20180605162459 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA82102130B3
+20180605162503 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA821032FD0B
+20180605162512 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA821061CB83
+20180605162520 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA8210880823
+20180605162522 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA82108C26F7
+20180605162526 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA82109CB12F
+20180605162533 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA8210BB232F
+20180605162535 2 6 100 2047 5 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA8210BC312F
+20180605162559 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA82114266EB
+20180605162617 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA8211A7EF93
+20180605162620 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA8211B1F463
+20180605162622 2 6 100 2047 2 EF800DA0F9EB4469B688C23071C58D9878E1174F7E07324B0BEA4FB5AE0346081E6F11059BB476DC4AFA0DB79D5F32F4AEA65DA1C9EFA1D004FB6344054D51F8678127338384A32FA7599F49F761C676A2EC1D98632090FD549A088D67E855D40A0FD5611B97974951E78032484E335157CF6FD3AC75534B5C1C138CD2ADB4E3CDE2592FDA8C14A0518D0BD8D857A7B7E5117D84E5E95EEDD90C495461DE8BF7037A392136050EBC5675E407A54C68F4C2DC1DA6B66541B46A12E3AAC9E6F5CE5CCB18C7986B7D9C54B454627150734D15586B91665FF5268A27F6D5F8AA9353C203D76B419600E6F131159CFABF562B925160B8BD1E6C33CAEDDA8211B2B8CB
+20180605165041 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935413C2A47
+20180605165123 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935418152F7
+20180605165153 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A593541B11757
+20180605165207 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A593541C320AB
+20180605165355 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935428684D7
+20180605165613 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935437F2AFB
+20180605165641 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A593543A9D4DB
+20180605165800 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935442F850B
+20180605165954 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A593544F97433
+20180605170035 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935453BD0D3
+20180605170132 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935459D2583
+20180605170224 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A593545EFFA8B
+20180605170257 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354623E5C3
+20180605170321 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935464932C3
+20180605171004 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935492771BB
+20180605171050 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A593549763053
+20180605171111 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354994174B
+20180605171124 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A593549A3E147
+20180605171332 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354A88895F
+20180605171340 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354A8E5173
+20180605171346 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354A903D4F
+20180605171418 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354AC3192B
+20180605171917 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354CE17653
+20180605172016 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354D459DC7
+20180605172106 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354D9A8CE3
+20180605172258 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354E6015A3
+20180605172334 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354E99359B
+20180605172635 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59354FDAF763
+20180605173053 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A593551AB6C67
+20180605173245 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935527032B7
+20180605173251 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A59355272787B
+20180605173312 2 6 100 3071 2 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A5935529301CB
+20180605173342 2 6 100 3071 5 EB5C4079829C2E1A39E88BFF48E2F94A4304E5198072CB97EACD9E3403E692767F80CC8DF04630FFC8B3DBC8521E6A8BC1E7A8FD54F3F28353F8353A6280C97DFBD87D3E8986FD077076C8CB440B2909EDC327470F92BD8BF35F90C0497C5392271CA0291C1F7E3636F5ED8034AC1CADFDE55B103A3B825A55EE452557FB712D34FB597A9D93DBB11FD12AFC1C2ADC95EC76D90AAC1795734C019804CE6F5922E6131CEEB4995C04277252F2D776AA185252A03451A99F2BE4E51ADC514BA754276FB6C3A9ACB9E2BB474D7F519B5BC56DC00D0D042DC066543F639569F00DD59FC1ADADCDD88FCFF0CDA84B8E7D8A58D77B9A22D2800A91EBE47B9B986AC9498A91E891A55CC17C6A398F04D2A14D30A205DAC8A41A7C33010298CF8FE53D9CC46F2AB136798C548ED9A503C132AD48DB1D038137636039BEB6983AC2EF3F2EF287CAB70F37455E206BF7684C8214191FBFFF447B587A3D94143336A22C1A83B6AB9A7DC2EB1099D04F7B9F4E134FB7A2329CCCE6E0FE73AB9A593552C1A7E7
+20180605174443 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F71BB9EBA7
+20180605175218 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F71D2678A3
+20180605175425 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F71D861ED3
+20180605175901 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F71E5FB7CF
+20180605180343 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F71F3B10EB
+20180605180359 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F71F3EFC3B
+20180605181956 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F7224AFBAB
+20180605182309 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F722DFE397
+20180605182606 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F723682E0F
+20180605183001 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F7241C6B53
+20180605183144 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F72468A833
+20180605183823 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F725A5A94B
+20180605184629 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F7271E9047
+20180605184939 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F727B4FF23
+20180605190534 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F72AAFF2BF
+20180605190753 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F72B14D523
+20180605191340 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F72C1ED923
+20180605191639 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F72CA9B123
+20180605193155 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F72F768B5B
+20180605193341 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F72FC32ECB
+20180605194146 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F73137091B
+20180605194618 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F7320594AB
+20180605194826 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F7326065DF
+20180605194913 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F7327A7273
+20180605195719 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F733F6EE4F
+20180605200053 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F7349A133B
+20180605200209 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F734CDA683
+20180605200404 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F73524AC77
+20180605200812 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F735E21A27
+20180605201507 2 6 100 4095 5 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F737264DFF
+20180605201935 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F737F47113
+20180605202538 2 6 100 4095 2 C99ACF60A371F11C9A02EA6920EA7F8F897742FD159713DE275C9C05059C86D7433F57043C70CC9D33F1E3CE222BB1991703F5F9688AAAF21305A0C263C82CAC5174B2621A318E14B1D7888B5F7ECDD4737101DCEC368A64AB38430AE56C3A6300E36FE8FB57C3619327C62ADC80671F67DC772A9C44EFB266D1120F9B9E7DEE5E3D092D6560D2794BFE19391FF4D11D5860DA7D110F3E13F6503765AA4060394E92F6E4301AEB248BFEA34182444B09732F95AA9B0FAAE1DC295022F1267099DE7E23B50D85585BED875C529FA59D642A09743222FDA04031281D729E9C2E9FC3E22FAE8C1AEA0A0F2FF7EC0C32E9B6B190B71917FFB8949A3ADB771843AE1DD39A3DAE9521CE2D10D2D12584E9289D849DBB9A52C7D990FA52EF786A0CA3D33EEDDD1F7350F501EC0ADAFBCA1B825FE995BF373853AC3FE33E48E728D918FA9A68B0E60F283EC8232B8F00984DB33C8800F9800183709C71F7CD5DF5837799837B473BFDB77E579DD76A2A239BFE09D0E32401B7D784391EEC064DF984E29F5C67F7F039BC8F156407AABD94879B4ABD773DA5506743A2E1AC7A5250ED51DD3D30E2CCC63971F1C72E7F424009884416F869A701C5257E9A6A1580324971575BF2999D37088AFB1B57B6F582007B7927CDE06166F2E500B5AC2C5143E6BE0C1A9AF4FEC2C9F688C86EB7DCB6A2C0F9CF6E4901361CAFC40EC640F7390F0743
+20180606081635 2 6 100 6143 5 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A3819B8FC5F
+20180606083850 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A381B1D13EB
+20180606084353 2 6 100 6143 5 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A381B65B5F7
+20180606090554 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A381CB9AFDB
+20180606092723 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A381E06BDBB
+20180606093241 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A381E51ADE3
+20180606101118 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A3820AE5D83
+20180606101425 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A3820D4A8DB
+20180606103024 2 6 100 6143 5 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A3821C99D9F
+20180606115838 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A3827308863
+20180606121641 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A38284780CB
+20180606121947 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A38286F57DB
+20180606131248 2 6 100 6143 5 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A382B9CA287
+20180606135001 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A382DD37563
+20180606140647 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A382ECDF72B
+20180606143527 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A383086B0F3
+20180606152011 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A38333510EB
+20180606153449 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A3834099ED3
+20180606154730 2 6 100 6143 5 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A3834C6C2F7
+20180606155117 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A3834F7FF83
+20180606191134 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A3840D756E3
+20180606201246 2 6 100 6143 5 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A38446BC09F
+20180606211911 2 6 100 6143 5 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A384849597F
+20180606223301 2 6 100 6143 5 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A384C9296DF
+20180606230821 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A384E995923
+20180607010019 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A38550B3B83
+20180607010449 2 6 100 6143 5 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A385542D20F
+20180607022006 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A3859892A7B
+20180607022905 2 6 100 6143 2 E52412D53049FA1E04E2773DFEC7889C30A4F3D4C3B3F7097EE2AF5389338B19F1A6F05E376AACA05A03716100BA338DA622A68FBE05566BBE6A32410BFAAF78177F712BEEE39DC8282F5E395907F7B7BB12E2A4C5C5E960E3C130C6F47F5A4D3E568D82E2D3A2BCB2BFDBDEA6739C8BB88F694A66EBF24F1AE57EB8C932B4DD9E83E0B400B70670CC4956B5B6E8F386D597FBDD1B7C7835024F002C2D3786B6BB82877959B16A78ED6192602832F6931E0A822D4ED88EB2BFA40234061518AC7E18EA0DF2398E27ECA306532B6155E18477E5A74B005A7A3903F762930F0EAA569B7C50B7502E3D4E4EDB115627DE49BBDED6528FFBBEEBF16D7D3EE29D61B0D5859ABDD8665345D05F7E5DD8FBB170203113333A87502E3E299E90F2D83AF447D67ADA23E77475E0E7416860385EDF12DD59F2576551D9E82457396064EDE8D13BDDF3F40AE591B4A0D3CB0527454EFABC40E629AF3B5A02BDCA06E194A195B13AD319E81915AB1375BB952A0B779040C46C23184962602D70BB0CBA2ED70AB24E2EB08B1BAEFE96D14154FCF1D00461A4D0B7291EC5010678482A136E4B3A4588C80C7AD89189FAA17F29FF4E5D318079EE5C181CC2CF586A6F73114BD85117EB97FE65CC2D2E3441B688C0DBDD11909783227150DF0FEE0946F39E6565285A62CCBF5464D5A518A7D217C6142A31134C0E8A8F401930F3A6979BC35C24275247444FBAAC542AB1280E7B455888F3AD8FE770FF3782DA1A5D76B3C633C40EC2E6A1B0615AF15931D3DD11F98907E0B836B16D5A2E450A97747509EFEB9963BC306A650B3215E1E0FCCEF9F323B56B75D579A8B280D757E2D28D7ABD079E2C0A7FAE800035BD7386E4EB901AA3BE80644720E625195CA36048A7C3514BD0247C37AD92AA3265B496C539B7DE84E39909E982A6D10D177803B0D38E2B80323C1DE7AD104FD5C1D1D631DA6309651C987255308DBE2DF7F4ED233BF6E6C07AD563E6F6FA23E3E9D248135EF83CBC35DB87F39E666F238B8DB06200DCF63EFA84117C2FDF365125604E09D972A32CA03490FD7D81C947C0B278BB2A385A0321EB
+20180607113212 2 6 100 8191 5 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD9285F38A617
+20180607125146 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928617A82F3
+20180607125328 2 6 100 8191 5 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928617CB5DF
+20180607151424 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD92865898703
+20180607154110 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928664CFCC3
+20180607160549 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD92866F6C0D3
+20180607170551 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD92868ADB733
+20180607185631 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD9286BD88C63
+20180607214035 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928707BBADB
+20180607235316 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928743304D3
+20180608011956 2 6 100 8191 5 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928769DD007
+20180608062301 2 6 100 8191 5 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD9287EFA162F
+20180608062621 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD9287F06E163
+20180608091419 2 6 100 8191 5 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD92883A67EDF
+20180608093938 2 6 100 8191 5 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD92884520EDF
+20180608122935 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD92888E78073
+20180608144406 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD9288C8EB5F3
+20180608204615 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928965840CB
+20180608213353 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928979C33F3
+20180608221715 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD92898C4F47B
+20180608230356 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD92899FB78E3
+20180609004940 2 6 100 8191 5 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD9289CC3013F
+20180609041610 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928A235CA2B
+20180609054840 2 6 100 8191 5 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928A49B8067
+20180609133521 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928B0B91E4B
+20180609143811 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928B24E1BF3
+20180609222946 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928BE4C0EC3
+20180610032425 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928C5BA8AFB
+20180610042318 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928C72C452B
+20180610043314 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928C762DC4B
+20180610072715 2 6 100 8191 5 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928CBBDB7BF
+20180610083654 2 6 100 8191 5 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928CD718587
+20180610085444 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928CDD91733
+20180610125906 2 6 100 8191 2 CEC852A0F60D2D7ECA1964A06B30C9C74CED6097183E357235647B360695981BFCA2F828FF22BB22CBCFF24E5B421D02E4169AA216FA977C33943011749067AF3996452BEB9C466CB71DB44802D60450F77A488C2C653115C2DD322D781CB1F4F70CBA60F5030B2569B1147F1EA25872E40326FF2F21D60DDBCC2350883EDF246F9F60D2BED0887D8CD9629A2317C4342785BED83D75765C8CCB9770B156256AB3A3D2F1E5C213BF51DA215802212A3EB18ECA6AFB944D26382E2F314FFB6F83AA2BB057E17BF7BE2604BEFF9BEAF8C72594B5097B97CDE8B4724B7A41816481154886EA99878F7D1570F1365971A237B18B0C048B4E0B550F0E4B84B0AEA8111991ADDB782A2585632E85100B8E6B04048565A70F699A04DF650C7FD138F489FC7B6D5D306FD86902666DA4C2F5259795BAEFA426F391265C2840232DC57DF50093EB6A6BDA2884BE777701953FBA502A233D811A49EBF59241B5931C6DAFC1CF3CFD688E182D8D27FF2CE1CA1D5AB06A44ACF0BAC4A35BF5212955D52AF7FE1F0EED58205C7A08EDF536AB22727C670B56D3F134485D4D4CE3D93883EA07AB900E4B9E1B39B6C19FFACFF664224038B5DE4C97DF0008282E6DDFCB9CAD35CD18FD9EE5EDCE40800E741F5CACAC25CEA9EF53C3B43008FF371EF9453A4E4AB69112C5761E903B5656D7FCA40090A1B26C8670217A2DF0AB05F4E530E1445FB243F2E8376BA169BD46A57EED72BE4395D77F5C595E422DECC125DC9ED0445CC15BC977F7DB6F683A419D862606E8EEC600CB206CDB958E9C98DC23E42BCDAE6560561177C4A119E0C65B22121B127B0A3E4A1D92CB42C297E59EDCD056F32DF3B8BF436785A842414BE3203395703B08EA6DCE4ECFE7831A882C0E0644C9D8C259CBFB3DB05AFCA2669D61D2E12EC3EB7BB105BC96627D239F3009F246CB5312C35420251A92F49C0B4C4B51B5526919C6767A13068A220497DFDEA49FC181F4EA2BAF496AE58E2A924F27F658FE6F7F7E21E26F5BCE5D469ABD9F3F19766051E9352CDB1324388C5DB78A6BD1DC861BE588FFDE7DDFE87F1CB0E9F422BD2B95A1EDC2D65EF9A88F36465053F4611E2B425CA697D4ACB99B5DE6B699495EA2F8F840D4720E40F475D3761432EBAAB46C15F2C251AB9C0AA4FAADEFD40B3C707F7B2A6729E55342F8728D21D263FF204B95407976147B9482170466B718232AA3E82A0C53049C6B2C0884830CEDCD8B9992309BB49BFD6BFD4695B0060540DE388DABC39D732B392F38D433EE0C02BE154DD8A48DB89BD98CB161A63AEEB0D25CC9A29D7C6F3780EA87808E8463E9EE46CBD669FAD39B6BDF75B054951784154BAB9C0BC554F30258AC6B39D72A492C027EE8955704E44414DF957398A9A0DA9005E6B152930F7A71AEEAAF2543947A773545E7A8B0B9C13F0CCAD928D3DBCC1B
20151021113847 2 6 100 8191 2 DC61EF13E4F3FC10CC946EEABC33F83EFCB35E0F47E4EC25C1CCBB2C7B502B2EFB0691AA231C8476DD51BA73204E6EA10B1A970FE2CF14AF01E72E1AEA87519A91D00D1499189F94A6CDA9E29C05F11F17FE74A4919A710A2787E180744465DF81C62AA65662FDA46FA6175E8A31E5B29E66DED6701C8FC4217E91D733FE94380F046680967D4CEA7BAC8F3916CDF96AA2C474FAD9650F48403FD0B5B756D34667D36A07767FA33027AE55484D0F701C3CA16632F413A14E4B8645AFAF15B78978C19A7661EDC569BEC72394B1204B166A48FCD5F56BE29840C7794CA6D3440356F15858CDCA9B429C7EA92E17242893FDC8C9C63841A382C32F20CFAB121B4BCAFD7BF9EF07FBF7CDFFECA0CEF3A49C3E2B24FA836F3318435255655E1B281071F62D5E4CD63361299B7828F72936E3FEA9E8044562A6F6ADD5321187C3101E4669C6271598FE1A866C93FE2870A4CEB9254BA32A4719E439317EA42200A335B5CFFA7946A7D0F1BD1A69AA11288B73C71C80B77FE3707CB077DDDEA5CA36A449FAB230C9625A0B12F8275D3FF82F5DA380E7A3F11B6F155FE7E91AC960BD95D9B13F7423AB9B15CC3C4DC34EF296033F009468EA16A721AD659F56C18516025050749ABF05E6D3EBD9778142A530979291F46DAA399A86B7BCDF09CC3E6EEF101419762A306DB45AEFC96C64E83F28338D55905F6A387E0F515E580C3A9B35330E21C32198CDEE3AFB355967A098F635FCA7C49CB4E1E82464B2B390EF1F259E40B9A06235C0273F76284FE6BD534EF3AF7CB01A4A5252B8B94CADC2850B2E56D53F9A31D7C029DF967D0A30C05BC64E119BED6076818FABC8CDD93F3255693E14EFC1A740A5D63A5E847FFE87BAB1DDE0506E1762EA61EFA9F9756151ECCCADD91B98A961A901A2D8B01ABDDD29EC804E8C8D28214BBA26048F924CA66316696E51A49D02FF034D20E44914B1115339CAD3819E0CB1640F0084886FEDDE5E28C29DC48ED30A8C3D789734338F5A9DF42584326E536FD1CF30BC85B8DCBD6120D127C98FE4B3614074F13C2CA4854E6D794156C185C40EB3DA7619CE96ADAF0941BD5499848B034C2B11DFECC0BDFA81C594241F759EF53FC7CDE7F2DE4F23CF81A5A0B7D62E31DABB9198D40307F7824DD130B7D1B80E9B6D322FEEDB5ACE34944F0BFB7D016762A9B2E173BFDD69303766AFBAB45FAB75D05430B4A3515858C4B7F04E23414E4AD03842CB0A20D8FF4B59B7C852BA9A5BE982A8ADA5CB70C36CE2A4D2C31A7015C9F3275E43D192C1B2924424088907A057DA7F2D32A2149922AB2E33F2147D637A3508911CB3FEA5E1AAB4525BACF27B6DD7A3E0AFA978FC3A39DE8882FB22688C3CCC92B6E69ACB0BBF575AB3368E51A2F6A20C414C6F146727CC0045F29061E695D29F7C030CE6929EB3AD11A5CBD0CDEE37347869A3
20151021133636 2 6 100 8191 2 DC61EF13E4F3FC10CC946EEABC33F83EFCB35E0F47E4EC25C1CCBB2C7B502B2EFB0691AA231C8476DD51BA73204E6EA10B1A970FE2CF14AF01E72E1AEA87519A91D00D1499189F94A6CDA9E29C05F11F17FE74A4919A710A2787E180744465DF81C62AA65662FDA46FA6175E8A31E5B29E66DED6701C8FC4217E91D733FE94380F046680967D4CEA7BAC8F3916CDF96AA2C474FAD9650F48403FD0B5B756D34667D36A07767FA33027AE55484D0F701C3CA16632F413A14E4B8645AFAF15B78978C19A7661EDC569BEC72394B1204B166A48FCD5F56BE29840C7794CA6D3440356F15858CDCA9B429C7EA92E17242893FDC8C9C63841A382C32F20CFAB121B4BCAFD7BF9EF07FBF7CDFFECA0CEF3A49C3E2B24FA836F3318435255655E1B281071F62D5E4CD63361299B7828F72936E3FEA9E8044562A6F6ADD5321187C3101E4669C6271598FE1A866C93FE2870A4CEB9254BA32A4719E439317EA42200A335B5CFFA7946A7D0F1BD1A69AA11288B73C71C80B77FE3707CB077DDDEA5CA36A449FAB230C9625A0B12F8275D3FF82F5DA380E7A3F11B6F155FE7E91AC960BD95D9B13F7423AB9B15CC3C4DC34EF296033F009468EA16A721AD659F56C18516025050749ABF05E6D3EBD9778142A530979291F46DAA399A86B7BCDF09CC3E6EEF101419762A306DB45AEFC96C64E83F28338D55905F6A387E0F515E580C3A9B35330E21C32198CDEE3AFB355967A098F635FCA7C49CB4E1E82464B2B390EF1F259E40B9A06235C0273F76284FE6BD534EF3AF7CB01A4A5252B8B94CADC2850B2E56D53F9A31D7C029DF967D0A30C05BC64E119BED6076818FABC8CDD93F3255693E14EFC1A740A5D63A5E847FFE87BAB1DDE0506E1762EA61EFA9F9756151ECCCADD91B98A961A901A2D8B01ABDDD29EC804E8C8D28214BBA26048F924CA66316696E51A49D02FF034D20E44914B1115339CAD3819E0CB1640F0084886FEDDE5E28C29DC48ED30A8C3D789734338F5A9DF42584326E536FD1CF30BC85B8DCBD6120D127C98FE4B3614074F13C2CA4854E6D794156C185C40EB3DA7619CE96ADAF0941BD5499848B034C2B11DFECC0BDFA81C594241F759EF53FC7CDE7F2DE4F23CF81A5A0B7D62E31DABB9198D40307F7824DD130B7D1B80E9B6D322FEEDB5ACE34944F0BFB7D016762A9B2E173BFDD69303766AFBAB45FAB75D05430B4A3515858C4B7F04E23414E4AD03842CB0A20D8FF4B59B7C852BA9A5BE982A8ADA5CB70C36CE2A4D2C31A7015C9F3275E43D192C1B2924424088907A057DA7F2D32A2149922AB2E33F2147D637A3508911CB3FEA5E1AAB4525BACF27B6DD7A3E0AFA978FC3A39DE8882FB22688C3CCC92B6E69ACB0BBF575AB3368E51A2F6A20C414C6F146727CC0045F29061E695D29F7C030CE6929EB3AD11A5CBD0CDEE373914ECA3
-20151021140108 2 6 100 8191 5 DC61EF13E4F3FC10CC946EEABC33F83EFCB35E0F47E4EC25C1CCBB2C7B502B2EFB0691AA231C8476DD51BA73204E6EA10B1A970FE2CF14AF01E72E1AEA87519A91D00D1499189F94A6CDA9E29C05F11F17FE74A4919A710A2787E180744465DF81C62AA65662FDA46FA6175E8A31E5B29E66DED6701C8FC4217E91D733FE94380F046680967D4CEA7BAC8F3916CDF96AA2C474FAD9650F48403FD0B5B756D34667D36A07767FA33027AE55484D0F701C3CA16632F413A14E4B8645AFAF15B78978C19A7661EDC569BEC72394B1204B166A48FCD5F56BE29840C7794CA6D3440356F15858CDCA9B429C7EA92E17242893FDC8C9C63841A382C32F20CFAB121B4BCAFD7BF9EF07FBF7CDFFECA0CEF3A49C3E2B24FA836F3318435255655E1B281071F62D5E4CD63361299B7828F72936E3FEA9E8044562A6F6ADD5321187C3101E4669C6271598FE1A866C93FE2870A4CEB9254BA32A4719E439317EA42200A335B5CFFA7946A7D0F1BD1A69AA11288B73C71C80B77FE3707CB077DDDEA5CA36A449FAB230C9625A0B12F8275D3FF82F5DA380E7A3F11B6F155FE7E91AC960BD95D9B13F7423AB9B15CC3C4DC34EF296033F009468EA16A721AD659F56C18516025050749ABF05E6D3EBD9778142A530979291F46DAA399A86B7BCDF09CC3E6EEF101419762A306DB45AEFC96C64E83F28338D55905F6A387E0F515E580C3A9B35330E21C32198CDEE3AFB355967A098F635FCA7C49CB4E1E82464B2B390EF1F259E40B9A06235C0273F76284FE6BD534EF3AF7CB01A4A5252B8B94CADC2850B2E56D53F9A31D7C029DF967D0A30C05BC64E119BED6076818FABC8CDD93F3255693E14EFC1A740A5D63A5E847FFE87BAB1DDE0506E1762EA61EFA9F9756151ECCCADD91B98A961A901A2D8B01ABDDD29EC804E8C8D28214BBA26048F924CA66316696E51A49D02FF034D20E44914B1115339CAD3819E0CB1640F0084886FEDDE5E28C29DC48ED30A8C3D789734338F5A9DF42584326E536FD1CF30BC85B8DCBD6120D127C98FE4B3614074F13C2CA4854E6D794156C185C40EB3DA7619CE96ADAF0941BD5499848B034C2B11DFECC0BDFA81C594241F759EF53FC7CDE7F2DE4F23CF81A5A0B7D62E31DABB9198D40307F7824DD130B7D1B80E9B6D322FEEDB5ACE34944F0BFB7D016762A9B2E173BFDD69303766AFBAB45FAB75D05430B4A3515858C4B7F04E23414E4AD03842CB0A20D8FF4B59B7C852BA9A5BE982A8ADA5CB70C36CE2A4D2C31A7015C9F3275E43D192C1B2924424088907A057DA7F2D32A2149922AB2E33F2147D637A3508911CB3FEA5E1AAB4525BACF27B6DD7A3E0AFA978FC3A39DE8882FB22688C3CCC92B6E69ACB0BBF575AB3368E51A2F6A20C414C6F146727CC0045F29061E695D29F7C030CE6929EB3AD11A5CBD0CDEE373A17959F
+b20151021140108 2 6 100 8191 5 DC61EF13E4F3FC10CC946EEABC33F83EFCB35E0F47E4EC25C1CCBB2C7B502B2EFB0691AA231C8476DD51BA73204E6EA10B1A970FE2CF14AF01E72E1AEA87519A91D00D1499189F94A6CDA9E29C05F11F17FE74A4919A710A2787E180744465DF81C62AA65662FDA46FA6175E8A31E5B29E66DED6701C8FC4217E91D733FE94380F046680967D4CEA7BAC8F3916CDF96AA2C474FAD9650F48403FD0B5B756D34667D36A07767FA33027AE55484D0F701C3CA16632F413A14E4B8645AFAF15B78978C19A7661EDC569BEC72394B1204B166A48FCD5F56BE29840C7794CA6D3440356F15858CDCA9B429C7EA92E17242893FDC8C9C63841A382C32F20CFAB121B4BCAFD7BF9EF07FBF7CDFFECA0CEF3A49C3E2B24FA836F3318435255655E1B281071F62D5E4CD63361299B7828F72936E3FEA9E8044562A6F6ADD5321187C3101E4669C6271598FE1A866C93FE2870A4CEB9254BA32A4719E439317EA42200A335B5CFFA7946A7D0F1BD1A69AA11288B73C71C80B77FE3707CB077DDDEA5CA36A449FAB230C9625A0B12F8275D3FF82F5DA380E7A3F11B6F155FE7E91AC960BD95D9B13F7423AB9B15CC3C4DC34EF296033F009468EA16A721AD659F56C18516025050749ABF05E6D3EBD9778142A530979291F46DAA399A86B7BCDF09CC3E6EEF101419762A306DB45AEFC96C64E83F28338D55905F6A387E0F515E580C3A9B35330E21C32198CDEE3AFB355967A098F635FCA7C49CB4E1E82464B2B390EF1F259E40B9A06235C0273F76284FE6BD534EF3AF7CB01A4A5252B8B94CADC2850B2E56D53F9A31D7C029DF967D0A30C05BC64E119BED6076818FABC8CDD93F3255693E14EFC1A740A5D63A5E847FFE87BAB1DDE0506E1762EA61EFA9F9756151ECCCADD91B98A961A901A2D8B01ABDDD29EC804E8C8D28214BBA26048F924CA66316696E51A49D02FF034D20E44914B1115339CAD3819E0CB1640F0084886FEDDE5E28C29DC48ED30A8C3D789734338F5A9DF42584326E536FD1CF30BC85B8DCBD6120D127C98FE4B3614074F13C2CA4854E6D794156C185C40EB3DA7619CE96ADAF0941BD5499848B034C2B11DFECC0BDFA81C594241F759EF53FC7CDE7F2DE4F23CF81A5A0B7D62E31DABB9198D40307F7824DD130B7D1B80E9B6D322FEEDB5ACE34944F0BFB7D016762A9B2E173BFDD69303766AFBAB45FAB75D05430B4A3515858C4B7F04E23414E4AD03842CB0A20D8FF4B59B7C852BA9A5BE982A8ADA5CB70C36CE2A4D2C31A7015C9F3275E43D192C1B2924424088907A057DA7F2D32A2149922AB2E33F2147D637A3508911CB3FEA5E1AAB4525BACF27B6DD7A3E0AFA978FC3A39DE8882FB22688C3CCC92B6E69ACB0BBF575AB3368E51A2F6A20C414C6F146727CC0045F29061E695D29F7C030CE6929EB3AD11A5CBD0CDEE373A17959F
diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl
index c0d7b9be8e..61a1239d26 100644
--- a/lib/public_key/src/pubkey_cert.erl
+++ b/lib/public_key/src/pubkey_cert.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/public_key/src/pubkey_crl.erl b/lib/public_key/src/pubkey_crl.erl
index 3621e9c0da..50abd704de 100644
--- a/lib/public_key/src/pubkey_crl.erl
+++ b/lib/public_key/src/pubkey_crl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/public_key/src/pubkey_moduli.hrl b/lib/public_key/src/pubkey_moduli.hrl
index e4beecc12a..768db624c7 100644
--- a/lib/public_key/src/pubkey_moduli.hrl
+++ b/lib/public_key/src/pubkey_moduli.hrl
@@ -1,395 +1,489 @@
-define(dh_default_groups,
[{1023,
[{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840821904219},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016037066299},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840822843699},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016038392563},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840824293227},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016038561043},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840824411619},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016040084083},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840826770579},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016040928019},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840829698867},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016041403147},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840831699579},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016044289459},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840831788499},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016046539987},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840835116819},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016048107763},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840838791147},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016048195459},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840839741403},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016048489219},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840843908763},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016051183339},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840844149459},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016051761379},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840846037779},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016059530419},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840846316347},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016061519299},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840848087763},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016061652187},
{2,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840851778483},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016062557059},
+ {2,
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016062981427},
+ {2,
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016066800187},
+ {5,
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016042534663},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840818511543},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016047828127},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840819546447},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016048304863},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840820698807},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016049426047},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840821875983},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016052250343},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840822182367},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016055892463},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840823493823},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016056347623},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840828115623},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016056938023},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840833652783},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016058313343},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840844852263},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016065124567},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840849785943},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016066293247},
{5,
- 145775197456487668749161655795234893413202527697104473695831577761647854852108768430387864189919819365658842431613137268371680467610991509847733954019734973873643148023271112285230508466838215139872267855676600969961870846186166681894080056503367717025795010132090088184706677576861830882312093982840849803727}]},
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016066518343},
+ {5,
+ 137423569441246262992289626302405506810075372518201635033473127540045433614984773406065519964899878780586235832348933590594300290793347611716697640359482924853366011641117770719027755146909495326369377183195861495553717174988136205384838926110458474346294939275424613035724229598089601829380531182016068472303}]},
{1535,
[{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891121581459},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789627621067},
+ {2,
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789628761283},
+ {2,
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789634361539},
+ {2,
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789638537803},
+ {2,
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789641659627},
+ {2,
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789647419339},
+ {2,
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789659085619},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891123347643},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789662256763},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891123353283},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789664867003},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891124232763},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789666330667},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891131462067},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789666841459},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891135933003},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789668814427},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891136255299},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789672118003},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891137177907},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789672898027},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891139347603},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789674915179},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891152305467},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789676842763},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891159084867},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789681188923},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891161343219},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789682812883},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891172563627},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789691688803},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891174672243},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789694851307},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891180467739},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789696895987},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891185564427},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789696948499},
{2,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891189869307},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789699330739},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891119456223},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789631448743},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891124590423},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789634212463},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891130908327},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789640500127},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891131873727},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789645700087},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891135211407},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789647710183},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891143426247},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789652039063},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891143747007},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789654186463},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891146699103},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789661060927},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891150054447},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789671831647},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891155995647},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789672578407},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891157019487},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789678179287},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891159178863},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789681924847},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891161250063},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789686897743},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891170145447},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789691863487},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891171171087},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789697728943},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891172350063},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789698140423},
{5,
- 1907170736023124811736411458785042542925115668082539810200109305735683587893811083066646767750558659131374424885053147631157680241645866111036024727506041045267916677127337026486727329498794109266986160904622741269220273376068857149157352410555723198695322554668593076155279812272319710239217381596287633268687131658367273821116604691564975255858007378139664922713363377579390448226123206847441877045380881530736814422784905045609836858066127174749699891176092263}]},
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789699225607},
+ {5,
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789699353287},
+ {5,
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789699437767},
+ {5,
+ 2117681492913321569697017096248004964074655225855064803226626530973545674132063479305336653601343613581681296068799225967217443469822913599882869070603558288530230411228882956187328693299502078948089815664109460010482204163236896700745132726891852191217183972837285242539058483051590799983736242396087464474074677177065221920708495653383923226837547541111948031363494948381073214833218893715532814018571166368347836868668692007351599237524270407572667789700740103}]},
{2047,
[{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127673160083},
- {2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127674746147},
- {2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127677513587},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074755345499},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127677855803},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074756461859},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127681703483},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074760692747},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127691773067},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074773822283},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127693199747},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074776983899},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127694475899},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074790653483},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127702886939},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074794713299},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127707613619},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074815828619},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127713247667},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074834327939},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127727962403},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074842331123},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127729070603},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074845064267},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127741606979},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074846183603},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127745340899},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074847350027},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127764392459},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074850417539},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127764820307},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074852923427},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127771318403},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074865137387},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127781167379},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074871791507},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127782355883},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074872448099},
{2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127782887579},
- {2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127787746619},
- {2,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127789102259},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074872498379},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127666983407},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074753531327},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127675200023},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074755896047},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127687609343},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074769190823},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127691690063},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074773140287},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127708300823},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074801938847},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127712140847},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074808850487},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127715948087},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074810458703},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127717449983},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074819068463},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127717581887},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074828950247},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127725119327},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074831380223},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127735619543},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074843050847},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127776932207},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074853193463},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127788684623},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074854277423},
{5,
- 31232761562882516094884070611630050950237146275890833609093891047897843797997552232718257871173954549538774751038496595396925563385404720255716837933677220581287383288516914691172469244029925326629700819138694871356510866851914242889526314963319760427147424913618697965734069376105953045113129440174661252504850768513753786509136822851125652952326518541742866669959696723616260017966174003560432807987735744247115916855658422620715728754034819398357826714599804921184478793666674492366199879602022266103884178166633701002913239714329019644011011091883511432521179210877235289776043130356321939953141370575127790955767}]},
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074856272687},
+ {5,
+ 30234100291786660119150592253986164718868634461318049072554515332884967674928782249469681512369934810827458855581922926809556244370595605788701190647548919395621435148266404705314169286338735491330335839065308771794695863455361843400123918598469633373229888515556903041476081665517841329650690706907312078385023867825976012891153434200817912196296808624612663609473822637069014486910713969827270391274088701875401022668082592335250640966918882542262485103727016143768199802712794462461532704087012779665855118715263701391361266921229205676528586338993875313766674367990445223648968867957230166128407903969074856341807}]},
{3071,
[{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199506260163},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289461870763},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199530244827},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289490971387},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199578944619},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289493767387},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199589988939},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289502528779},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199594013379},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289515762739},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199601609043},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289520111827},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199604230203},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289526490499},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199606755099},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289531918987},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199618079787},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289535321539},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199653718659},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289537766083},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199657776483},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289585885627},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199707657579},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289591046227},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199722711699},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289593005899},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199743456099},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289609404787},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199785339603},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289612863787},
{2,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199797260499},
- {5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199507581927},
- {5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199510208343},
- {5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199537327623},
- {5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199551703167},
- {5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199617722127},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289648408147},
+ {2,
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289660538083},
+ {2,
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289673483683},
+ {2,
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289677227419},
+ {2,
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289698314083},
+ {2,
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289741797499},
+ {2,
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289743929803},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199621084383},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289453025863},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199634824407},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289457558263},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199642326807},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289460688727},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199665149823},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289474675927},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199708695087},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289594040647},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199765825887},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289609025887},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199767685887},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289609530703},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199773947727},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289654971847},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199780743543},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289728752743},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199786221207},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289741648567},
{5,
- 5436771231278176260464207572014249237436628003751950430443256176419437109283409279325055179822137303309588375578210454771206339795059466564724705882357808020147943371370952376862400031959913112146741735409727429098983569717815170493079969998376532776669142518838712137720503257349411673630616846814922326748760377074686267404617800626017790893617723327526800481821613452766006640701474488365374399399907853664959711238779541522615905232982411502798277910194792404145749492189947629774082615011566526902465295439792626194825661087612449173617161800099003448528272624654517679417559537997833575275437573873218238645979906696208545848771753496507149936213366692226040978858284500769836334638725943292501159483097128028975365907974867494222456802766986272374880246378778326493320216426233834650917807239104899121676291950634433590565261175675893968032464664959347175273331523630462401583678513811133107339834284448366199798706967}]},
+ 5341214654634261952873757181561533451707821361473790513564315292835421225907290979705658514768610744229080270038566630873421837799494130654470818355524260427309266809137559455752156841542079285699912382198438256477191140483659741554623458276984132571490005422487391200312212866133415680909716507907845827994683552282075519283183306400978216170683966125586514167935144707307129515552296413428393454073134896115280919323970931969859738752463628375871247541392539129483603011834938988123237171126084442161006950491163910976429369302209546222425310901643650474858404742396613584660709357575219554168390865409561609082174871377547770444430973616557924010418332760953296455735166542214510320276939683699294586632574638203802976903133684878674504505778352407591179548498641812857848247717199756967280188814464938382873930435957699864919392905570032937866615892011156011915598355499435483769756567649481438043557349653592289746986983}]},
{4095,
[{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328641094123},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908261488803},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328654189387},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908267757267},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328663242883},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908296392939},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328715041723},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908296649787},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328717604779},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908347767723},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328805204587},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908378270547},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328806565843},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908383266867},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328807451707},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908404042059},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328836115507},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908438601507},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328845968059},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908495213859},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328887178459},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908512647459},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328908234163},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908521746723},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328948166083},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908568726363},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328954136203},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908573748939},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328963052323},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908598118683},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329023777723},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908611654827},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329047093003},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908619313779},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329058480379},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908654940987},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329090057419},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908658321027},
{2,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329132001859},
- {5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328685618887},
- {5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328733393407},
- {5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328804704703},
- {5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328808160607},
- {5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328817663383},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908711194899},
+ {2,
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908729714499},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328826409727},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908237597607},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328842353143},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908282017743},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328915670167},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908357526423},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328928173423},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908366458383},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328936548223},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908428742727},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328945813063},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908488602303},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328955100607},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908617606623},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328983302407},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908644249167},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024328995176167},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908664024183},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329021303887},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908676438567},
{5,
- 818034524162384276004384029858643530286875094391273833506734966261806257117433972760379103507630310628953496150318170372254219924175532996281953750642804369831900894594960807970232131410638888573275563720690293481410915588408505771183615664441221559618326229227448328879290185035795866796496147000467456347856187771645103733376761936369144682074588463621004219054111244232031965820058057143484947957179035662640791007685559024477920075136419228662974090561346329074935312181886940693299380892129818458511403741106419480550004799657220331973244248753744516935739033770420884365608406478656143540532371463443324228730693491647103274058971797182813283112583029849186056551355376851686616057869624968077484471229044125401535456699914745876082047459812392122562460031611344154642406382436701361983114768023990405077450124649862159757605118611426368650203370143674925598905779061402007525955196464201496773278952462368223659263492419274489020447849336502432222101793313731259141617677580646998184158969477474527427664187763741360356528830301163614618231141541403007931347398186427059736520580903587497382362610721261644208653717495736748724114113311672504064943864203789205551568648546606356374830209356446449765364678719909024329064403567}]},
+ 822475527894530229285616572113840248471252289865654730245673569989009517195150670386319918731764341482939973599599030444586627098726805325532602670776492782830517765627499389443537251148551632924278584658894256392558800578282770783952781444172123021909239761249266774011128112210797775865561188225245937456884457382356013600801136212313898917668235824265001348217562305609115401999529744566651634335823205650035802368807460021617740974817291658859354863897470423588038163002057414285871641295222833687523714538475514552855242579151518676338365048493158502050812316214163484509139051517638342109175849018785568945149403656833584359154601084850728291664155244903363511084332084337961858034913924653425899617872300974717518876133738228463402736897605365573279650828581423928774933880146466418294504197525108110672457161289146815032997391965470390378909910135534473119298720916725046763262261767220808960157446815529871730997078479389353851235418277521225090118250855917746026804319123727978865815215602336860198597431012309304151978584224046103750860062629864591763945976315990671793648388266723695721279940197843205282458713913995036945430630152450677414407385229033726976302905725696701985169880658807635234608315361840320908697685503}]},
{6143,
[{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255204878912539},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066212697067},
+ {2,
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066239737819},
+ {2,
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066261564859},
+ {2,
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066266476003},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205024824427},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066306104707},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205108938283},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066308614363},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205168452667},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066415298659},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205178336083},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066433581259},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205194695203},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066436192219},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205234987027},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066526639459},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205249389907},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066543056683},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205299503899},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066571940083},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205303762219},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066616922347},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205318419043},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066630852307},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205369723267},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066646474627},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205388065627},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066845660899},
{2,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205483192027},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104067076479267},
+ {2,
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104067184606083},
+ {2,
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104067259968123},
+ {2,
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104067267961323},
{5,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255204867528103},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066189360223},
{5,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255204958533343},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066217457143},
{5,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205142917087},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066324667807},
{5,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205164709807},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066489492103},
{5,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205223494543},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066643247863},
{5,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205238451607},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066905718943},
{5,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205398650527},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104066970573183},
{5,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205534891927},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104067042481887},
{5,
- 33437583241773200736998306224385528803766612787425393970240448895665693432965804079937003812356294308539203151272072972277375104789647202046031197278230667153631409232762771720006125219920706956123725594446372009116332714804701277193618508630316668034287884909832516041233220775901611206642660372233947390606274902141826658826141733970432621047550484555565916575805826057191334266474445170275718783081560666447409216535181360674632456526571101451968821169633558969474691730611539132286052022835952896201555123627380799302110683026529909820807288537680562845821392314996440379370705723540964585839337801927778062852215686895319024767481042895138442976855163068747380166531199300232551267526017036164413600564815784019785977970949693984340717238729942561030179919817420833573731051545887599723662578148436252999801801184946912344055039296858955344284666098693644023712197329293309829111260795234865981993976990661827891668714260305572784933890804266304027991177237933956448650403587826112875783795940606993503972135788451776288043780405914188427059396997568948159052168252857826777287128664074216861215783789478700515409553239441062015685435438583826256963919799489374587339208720501219592669600392307850331252795823771544828155101319705650241344450112892458324477254048023146580514471110326358407290566960742849415447980366665653434043627949138890739742819993505594819520369919793246819138042045825632762369551350013672323292476735446079801969860131404566127284762569608997426987715169971180098109830736446816299192620247945607493820377482306775990092969824710142555863464957556013639252952281232650874597306442373552573476420189325342908686488322042941568296395918651660523487617863085692837653979094810691084612642444899086069505869007138363971482049103042831515780578797971864682660432869186605371682266108433970938695484953644215301255205578782263}]},
+ 30210369155779651888589832154992934074138507220822617750684652871127582962409899985645946445695043253195686248244998571402305199678770384280564307485035486218800068429843963439425551779021865465473175487387006425679517736862515996424867831461548685177440883895142510892080386024242790580351718476912346064665887342021801124592374644199240055614707801951400286738571835106941459565263538011604632591754698655670731747906958754306695890917250845082935314433013066321817795811216868330076422883334026288452966305998174700518168814979477732850177021088448137305837683404856702535774772361477172629825124721712806311678193131143271354379844514551970600366748790881625770009341628054007754553253798271412759265676226769394213651014204828629926952929904315923670432908575989917617637701451215022415020602741724294119817098286839062394376589141071497906909592069997336204239169602926838746847024777759842015748321319275357899423502183072151966760234482986263033779816032715802142058060420345923767082809675434739360245514122590144988299733345731573144371526046690587022732405227784184600940160738238518293781021765582962691631713434222022562950296250509633938674749281309291074381760671163336862668582157228513024763628253337784730104842959368278069041285218519766922739574404159050610285845118633942864745158438604557438873320358729699870593735296129291292133537433344339822168319576836729204869998368045864710009464349668393627057504172016907834801787571594303040666608785976162184230007930556331766254151014073812956419139773303370139752142739047952426344593274617190212675329544654619143794215577626176639637678757668518842586496846866347512471156638951909845841212416559374312458890749201523393740959899515314744619218832833815902335851353279396321673115498490049357132026679171719767095122045794337383943188601986364730890641872503895354104067188249103}]},
{8191,
[{2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408345391859},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408413484803},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408426294467},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408437420243},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408466188083},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408519326819},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408597129947},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408659473619},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408841130339},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409006846067},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409068135923},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409232339147},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409253569523},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409273017467},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409293367523},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409431407147},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409674894923},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409701436403},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409902628547},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645410027309819},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645410051540267},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645410055117899},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645410163529523},
+ {2,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645410264370203},
+ {2,
938991641448887958659860711024139841840373070892857314837350127283993531354468803860225599873491818506054401963417489724433963777795696041544477412963807403300832656512849715212168703537706302853428971073305304224008208665300028518281475780493382070018498379488833882168221853720545474425047940975435356027594634176129712250061883354535324982741923143373986406603949677080360223989497048086447454366625852264609369284140522273595340921542019308988041920995057608746115976973659704188342646944998285431473302075966106608530908140377765357842459486869512398523240695806503711124427370056638597159539032058092571318621818616699716647464298881944582194013388150591419588422793657857267906072494480713650129757905856314362270238621284311461743652666256381611674809565144562467655186251867429369336740018623120262859220669942243740953355278814789244133782043857008487446798345197999966787658254507117076710455244182794239065255535191498857182705725985655379455993825553257619502588673174759329362518373537685585117537004065137523099625519490356398330532110250061129576411957409731201790054967354938147031111368166150009421041430118523249245874882140875551501824754839814848195806919150975076831338899823813371473496616326897054534509843640848822974414341233324307292275820287661792887177523563243279340678632061899626115667671047274195425889742755327012266774742591229119994211561599405909368902449776535330722644597809098307346948888547387746758109319767106289995123864514603259977184876246412673772519845777697496361969177346826245108557971745523905955370437517039028495325595180934057507336816903052766590118820327869839202378278312909402987412274414739124292902164277499512007446916921747463997761815820546816791093343347969046462095463611789365326128045878985464594892022442144072282717352526544915821855299863549245012366815543939396712522935345161074836470227392836664033041735035699615758782980717425699108612161567924880267630103820215946940542401779795959759774248414245436455737309858403883625882609790799283421857564831362243562647683958370353023343221966296655134926556805244483888769178095889844741765908328185625663202823312608064683035802724504683124396450612201783060593269112984065572954508643688374585823409316161924407053191442613988480926581084892323451281350937867676271858142177713557970909833234285545964647506859724327822527317869059455132036566677244407755994867168874825546516623190701762311472512591018622127119388239627852234680483324150442403},
{2,
938991641448887958659860711024139841840373070892857314837350127283993531354468803860225599873491818506054401963417489724433963777795696041544477412963807403300832656512849715212168703537706302853428971073305304224008208665300028518281475780493382070018498379488833882168221853720545474425047940975435356027594634176129712250061883354535324982741923143373986406603949677080360223989497048086447454366625852264609369284140522273595340921542019308988041920995057608746115976973659704188342646944998285431473302075966106608530908140377765357842459486869512398523240695806503711124427370056638597159539032058092571318621818616699716647464298881944582194013388150591419588422793657857267906072494480713650129757905856314362270238621284311461743652666256381611674809565144562467655186251867429369336740018623120262859220669942243740953355278814789244133782043857008487446798345197999966787658254507117076710455244182794239065255535191498857182705725985655379455993825553257619502588673174759329362518373537685585117537004065137523099625519490356398330532110250061129576411957409731201790054967354938147031111368166150009421041430118523249245874882140875551501824754839814848195806919150975076831338899823813371473496616326897054534509843640848822974414341233324307292275820287661792887177523563243279340678632061899626115667671047274195425889742755327012266774742591229119994211561599405909368902449776535330722644597809098307346948888547387746758109319767106289995123864514603259977184876246412673772519845777697496361969177346826245108557971745523905955370437517039028495325595180934057507336816903052766590118820327869839202378278312909402987412274414739124292902164277499512007446916921747463997761815820546816791093343347969046462095463611789365326128045878985464594892022442144072282717352526544915821855299863549245012366815543939396712522935345161074836470227392836664033041735035699615758782980717425699108612161567924880267630103820215946940542401779795959759774248414245436455737309858403883625882609790799283421857564831362243562647683958370353023343221966296655134926556805244483888769178095889844741765908328185625663202823312608064683035802724504683124396450612201783060593269112984065572954508643688374585823409316161924407053191442613988480926581084892323451281350937867676271858142177713557970909833234285545964647506859724327822527317869059455132036566677244407755994867168874825546516623190701762311472512591018622127119388239627852234680483324227808419},
{5,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408307521047},
+ {5,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408345535967},
+ {5,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408700026887},
+ {5,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408840291887},
+ {5,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408918699743},
+ {5,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645408929943263},
+ {5,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409339998527},
+ {5,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645409471627367},
+ {5,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645410128181183},
+ {5,
+ 881045461522943321086778073300940478556218355297969911976909161486894133662493726399243167458009140047097403832005558428608022057031977203602474613009545091720237343240266129021712322298408144531017770778248716957128799297677903712279084392023819163463966227515269649827380536523405101157732109499388260769586116300288304982677621782718749987230168262305655004727816729815800533511307474309647349575475321354016095742812539133151602748038504759763440423033004809780519532557484323246180020130950200646945418165013898390018998574383185461948128020544881733962825915669056546421700831605194278745248581382984298520377716141327298492058956203175900776169162131066555283318461828456520694888875026876615176999234594065729624240200260702661257238500249077130700729314922467706084046564196655345340394880604121971434682608173172839952354536660137326680056370043971462309932399249681084807535691908014774608948539576573091871838175518964071111240660427603031489552613754601246540211425394120613055590993731825013169587667380928210308207859749014992608494977324762902471764267795852486660601596648189999837075454896316687482540387017067211974603191279230953515521397067907513757763367315888101693042775385804066821260256218210264761730017655260313514255350592287156466544141273327424165523630928036465070504326759160965905472140206420733620859718350162744176336519051572708874620380237875083788097274492094030771087416734847686560630664937136197575123272360898853159596587429099207143246305845544244799356813180338388773189837194780822656452007718856513775556746086854637309945375913748887588098858159436611056484858182222940508156607890079350636796413492320863755066068420264176273501354701451580424930853731245191488999731887724342512885115174853872824237863191925018415676193712562003253140276927443202251707682541813796844055771821904734125528936278921457950566975054216078541402261766645717620168828928676184585062086661069943438428009453737016388913674954661321656899115360462958864817727116179756063838264308057333138934007726602464976584961039426342748390610135215206761067742896313902468085136725214515755654144065167649442144794757021442299332980346481411405659939120613041046295543064197536090990615733218132400037369470292737483454477799095857545361137577823887518193742510875707781884043932899326953370891554930847941892191784528780453236476476667586752290919919524010419077090794678643057876460306613406236250774207318712135446125272108408598954645410156742023},
+ {5,
938991641448887958659860711024139841840373070892857314837350127283993531354468803860225599873491818506054401963417489724433963777795696041544477412963807403300832656512849715212168703537706302853428971073305304224008208665300028518281475780493382070018498379488833882168221853720545474425047940975435356027594634176129712250061883354535324982741923143373986406603949677080360223989497048086447454366625852264609369284140522273595340921542019308988041920995057608746115976973659704188342646944998285431473302075966106608530908140377765357842459486869512398523240695806503711124427370056638597159539032058092571318621818616699716647464298881944582194013388150591419588422793657857267906072494480713650129757905856314362270238621284311461743652666256381611674809565144562467655186251867429369336740018623120262859220669942243740953355278814789244133782043857008487446798345197999966787658254507117076710455244182794239065255535191498857182705725985655379455993825553257619502588673174759329362518373537685585117537004065137523099625519490356398330532110250061129576411957409731201790054967354938147031111368166150009421041430118523249245874882140875551501824754839814848195806919150975076831338899823813371473496616326897054534509843640848822974414341233324307292275820287661792887177523563243279340678632061899626115667671047274195425889742755327012266774742591229119994211561599405909368902449776535330722644597809098307346948888547387746758109319767106289995123864514603259977184876246412673772519845777697496361969177346826245108557971745523905955370437517039028495325595180934057507336816903052766590118820327869839202378278312909402987412274414739124292902164277499512007446916921747463997761815820546816791093343347969046462095463611789365326128045878985464594892022442144072282717352526544915821855299863549245012366815543939396712522935345161074836470227392836664033041735035699615758782980717425699108612161567924880267630103820215946940542401779795959759774248414245436455737309858403883625882609790799283421857564831362243562647683958370353023343221966296655134926556805244483888769178095889844741765908328185625663202823312608064683035802724504683124396450612201783060593269112984065572954508643688374585823409316161924407053191442613988480926581084892323451281350937867676271858142177713557970909833234285545964647506859724327822527317869059455132036566677244407755994867168874825546516623190701762311472512591018622127119388239627852234680483324244759967}]}]
).
diff --git a/lib/public_key/src/pubkey_pbe.erl b/lib/public_key/src/pubkey_pbe.erl
index e89e16f120..806f7c5b0f 100644
--- a/lib/public_key/src/pubkey_pbe.erl
+++ b/lib/public_key/src/pubkey_pbe.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/public_key/src/pubkey_pem.erl b/lib/public_key/src/pubkey_pem.erl
index 06a4455b3f..b92790554f 100644
--- a/lib/public_key/src/pubkey_pem.erl
+++ b/lib/public_key/src/pubkey_pem.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -209,6 +209,8 @@ pem_start('DSAPrivateKey') ->
<<"-----BEGIN DSA PRIVATE KEY-----">>;
pem_start('DHParameter') ->
<<"-----BEGIN DH PARAMETERS-----">>;
+pem_start('PrivateKeyInfo') ->
+ <<"-----BEGIN PRIVATE KEY-----">>;
pem_start('EncryptedPrivateKeyInfo') ->
<<"-----BEGIN ENCRYPTED PRIVATE KEY-----">>;
pem_start('CertificationRequest') ->
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 931901640a..b34f905fc3 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -49,6 +49,7 @@
pkix_normalize_name/1,
pkix_path_validation/3,
pkix_verify_hostname/2, pkix_verify_hostname/3,
+ pkix_verify_hostname_match_fun/1,
ssh_decode/2, ssh_encode/2,
ssh_hostkey_fingerprint/1, ssh_hostkey_fingerprint/2,
ssh_curvename2oid/1, oid2ssh_curvename/1,
@@ -237,7 +238,7 @@ der_decode(Asn1Type, Der) when (Asn1Type == 'PrivateKeyInfo') or
andalso is_binary(Der) ->
try
{ok, Decoded} = 'PKCS-FRAME':decode(Asn1Type, Der),
- Decoded
+ der_priv_key_decode(Decoded)
catch
error:{badmatch, {error, _}} = Error ->
erlang:error(Error)
@@ -252,12 +253,45 @@ der_decode(Asn1Type, Der) when is_atom(Asn1Type), is_binary(Der) ->
erlang:error(Error)
end.
+der_priv_key_decode({'PrivateKeyInfo', v1,
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'id-ecPublicKey', {asn1_OPENTYPE, Parameters}}, PrivKey, _}) ->
+ EcPrivKey = der_decode('ECPrivateKey', PrivKey),
+ EcPrivKey#'ECPrivateKey'{parameters = der_decode('EcpkParameters', Parameters)};
+der_priv_key_decode({'PrivateKeyInfo', v1,
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'rsaEncryption', _}, PrivKey, _}) ->
+ der_decode('RSAPrivateKey', PrivKey);
+der_priv_key_decode({'PrivateKeyInfo', v1,
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'id-dsa', {asn1_OPENTYPE, Parameters}}, PrivKey, _}) ->
+ {params, #'Dss-Parms'{p=P, q=Q, g=G}} = der_decode('DSAParams', Parameters),
+ X = der_decode('Prime-p', PrivKey),
+ #'DSAPrivateKey'{p=P, q=Q, g=G, x=X};
+der_priv_key_decode(PKCS8Key) ->
+ PKCS8Key.
+
%%--------------------------------------------------------------------
-spec der_encode(asn1_type(), term()) -> Der::binary().
%%
%% Description: Encodes a public key entity with asn1 DER encoding.
%%--------------------------------------------------------------------
-der_encode(Asn1Type, Entity) when (Asn1Type == 'PrivateKeyInfo') or
+
+der_encode('PrivateKeyInfo', #'DSAPrivateKey'{p=P, q=Q, g=G, x=X}) ->
+ der_encode('PrivateKeyInfo',
+ {'PrivateKeyInfo', v1,
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'id-dsa',
+ {asn1_OPENTYPE, der_encode('Dss-Parms', #'Dss-Parms'{p=P, q=Q, g=G})}},
+ der_encode('Prime-p', X), asn1_NOVALUE});
+der_encode('PrivateKeyInfo', #'RSAPrivateKey'{} = PrivKey) ->
+ der_encode('PrivateKeyInfo',
+ {'PrivateKeyInfo', v1,
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'rsaEncryption', {asn1_OPENTYPE, ?DER_NULL}},
+ der_encode('RSAPrivateKey', PrivKey), asn1_NOVALUE});
+der_encode('PrivateKeyInfo', #'ECPrivateKey'{parameters = Parameters} = PrivKey) ->
+ der_encode('PrivateKeyInfo',
+ {'PrivateKeyInfo', v1,
+ {'PrivateKeyInfo_privateKeyAlgorithm', ?'id-ecPublicKey',
+ {asn1_OPENTYPE, der_encode('EcpkParameters', Parameters)}},
+ der_encode('ECPrivateKey', PrivKey#'ECPrivateKey'{parameters = asn1_NOVALUE}), asn1_NOVALUE});
+der_encode(Asn1Type, Entity) when (Asn1Type == 'PrivateKeyInfo') or
(Asn1Type == 'EncryptedPrivateKeyInfo') ->
try
{ok, Encoded} = 'PKCS-FRAME':encode(Asn1Type, Entity),
@@ -850,12 +884,24 @@ pkix_crls_validate(OtpCert, DPAndCRLs0, Options) ->
Options, pubkey_crl:init_revokation_state()).
%--------------------------------------------------------------------
--spec pkix_verify_hostname(Cert :: #'OTPCertificate'{} | binary(),
- ReferenceIDs :: [{uri_id | dns_id | ip | srv_id | oid(), string()}]) -> boolean().
+-spec pkix_verify_hostname(#'OTPCertificate'{} | binary(),
+ referenceIDs()
+ ) -> boolean().
+
+-spec pkix_verify_hostname(#'OTPCertificate'{} | binary(),
+ referenceIDs(),
+ proplists:proplist()) -> boolean().
--spec pkix_verify_hostname(Cert :: #'OTPCertificate'{} | binary(),
- ReferenceIDs :: [{uri_id | dns_id | ip | srv_id | oid(), string()}],
- Options :: proplists:proplist()) -> boolean().
+-type referenceIDs() :: [referenceID()] .
+-type referenceID() :: {uri_id | dns_id | ip | srv_id | oid(), string()}
+ | {ip, inet:ip_address()} .
+
+-spec pkix_verify_hostname_match_fun(high_level_alg()) -> match_fun() .
+
+-type high_level_alg() :: https .
+-type match_fun() :: fun((ReferenceID::referenceID() | string(),
+ PresentedID::{atom()|oid(),string()}) -> match_fun_result() ) .
+-type match_fun_result() :: boolean() | default .
%% Description: Validates a hostname to RFC 6125
%%--------------------------------------------------------------------
@@ -920,6 +966,11 @@ pkix_verify_hostname(Cert = #'OTPCertificate'{tbsCertificate = TbsCert}, Referen
end
end.
+pkix_verify_hostname_match_fun(https) ->
+ fun({dns_id,FQDN=[_|_]}, {dNSName,Name=[_|_]}) -> verify_hostname_match_wildcard(FQDN, Name);
+ (_, _) -> default
+ end.
+
%%--------------------------------------------------------------------
-spec ssh_decode(binary(), public_key | ssh_file()) -> [{public_key(), Attributes::list()}]
; (binary(), ssh2_pubkey) -> public_key()
@@ -1483,9 +1534,7 @@ verify_hostname_match_default(Ref, Pres) ->
verify_hostname_match_default0(FQDN=[_|_], {cn,FQDN}) ->
not lists:member($*, FQDN);
verify_hostname_match_default0(FQDN=[_|_], {cn,Name=[_|_]}) ->
- [F1|Fs] = string:tokens(FQDN, "."),
- [N1|Ns] = string:tokens(Name, "."),
- match_wild(F1,N1) andalso Fs==Ns;
+ verify_hostname_match_wildcard(FQDN, Name);
verify_hostname_match_default0({dns_id,R}, {dNSName,P}) ->
R==P;
verify_hostname_match_default0({uri_id,R}, {uniformResourceIdentifier,P}) ->
@@ -1520,6 +1569,13 @@ verify_hostname_match_default0({srv_id,R}, {?srvName_OID,P}) ->
verify_hostname_match_default0(_, _) ->
false.
+
+verify_hostname_match_wildcard(FQDN, Name) ->
+ [F1|Fs] = string:tokens(FQDN, "."),
+ [N1|Ns] = string:tokens(Name, "."),
+ match_wild(F1,N1) andalso Fs==Ns.
+
+
ok({ok,X}) -> X.
l16_to_tup(L) -> list_to_tuple(l16_to_tup(L, [])).
diff --git a/lib/public_key/test/pbe_SUITE.erl b/lib/public_key/test/pbe_SUITE.erl
index 44caf479e5..523c9e2515 100644
--- a/lib/public_key/test/pbe_SUITE.erl
+++ b/lib/public_key/test/pbe_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -226,11 +226,6 @@ pbes2(Config) when is_list(Config) ->
ok
end.
-check_key_info(#'PrivateKeyInfo'{privateKeyAlgorithm =
- #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?rsaEncryption},
- privateKey = Key}) ->
- #'RSAPrivateKey'{} = public_key:der_decode('RSAPrivateKey', iolist_to_binary(Key)).
-
decode_encode_key_file(File, Password, Cipher, Config) ->
Datadir = proplists:get_value(data_dir, Config),
{ok, PemKey} = file:read_file(filename:join(Datadir, File)),
@@ -238,11 +233,10 @@ decode_encode_key_file(File, Password, Cipher, Config) ->
PemEntry = public_key:pem_decode(PemKey),
ct:print("Pem entry: ~p" , [PemEntry]),
[{Asn1Type, _, {Cipher,_} = CipherInfo} = PubEntry] = PemEntry,
- KeyInfo = public_key:pem_entry_decode(PubEntry, Password),
+ #'RSAPrivateKey'{} = KeyInfo = public_key:pem_entry_decode(PubEntry, Password),
PemKey1 = public_key:pem_encode([public_key:pem_entry_encode(Asn1Type, KeyInfo, {CipherInfo, Password})]),
Pem = strip_ending_newlines(PemKey),
- Pem = strip_ending_newlines(PemKey1),
- check_key_info(KeyInfo).
+ Pem = strip_ending_newlines(PemKey1).
strip_ending_newlines(Bin) ->
string:strip(binary_to_list(Bin), right, 10).
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index 449d1fc040..cfd8e7a34b 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -64,6 +64,7 @@ all() ->
groups() ->
[{pem_decode_encode, [], [dsa_pem, rsa_pem, ec_pem, encrypted_pem,
dh_pem, cert_pem, pkcs7_pem, pkcs10_pem, ec_pem2,
+ rsa_priv_pkcs8, dsa_priv_pkcs8, ec_priv_pkcs8,
ec_pem_encode_generated,
gen_ec_param_prime_field, gen_ec_param_char_2_field
]},
@@ -181,6 +182,19 @@ dsa_pem(Config) when is_list(Config) ->
DSAPubPemNoEndNewLines = strip_superfluous_newlines(DSAPubPem),
DSAPubPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PubEntry0])).
+dsa_priv_pkcs8() ->
+ [{doc, "DSA PKCS8 private key decode/encode"}].
+dsa_priv_pkcs8(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+ {ok, DsaPem} = file:read_file(filename:join(Datadir, "dsa_key_pkcs8.pem")),
+ [{'PrivateKeyInfo', DerDSAKey, not_encrypted} = Entry0 ] = public_key:pem_decode(DsaPem),
+ DSAKey = public_key:der_decode('PrivateKeyInfo', DerDSAKey),
+ DSAKey = public_key:pem_entry_decode(Entry0),
+ true = check_entry_type(DSAKey, 'DSAPrivateKey'),
+ PrivEntry0 = public_key:pem_entry_encode('PrivateKeyInfo', DSAKey),
+ DSAPemNoEndNewLines = strip_superfluous_newlines(DsaPem),
+ DSAPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PrivEntry0])).
+
%%--------------------------------------------------------------------
rsa_pem() ->
@@ -216,6 +230,19 @@ rsa_pem(Config) when is_list(Config) ->
RSARawPemNoEndNewLines = strip_superfluous_newlines(RSARawPem),
RSARawPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PubEntry1])).
+rsa_priv_pkcs8() ->
+ [{doc, "RSA PKCS8 private key decode/encode"}].
+rsa_priv_pkcs8(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+ {ok, RsaPem} = file:read_file(filename:join(Datadir, "rsa_key_pkcs8.pem")),
+ [{'PrivateKeyInfo', DerRSAKey, not_encrypted} = Entry0 ] = public_key:pem_decode(RsaPem),
+ RSAKey = public_key:der_decode('PrivateKeyInfo', DerRSAKey),
+ RSAKey = public_key:pem_entry_decode(Entry0),
+ true = check_entry_type(RSAKey, 'RSAPrivateKey'),
+ PrivEntry0 = public_key:pem_entry_encode('PrivateKeyInfo', RSAKey),
+ RSAPemNoEndNewLines = strip_superfluous_newlines(RsaPem),
+ RSAPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PrivEntry0])).
+
%%--------------------------------------------------------------------
ec_pem() ->
@@ -262,6 +289,18 @@ ec_pem2(Config) when is_list(Config) ->
ECPemNoEndNewLines = strip_superfluous_newlines(ECPrivPem),
ECPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([Entry1, Entry2])).
+ec_priv_pkcs8() ->
+ [{doc, "EC PKCS8 private key decode/encode"}].
+ec_priv_pkcs8(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+ {ok, ECPrivPem} = file:read_file(filename:join(Datadir, "ec_key_pkcs8.pem")),
+ [{'PrivateKeyInfo', _, not_encrypted} = PKCS8Key] = public_key:pem_decode(ECPrivPem),
+ ECPrivKey = public_key:pem_entry_decode(PKCS8Key),
+ true = check_entry_type(ECPrivKey, 'ECPrivateKey'),
+ true = check_entry_type(ECPrivKey#'ECPrivateKey'.parameters, 'EcpkParameters'),
+ PrivEntry0 = public_key:pem_entry_encode('PrivateKeyInfo', ECPrivKey),
+ ECPemNoEndNewLines = strip_superfluous_newlines(ECPrivPem),
+ ECPemNoEndNewLines = strip_superfluous_newlines(public_key:pem_encode([PrivEntry0])).
init_ec_pem_encode_generated(Config) ->
case catch true = lists:member('secp384r1', crypto:ec_curves()) of
@@ -271,7 +310,7 @@ init_ec_pem_encode_generated(Config) ->
ec_pem_encode_generated() ->
[{doc, "PEM-encode generated EC key"}].
-ec_pem_encode_generated(Config) ->
+ec_pem_encode_generated(_Config) ->
Key1 = public_key:generate_key({namedCurve, 'secp384r1'}),
public_key:pem_entry_encode('ECPrivateKey', Key1),
@@ -926,7 +965,7 @@ pkix_verify_hostname_cn(Config) ->
%% openssl req -x509 -nodes -newkey rsa:1024 -keyout /dev/null -extensions SAN -config public_key_SUITE_data/verify_hostname.conf 2>/dev/null > public_key_SUITE_data/pkix_verify_hostname_subjAltName.pem
%%
%% Subject: C=SE, CN=example.com
-%% Subject Alternative Name: DNS:kb.example.org, URI:http://www.example.org, URI:https://wws.example.org
+%% Subject Alternative Name: DNS:kb.example.org, DNS:*.example.org, URI:http://www.example.org, URI:https://wws.example.org
pkix_verify_hostname_subjAltName(Config) ->
DataDir = proplists:get_value(data_dir, Config),
@@ -945,7 +984,25 @@ pkix_verify_hostname_subjAltName(Config) ->
{dns_id,"wws.example.org"}]),
%% Check that a dns_id matches a DNS subjAltName:
- true = public_key:pkix_verify_hostname(Cert, [{dns_id,"kb.example.org"}]).
+ true = public_key:pkix_verify_hostname(Cert, [{dns_id,"kb.example.org"}]),
+
+ %% Check that a dns_id does not match a DNS subjAltName wiht wildcard
+ false = public_key:pkix_verify_hostname(Cert, [{dns_id,"other.example.org"}]),
+
+ %% Check that a dns_id does match a DNS subjAltName wiht wildcard with matchfun
+ true = public_key:pkix_verify_hostname(Cert, [{dns_id,"other.example.org"}],
+ [{match_fun, public_key:pkix_verify_hostname_match_fun(https)}
+ ]
+ ),
+
+ %% Check that a uri_id does not match a DNS subjAltName wiht wildcard
+ false = public_key:pkix_verify_hostname(Cert, [{uri_id,"https://other.example.org"}]),
+
+ %% Check that a dns_id does match a DNS subjAltName wiht wildcard with matchfun
+ true = public_key:pkix_verify_hostname(Cert, [{uri_id,"https://other.example.org"}],
+ [{match_fun, public_key:pkix_verify_hostname_match_fun(https)}
+ ]
+ ).
%%--------------------------------------------------------------------
%% Uses the pem-file for pkix_verify_hostname_cn
@@ -992,7 +1049,14 @@ pkix_verify_hostname_options(Config) ->
end}]),
true = public_key:pkix_verify_hostname(Cert, [{uri_id,"https://example.com"}],
[{fqdn_fun, fun(_) -> default end}]),
- false = public_key:pkix_verify_hostname(Cert, [{uri_id,"some://very.wrong.domain"}]).
+ false = public_key:pkix_verify_hostname(Cert, [{uri_id,"some://very.wrong.domain"}]),
+
+ true = public_key:pkix_verify_hostname(Cert, [{dns_id,"example.com"}]),
+ true = public_key:pkix_verify_hostname(Cert, [{dns_id,"abb.bar.example.com"}]),
+ false = public_key:pkix_verify_hostname(Cert, [{dns_id,"example.com"},
+ {dns_id,"abb.bar.example.com"}],
+ [{fqdn_fun,fun(_)->undefined end}]).
+
%%--------------------------------------------------------------------
%% To generate the PEM file contents:
@@ -1312,7 +1376,7 @@ do_gen_ec_param(File) ->
ct:fail({key_gen_fail, File})
end.
-init_per_testcase_gen_ec_param(TC, Curve, Config) ->
+init_per_testcase_gen_ec_param(_TC, Curve, Config) ->
case crypto:ec_curves() of
[] ->
{skip, missing_ec_support};
@@ -1328,7 +1392,7 @@ init_per_testcase_gen_ec_param(TC, Curve, Config) ->
end.
-crypto_supported_curve(Curve, Curves) ->
+crypto_supported_curve(Curve, _Curves) ->
try crypto:generate_key(ecdh, Curve) of
{error,_} -> false; % Just in case crypto is changed in the future...
_-> true
diff --git a/lib/public_key/test/public_key_SUITE_data/dsa_key_pkcs8.pem b/lib/public_key/test/public_key_SUITE_data/dsa_key_pkcs8.pem
new file mode 100644
index 0000000000..86e38e2c76
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/dsa_key_pkcs8.pem
@@ -0,0 +1,9 @@
+-----BEGIN PRIVATE KEY-----
+MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBALez5tklY5CdFeTMos899pA6i4u4
+uCtszgBzrdBk6cl5FVqzdzWMGTQiynnTpGsrOESinzP06Ip+pG15We2OORwgvCxD
+/W95aCiN0/+MdiXqlsmboBARMzsa+SmBENN3gF/+tuuEAFzOXU1q2cmEywRLyfbM
+2KIBVE/TChWYw2eRAhUA1R64VvcQ90XA8SOKVDmMA0dBzukCgYEAlLMYP0pbgBlg
+HQVO3/avAHlWNrIq52Lxk7SdPJWgMvPjTK9Z6sv88kxsCcydtjvO439j1yqcwk50
+GQc+86ktBWWz93/HkIdnFyqafef4mmWvm2Uq6ClQKS+A0Asfaj8Mys+HUMiI+qsf
+djRbyIpwb7MX1nsVdsKzALnZNMW27A0EFgIUWYCfDrv5tqwPWKJu00ez0R192SY=
+-----END PRIVATE KEY-----
diff --git a/lib/public_key/test/public_key_SUITE_data/ec_key_pkcs8.pem b/lib/public_key/test/public_key_SUITE_data/ec_key_pkcs8.pem
new file mode 100644
index 0000000000..8280a3671a
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/ec_key_pkcs8.pem
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgB349XXSmba5BbJT5UuCK
+OoyoPHsygy6n+WzP1J+8eYShRANCAATTJdDtiqV9Hs7q+Y/yak1z3uJpukFQGYmr
+lJ2iztxfv7bz10eJ5yM/GNqG8kK0w7SIzjedsIkfjRK7bX6mP7h4
+-----END PRIVATE KEY-----
diff --git a/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName.pem b/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName.pem
index 83e1ad37b3..7ab9ed7b96 100644
--- a/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName.pem
+++ b/lib/public_key/test/public_key_SUITE_data/pkix_verify_hostname_subjAltName.pem
@@ -1,14 +1,14 @@
-----BEGIN CERTIFICATE-----
-MIICEjCCAXugAwIBAgIJANwliLph5EiAMA0GCSqGSIb3DQEBCwUAMCMxCzAJBgNV
-BAYTAlNFMRQwEgYDVQQDEwtleGFtcGxlLmNvbTAeFw0xNjEyMjAxNTEyMjRaFw0x
-NzAxMTkxNTEyMjRaMCMxCzAJBgNVBAYTAlNFMRQwEgYDVQQDEwtleGFtcGxlLmNv
-bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAydstIN157w8QxkVaOl3wm81j
-fgZ8gqO3BXkECPF6bw5ewLlmePL6Qs4RypsaRe7cKJ9rHFlwhpdcYkxWSWEt2N7Z
-Ry3N4SjuU04ohWbYgy3ijTt7bJg7jOV1Dh56BnI4hwhQj0oNFizNZOeRRfEzdMnS
-+uk03t/Qre2NS7KbwnUCAwEAAaNOMEwwSgYDVR0RBEMwQYIOa2IuZXhhbXBsZS5v
-cmeGFmh0dHA6Ly93d3cuZXhhbXBsZS5vcmeGF2h0dHBzOi8vd3dzLmV4YW1wbGUu
-b3JnMA0GCSqGSIb3DQEBCwUAA4GBAKqFqW5gCso422bXriCBJoygokOTTOw1Rzpq
-K8Mm0B8W9rrW9OTkoLEcjekllZcUCZFin2HovHC5HlHZz+mQvBI1M6sN2HVQbSzS
-EgL66U9gwJVnn9/U1hXhJ0LO28aGbyE29DxnewNR741dWN3oFxCdlNaO6eMWaEsO
-gduJ5sDl
+MIICITCCAYqgAwIBAgIJAP31suf/Fi4oMA0GCSqGSIb3DQEBCwUAMCMxCzAJBgNV
+BAYTAlNFMRQwEgYDVQQDEwtleGFtcGxlLmNvbTAeFw0xODA1MTcxMDIzNDBaFw0x
+ODA2MTYxMDIzNDBaMCMxCzAJBgNVBAYTAlNFMRQwEgYDVQQDEwtleGFtcGxlLmNv
+bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsUVMXSM4Q6vYp7H4Svsfv4QQ
+dmUD3IdTbtumlyAqLZuc6Z0HU9IOE0wpF97+5AE3moHluwN/MtSX/fb9oxCjh3L6
+iDla770uUoIgiWkA9lyzuYXt7zGsqc0EmGMJRAHp4jOxI26U/C8wdXoyZsGD8GPr
+hYAI2Me4CkdDqCoRuUUCAwEAAaNdMFswWQYDVR0RBFIwUIIOa2IuZXhhbXBsZS5v
+cmeCDSouZXhhbXBsZS5vcmeGFmh0dHA6Ly93d3cuZXhhbXBsZS5vcmeGF2h0dHBz
+Oi8vd3dzLmV4YW1wbGUub3JnMA0GCSqGSIb3DQEBCwUAA4GBAKs8vWMqpXiuFhcq
+6W1dMrVB4tuDjt1Ctr3g2USXBLgm8NxsZzslFyDnrvtZY0hbjcAkGKMMhy8lFD5t
++GjBbyp7MKII6vJaVvc+wbrsbNdvioB1puGwbgVhgD3Kb79do9h6JrNncjMvBN7j
+VK6BUB8TUofFmztMjoPlxFOs/7qK
-----END CERTIFICATE-----
diff --git a/lib/public_key/test/public_key_SUITE_data/rsa_key_pkcs8.pem b/lib/public_key/test/public_key_SUITE_data/rsa_key_pkcs8.pem
new file mode 100644
index 0000000000..9ef5b3353f
--- /dev/null
+++ b/lib/public_key/test/public_key_SUITE_data/rsa_key_pkcs8.pem
@@ -0,0 +1,10 @@
+-----BEGIN PRIVATE KEY-----
+MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEA1GLJmDS5yLvg1zqa
+epnwCgOXzxpPvHokDQx+AcgfO14SPtCD6UTlDEwYBp+6tUTm+qgeQN/CTi7POwIA
+m7P3UwIDAQABAkALFiEJ1e7AwLXq5j88GR8Dls5s3CW/Y+zP1ZAaTbT7p0QUMxG+
+0ko7h8NoxcQJHZU27sZXCjog/IBqn577Xv4RAiEA8/aQ09kz0jxi4aNvlix4B+bW
+gX0sYtcCDkBzx8Y6iMkCIQDe3WCxV9PuiDjpuC8cAy3UMC5PBygZG4iK3arpgzxp
+OwIhAKxKJg+mpgVEJiTpsiVhNEeIS1bZWp5W75m3BM1B/haZAiBQOhEcxikcrR0P
+xaXvx5Uv1UhWWpUstKSqmLF17jBJEQIhAMx4HMLqwaGeYwOcxfzxz6Al8fnPmfAR
+hqFR28fVJrWX
+-----END PRIVATE KEY-----
diff --git a/lib/public_key/test/public_key_SUITE_data/verify_hostname.conf b/lib/public_key/test/public_key_SUITE_data/verify_hostname.conf
index a28864dc78..6b4e4f284e 100644
--- a/lib/public_key/test/public_key_SUITE_data/verify_hostname.conf
+++ b/lib/public_key/test/public_key_SUITE_data/verify_hostname.conf
@@ -10,7 +10,8 @@ CN=example.com
subjectAltName = @alt_names
[alt_names]
-DNS = kb.example.org
+DNS.1 = kb.example.org
+DNS.2 = *.example.org
URI.1 = http://www.example.org
URI.2 = https://wws.example.org
diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk
index 99a0cc087e..5e9e463323 100644
--- a/lib/public_key/vsn.mk
+++ b/lib/public_key/vsn.mk
@@ -1 +1 @@
-PUBLIC_KEY_VSN = 1.5.2
+PUBLIC_KEY_VSN = 1.6.1
diff --git a/lib/reltool/doc/src/Makefile b/lib/reltool/doc/src/Makefile
index e378cdf980..8daafb7a2b 100644
--- a/lib/reltool/doc/src/Makefile
+++ b/lib/reltool/doc/src/Makefile
@@ -88,6 +88,7 @@ clean clean_docs:
fi \
done
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/reltool/doc/src/notes.xml b/lib/reltool/doc/src/notes.xml
index d7ad7c8dcc..52419259c6 100644
--- a/lib/reltool/doc/src/notes.xml
+++ b/lib/reltool/doc/src/notes.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2009</year>
- <year>2017</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -38,7 +38,22 @@
thus constitutes one section in this document. The title of each
section is the version number of Reltool.</p>
- <section><title>Reltool 0.7.5</title>
+ <section><title>Reltool 0.7.6</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Calls to <c>erlang:get_stacktrace()</c> are removed.
+ </p>
+ <p>
+ Own Id: OTP-14861</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Reltool 0.7.5</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/reltool/doc/src/reltool.xml b/lib/reltool/doc/src/reltool.xml
index 5bfbee966b..0da9279c80 100644
--- a/lib/reltool/doc/src/reltool.xml
+++ b/lib/reltool/doc/src/reltool.xml
@@ -806,7 +806,7 @@ target_spec() = [target_spec()]
<name>stop(Pid) -> ok | {error, Reason}</name>
<fsummary>Stop a server or window process</fsummary>
<type>
- <v>Pid = server_pid() | window_pid()()</v>
+ <v>Pid = server_pid() | window_pid()</v>
<v>Reason = reason()</v>
</type>
<desc><p>Stop a server or window process</p></desc>
diff --git a/lib/reltool/src/reltool.app.src b/lib/reltool/src/reltool.app.src
index dc21c1cfce..dc85464750 100644
--- a/lib/reltool/src/reltool.app.src
+++ b/lib/reltool/src/reltool.app.src
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/reltool/src/reltool.erl b/lib/reltool/src/reltool.erl
index feb6925044..2e1dbfd713 100644
--- a/lib/reltool/src/reltool.erl
+++ b/lib/reltool/src/reltool.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/reltool/src/reltool_app_win.erl b/lib/reltool/src/reltool_app_win.erl
index 335b40fa74..c84c1562ee 100644
--- a/lib/reltool/src/reltool_app_win.erl
+++ b/lib/reltool/src/reltool_app_win.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/reltool/src/reltool_fgraph_win.erl b/lib/reltool/src/reltool_fgraph_win.erl
index a10a2281db..0875d5dd7d 100644
--- a/lib/reltool/src/reltool_fgraph_win.erl
+++ b/lib/reltool/src/reltool_fgraph_win.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/reltool/src/reltool_mod_win.erl b/lib/reltool/src/reltool_mod_win.erl
index 8272d864c2..7df62b71be 100644
--- a/lib/reltool/src/reltool_mod_win.erl
+++ b/lib/reltool/src/reltool_mod_win.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index 66ee1a3742..47aba77835 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -526,7 +526,7 @@ analyse(#state{sys=Sys} = S, Apps, Status) ->
%% is included in a release (rel spec - see apps_in_rels above).
%% Then initiate the same for each module, and check that there
%% are no duplicated module names (in different applications)
- %% where we can not decide which one to use.
+ %% where we cannot decide which one to use.
%% Write all #app to app_tab and all #mod to mod_tab.
Status2 = apps_init_is_included(S, Apps, RelApps, Status),
diff --git a/lib/reltool/src/reltool_sys_win.erl b/lib/reltool/src/reltool_sys_win.erl
index d87b1dc91f..e24f468f67 100644
--- a/lib/reltool/src/reltool_sys_win.erl
+++ b/lib/reltool/src/reltool_sys_win.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/reltool/src/reltool_target.erl b/lib/reltool/src/reltool_target.erl
index 0eeeca4a61..64834ecc1d 100644
--- a/lib/reltool/src/reltool_target.erl
+++ b/lib/reltool/src/reltool_target.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/reltool/test/reltool_app_SUITE.erl b/lib/reltool/test/reltool_app_SUITE.erl
index a51ee8875a..bd0ed5edca 100644
--- a/lib/reltool/test/reltool_app_SUITE.erl
+++ b/lib/reltool/test/reltool_app_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/reltool/test/reltool_manual_gui_SUITE.erl b/lib/reltool/test/reltool_manual_gui_SUITE.erl
index 44da4ffd2c..3a4b012d2e 100644
--- a/lib/reltool/test/reltool_manual_gui_SUITE.erl
+++ b/lib/reltool/test/reltool_manual_gui_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index 3622f6650c..fc976bfb94 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1038,7 +1038,7 @@ create_standalone_app(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Generate standalone system with inlined archived application
-%% Check that the inlined app can not be explicitly configured
+%% Check that the inlined app cannot be explicitly configured
create_standalone_app_clash(Config) ->
%% Create archive
@@ -1658,7 +1658,7 @@ set_apps_inlined(Config) ->
?m(true, Someapp1#app.is_included),
?m(true, Someapp1#app.is_pre_included),
- %% Check that inlined app can not be configured
+ %% Check that inlined app cannot be configured
Someapp2 = Someapp1#app{incl_cond=exclude},
?msym({error,
"Application someapp is inlined in '*escript* someapp'. "
diff --git a/lib/reltool/test/reltool_test_lib.erl b/lib/reltool/test/reltool_test_lib.erl
index 53aeb8c08c..be48ea4726 100644
--- a/lib/reltool/test/reltool_test_lib.erl
+++ b/lib/reltool/test/reltool_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/reltool/test/reltool_wx_SUITE.erl b/lib/reltool/test/reltool_wx_SUITE.erl
index 19707894ae..f6f7721762 100644
--- a/lib/reltool/test/reltool_wx_SUITE.erl
+++ b/lib/reltool/test/reltool_wx_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/reltool/test/rtt.erl b/lib/reltool/test/rtt.erl
index d9e8e5520d..479241d86b 100644
--- a/lib/reltool/test/rtt.erl
+++ b/lib/reltool/test/rtt.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/reltool/vsn.mk b/lib/reltool/vsn.mk
index 49997b1e52..c698790ede 100644
--- a/lib/reltool/vsn.mk
+++ b/lib/reltool/vsn.mk
@@ -1 +1 @@
-RELTOOL_VSN = 0.7.5
+RELTOOL_VSN = 0.7.6
diff --git a/lib/runtime_tools/doc/src/LTTng.xml b/lib/runtime_tools/doc/src/LTTng.xml
index 93937b3fdc..89cbc805d8 100644
--- a/lib/runtime_tools/doc/src/LTTng.xml
+++ b/lib/runtime_tools/doc/src/LTTng.xml
@@ -3,7 +3,7 @@
<chapter>
<header>
<copyright>
- <year>2016</year><year>2017</year>
+ <year>2016</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -111,7 +111,7 @@ $ make </code>
<p><em>process_register</em></p>
<list type="bulleted">
<item><c>pid : string</c> :: Process ID. Ex. <c>"&lt;0.131.0&gt;"</c></item>
- <item><c>name : string</c> :: Registered name. Ex. <c>"error_logger"</c></item>
+ <item><c>name : string</c> :: Registered name. Ex. <c>"logger"</c></item>
<item><c>type : string</c> :: <c>"register" | "unregister"</c></item>
</list>
<p>Example:</p>
diff --git a/lib/runtime_tools/doc/src/Makefile b/lib/runtime_tools/doc/src/Makefile
index 11583406b7..2399ed51e0 100644
--- a/lib/runtime_tools/doc/src/Makefile
+++ b/lib/runtime_tools/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
+# Copyright Ericsson AB 1999-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -120,6 +120,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(MAN6DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
diff --git a/lib/runtime_tools/doc/src/dbg.xml b/lib/runtime_tools/doc/src/dbg.xml
index 276a41c415..ae60b610ed 100644
--- a/lib/runtime_tools/doc/src/dbg.xml
+++ b/lib/runtime_tools/doc/src/dbg.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -113,7 +113,7 @@
<p>The imported variables will be replaced by match_spec
<c>const</c> expressions, which is consistent with the
static scoping for Erlang <c>fun()</c>s. Local or global
- function calls can not be in the guard or body of the fun
+ function calls cannot be in the guard or body of the fun
however. Calls to builtin match_spec functions of course is
allowed:</p>
<pre>
@@ -756,7 +756,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
<c>cant_add_local_node</c> is returned.
</p>
<p>If a trace port (see <seealso marker="#trace_port-2"><c>trace_port/2</c></seealso>) is
- running on the local node, remote nodes can not be traced with
+ running on the local node, remote nodes cannot be traced with
a tracer process. The error reason
<c>cant_trace_remote_pid_to_local_port</c> is returned. A
trace port can however be started on the remote node with the
diff --git a/lib/runtime_tools/doc/src/notes.xml b/lib/runtime_tools/doc/src/notes.xml
index 355e3dd40d..5692df2ab4 100644
--- a/lib/runtime_tools/doc/src/notes.xml
+++ b/lib/runtime_tools/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,22 @@
<p>This document describes the changes made to the Runtime_Tools
application.</p>
+<section><title>Runtime_Tools 1.13</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ New utility module <c>scheduler</c> which makes it easier
+ to measure scheduler utilization.</p>
+ <p>
+ Own Id: OTP-14904</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Runtime_Tools 1.12.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/runtime_tools/doc/src/ref_man.xml b/lib/runtime_tools/doc/src/ref_man.xml
index eb3a6f0f5c..fdca65422d 100644
--- a/lib/runtime_tools/doc/src/ref_man.xml
+++ b/lib/runtime_tools/doc/src/ref_man.xml
@@ -4,7 +4,7 @@
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1999</year><year>2016</year>
+ <year>1999</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/runtime_tools/src/Makefile b/lib/runtime_tools/src/Makefile
index 6faa9c2e35..76286c5499 100644
--- a/lib/runtime_tools/src/Makefile
+++ b/lib/runtime_tools/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2017. All Rights Reserved.
+# Copyright Ericsson AB 1999-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/runtime_tools/src/appmon_info.erl b/lib/runtime_tools/src/appmon_info.erl
index 9c587475ca..d64206decf 100644
--- a/lib/runtime_tools/src/appmon_info.erl
+++ b/lib/runtime_tools/src/appmon_info.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/runtime_tools/src/erts_alloc_config.erl b/lib/runtime_tools/src/erts_alloc_config.erl
index 6c1a945484..845efaf9ef 100644
--- a/lib/runtime_tools/src/erts_alloc_config.erl
+++ b/lib/runtime_tools/src/erts_alloc_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/runtime_tools/src/msacc.erl b/lib/runtime_tools/src/msacc.erl
index 37887cee72..7a3633be8e 100644
--- a/lib/runtime_tools/src/msacc.erl
+++ b/lib/runtime_tools/src/msacc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2014-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/runtime_tools/src/observer_backend.erl b/lib/runtime_tools/src/observer_backend.erl
index 7ec3b38930..3a24986381 100644
--- a/lib/runtime_tools/src/observer_backend.erl
+++ b/lib/runtime_tools/src/observer_backend.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -94,7 +94,7 @@ sys_info() ->
{port_limit, erlang:system_info(port_limit)},
{port_count, erlang:system_info(port_count)},
{ets_limit, erlang:system_info(ets_limit)},
- {ets_count, length(ets:all())},
+ {ets_count, erlang:system_info(ets_count)},
{dist_buf_busy_limit, erlang:system_info(dist_buf_busy_limit)}
| MemInfo].
diff --git a/lib/runtime_tools/src/runtime_tools.app.src b/lib/runtime_tools/src/runtime_tools.app.src
index 09a9b447c2..b026048b94 100644
--- a/lib/runtime_tools/src/runtime_tools.app.src
+++ b/lib/runtime_tools/src/runtime_tools.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/runtime_tools/src/system_information.erl b/lib/runtime_tools/src/system_information.erl
index 136ee55b54..8f7bfa195b 100644
--- a/lib/runtime_tools/src/system_information.erl
+++ b/lib/runtime_tools/src/system_information.erl
@@ -400,7 +400,6 @@ os_getenv_erts_specific() ->
"ERL_MALLOC_LIB",
"ERL_MAX_PORTS",
"ERL_MAX_ETS_TABLES",
- "ERL_NO_VFORK",
"ERL_NO_KERNEL_POLL",
"ERL_THREAD_POOL_SIZE",
"ERLC_EMULATOR",
diff --git a/lib/runtime_tools/test/dbg_SUITE.erl b/lib/runtime_tools/test/dbg_SUITE.erl
index c5dcccb887..98cbc0360f 100644
--- a/lib/runtime_tools/test/dbg_SUITE.erl
+++ b/lib/runtime_tools/test/dbg_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/runtime_tools/test/dyntrace_SUITE.erl b/lib/runtime_tools/test/dyntrace_SUITE.erl
index 7ffbe54446..17bc104e9a 100644
--- a/lib/runtime_tools/test/dyntrace_SUITE.erl
+++ b/lib/runtime_tools/test/dyntrace_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/runtime_tools/vsn.mk b/lib/runtime_tools/vsn.mk
index 26869b9412..0a4ad61537 100644
--- a/lib/runtime_tools/vsn.mk
+++ b/lib/runtime_tools/vsn.mk
@@ -1 +1 @@
-RUNTIME_TOOLS_VSN = 1.12.5
+RUNTIME_TOOLS_VSN = 1.13
diff --git a/lib/sasl/doc/src/Makefile b/lib/sasl/doc/src/Makefile
index baf563ca62..8e1e8b502c 100644
--- a/lib/sasl/doc/src/Makefile
+++ b/lib/sasl/doc/src/Makefile
@@ -101,6 +101,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(MAN4DIR)/*
rm -f $(MAN6DIR)/*
diff --git a/lib/sasl/doc/src/appup.xml b/lib/sasl/doc/src/appup.xml
index d9d339884f..102ea9e5d7 100644
--- a/lib/sasl/doc/src/appup.xml
+++ b/lib/sasl/doc/src/appup.xml
@@ -4,7 +4,7 @@
<fileref>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/sasl/doc/src/error_logging.xml b/lib/sasl/doc/src/error_logging.xml
index 4b2c960bbb..e6c244c1b9 100644
--- a/lib/sasl/doc/src/error_logging.xml
+++ b/lib/sasl/doc/src/error_logging.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,22 +32,52 @@
<rev>B</rev>
<file>error_logging.xml</file>
</header>
+ <note>
+ <p>The SASL error logging concept described in this section is
+ deprecated since Erlang/OTP 21.0, when the
+ new <seealso marker="kernel:logger_chapter">logging
+ API</seealso> was introduced.</p>
+ <p>The new default behaviour is that the SASL application no
+ longer affects which log events that are logged.
+ <seealso marker="#supervisor_report">Supervisor
+ reports</seealso> and <seealso marker="#crash_report">crash
+ reports</seealso> are logged via the default logger handler
+ which is setup by
+ Kernel. <seealso marker="#progress_report">Progress
+ reports</seealso> are by default not logged, but can be enabled
+ by setting the primary log level to <c>info</c>, for example by
+ using the Kernel configuration
+ parameter <seealso marker="kernel:kernel_app#logger_level">
+ <c>logger_level</c></seealso>.</p>
+ <p>The old SASL error logging behaviour can be re-enabled by setting the
+ Kernel configuration
+ parameter <seealso marker="kernel:kernel_app#logger_sasl_compatible">
+ <c>logger_sasl_compatible</c></seealso> to <c>true</c>.</p>
+ <p>The mechanism
+ for <seealso marker="#multi_file_logging">multi-file error report
+ logging</seealso> as described in this section is also kept for
+ backwards compatibility. However, the new logging API also
+ introduces <seealso marker="kernel:logger_disk_log_h">
+ <c>logger_disk_log_h(3)</c></seealso>, which is a logger
+ handler that can print to multiple files
+ using <seealso marker="kernel:disk_log"><c>disk_log(3)</c></seealso>.</p>
+ </note>
+
+ <section>
+ <title>SASL reports</title>
<p>The SASL application introduces three types of reports:</p>
<list type="bulleted">
<item>Supervisor report</item>
<item>Progress report</item>
<item>Crash report</item>
</list>
- <p>When the SASL application is started, it adds a handler that
- formats and writes these reports, as specified in the configuration
- parameters for SASL, that is, the environment variables
- in the SASL application specification, which is found in the
- <c>.app</c> file of SASL. For details, see the
- <seealso marker="sasl_app"><c>sasl(6)</c></seealso> application in the
- Reference Manual and the <seealso marker="kernel:app"><c>app(4)</c></seealso>
- file in the Kernel Reference Manual.</p>
+ <p>When the SASL application is started, it adds a Logger handler
+ that formats and writes these reports, as specified in
+ the <seealso marker="sasl_app#deprecated_error_logger_config">configuration
+ parameters for SASL</seealso>.</p>
<section>
+ <marker id="supervisor_report"/>
<title>Supervisor Report</title>
<p>A supervisor report is issued when a supervised child terminates
unexpectedly. A supervisor report contains the following
@@ -68,6 +98,7 @@
</section>
<section>
+ <marker id="progress_report"/>
<title>Progress Report</title>
<p>A progress report is issued when a supervisor starts or
restarts a child. A progress report contains the following items:</p>
@@ -82,6 +113,7 @@
</section>
<section>
+ <marker id="crash_report"/>
<title>Crash Report</title>
<p>Processes started with functions
<seealso marker="stdlib:proc_lib#spawn/1"><c>proc_lib:spawn</c></seealso> or
@@ -105,6 +137,7 @@
crash. The information gathered is the same as the information
for Crasher, described in the previous item.</p></item>
</taglist>
+ </section>
<section>
<title>Example</title>
@@ -163,6 +196,7 @@
</section>
<section>
+ <marker id="multi_file_logging"/>
<title>Multi-File Error Report Logging</title>
<p>Multi-file error report logging is used to store error messages
received by <c>error_logger</c>. The error messages
@@ -171,7 +205,8 @@
of files exist at the same time. The logging is very fast, as
each error message is written as a binary term.</p>
<p>For more details, see the
- <seealso marker="sasl_app"><c>sasl(6)</c></seealso>
+ <seealso marker="sasl_app#deprecated_error_logger_config">
+ <c>sasl(6)</c></seealso>
application in the Reference Manual.</p>
</section>
diff --git a/lib/sasl/doc/src/notes.xml b/lib/sasl/doc/src/notes.xml
index 791e9c063a..3dda5b06e8 100644
--- a/lib/sasl/doc/src/notes.xml
+++ b/lib/sasl/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,88 @@
</header>
<p>This document describes the changes made to the SASL application.</p>
+<section><title>SASL 3.2</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>A new logging API is added to Erlang/OTP, see the
+ <seealso
+ marker="kernel:logger"><c>logger(3)</c></seealso> manual
+ page, and section <seealso
+ marker="kernel:logger_chapter">Logging</seealso> in the
+ Kernel User's Guide.</p>
+ <p>Calls to <c>error_logger</c> are automatically
+ redirected to the new API, and legacy error logger event
+ handlers can still be used. It is, however, recommended
+ to use the Logger API directly when writing new code.</p>
+ <p>Notice the following potential incompatibilities:</p>
+ <list> <item><p>Kernel configuration parameters
+ <c>error_logger</c> still works, but is overruled if the
+ default handler's output destination is configured with
+ Kernel configuration parameter <c>logger</c>.</p> <p>In
+ general, parameters for configuring error logger are
+ overwritten by new parameters for configuring
+ Logger.</p></item> <item><p>The concept of SASL error
+ logging is deprecated, meaning that by default the SASL
+ application does not affect which log events are
+ logged.</p> <p>By default, supervisor reports and crash
+ reports are logged by the default Logger handler started
+ by Kernel, and end up at the same destination (terminal
+ or file) as other standard log event from Erlang/OTP.</p>
+ <p>Progress reports are not logged by default, but can be
+ enabled by setting the primary log level to info, for
+ example with the Kernel configuration parameter
+ <c>logger_level</c>.</p> <p>To obtain backwards
+ compatibility with the SASL error logging functionality
+ from earlier releases, set Kernel configuration parameter
+ <c>logger_sasl_compatible</c> to <c>true</c>. This
+ prevents the default Logger handler from logging any
+ supervisor-, crash-, or progress reports. Instead, SASL
+ adds a separate Logger handler during application start,
+ which takes care of these log events. The SASL
+ configuration parameters <c>sasl_error_logger</c> and
+ <c>sasl_errlog_type</c> specify the destination (terminal
+ or file) and severity level to log for these
+ events.</p></item></list>
+ <p>
+ Since Logger is new in Erlang/OTP 21.0, we do reserve the
+ right to introduce changes to the Logger API and
+ functionality in patches following this release. These
+ changes might or might not be backwards compatible with
+ the initial version.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-13295</p>
+ </item>
+ <item>
+ <p>
+ The old and outdated "Status Inspection" tool (modules
+ <c>si</c> and <c>si_sasl_sup</c>) is removed.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14469</p>
+ </item>
+ <item>
+ <p>
+ When creating the release tar file, systools now includes
+ sys.config.src if it exists in the
+ $ROOT/releases/&lt;vsn&gt;/ directory. This is to allow
+ adjustments, e.g. resolving environment variables, after
+ unpacking the release, but before installing it. This
+ functionality requires a custom tool which uses
+ sys.config.src as input and creates a correct sys.config
+ file.</p>
+ <p>
+ Own Id: OTP-14950 Aux Id: PR-1560 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SASL 3.1.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/sasl/doc/src/release_handler.xml b/lib/sasl/doc/src/release_handler.xml
index 975188f489..9ba276aeac 100644
--- a/lib/sasl/doc/src/release_handler.xml
+++ b/lib/sasl/doc/src/release_handler.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/sasl/doc/src/sasl_app.xml b/lib/sasl/doc/src/sasl_app.xml
index 48b0b8eafb..fc83f63fe6 100644
--- a/lib/sasl/doc/src/sasl_app.xml
+++ b/lib/sasl/doc/src/sasl_app.xml
@@ -4,7 +4,7 @@
<appref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -86,30 +86,27 @@
<c>RELDIR</c> is used. By default, this is
<c>$OTP_ROOT/releases</c>.</p>
</item>
- <tag><c><![CDATA[utc_log = true | false ]]></c></tag>
- <item>
- <p>If set to <c>true</c>, all dates in textual log outputs are
- displayed in Universal Coordinated Time with the string
- <c>UTC</c> appended.</p>
- </item>
</taglist>
</section>
<section>
+ <marker id="deprecated_error_logger_config"/>
<title>Deprecated Error Logger Event Handlers and Configuration</title>
- <p>In OTP-21, a new API for logging was added to Erlang/OTP. The
+ <p>In Erlang/OTP 21.0, a new API for logging was added. The
old <c>error_logger</c> event manager, and event handlers
- running on this manager, will still work, but they are not used
+ running on this manager, still work, but they are not used
by default.</p>
<p>The error logger event handlers <c>sasl_report_tty_h</c>
- and <c>sasl_report_file_h</c>, were earliger used for printing
+ and <c>sasl_report_file_h</c>, were earlier used for printing
the so called SASL reports, i.e. <em>supervisor
reports</em>, <em>crash reports</em>, and <em>progress
- reports</em>. These reports are now also printed by the standard
+ reports</em>. These reports are now also printed by the default
logger handler started by the Kernel application. Progress
- reports are by default stopped by a filter, but can easily be
- added by setting the Kernel configuration
- parameter <seealso marker="kernel:kernel_app#logger_log_progress"><c>logger_log_progress=true</c></seealso>.</p>
+ reports are by default stopped by the primary log level, but can
+ be enabled by setting this level to <c>info</c>, for example by
+ using the Kernel configuration
+ parameter <seealso marker="kernel:kernel_app#logger_level">
+ <c>logger_level</c></seealso>.</p>
<p>If the old error logger event handlers are still desired, they
must be added by
calling <c>error_logger:add_report_handler/1,2</c>.</p>
@@ -119,34 +116,29 @@
<p>Formats and writes <em>supervisor reports</em>, <em>crash
reports</em>, and <em>progress reports</em> to <c>stdio</c>.
This error logger event handler uses
- <seealso marker="kernel:kernel_app#logger_format_depth"><c>logger_format_depth</c></seealso>
+ <seealso marker="kernel:kernel_app#deprecated-configuration-parameters"><c>error_logger_format_depth</c></seealso>
in the Kernel application to limit how much detail is printed
- in crash and supervisor reports. If <c>logger_format_depth</c>
- is not set, it uses the old <c>error_logger_format_depth</c>
- instead.</p>
+ in crash and supervisor reports.</p>
</item>
<tag><c>sasl_report_file_h</c></tag>
<item>
<p>Formats and writes <em>supervisor reports</em>, <em>crash
report</em>, and <em>progress report</em> to a single file.
This error logger event handler uses
- <seealso marker="kernel:kernel_app#logger_format_depth"><c>logger_format_depth</c></seealso>
+ <seealso marker="kernel:kernel_app#deprecated-configuration-parameters"><c>error_logger_format_depth</c></seealso>
in the Kernel application to limit the details printed in
- crash and supervisor reports. If <c>logger_format_depth</c> is
- not set, it uses the old <c>error_logger_format_depth</c>
- instead.</p>
+ crash and supervisor reports.</p>
</item>
</taglist>
<p>A similar behaviour, but still using the new logger API, can be
obtained by setting the Kernel application environment
- variable <seealso marker="kernel:kernel_app#logger_sasl_compatible"><c>logger_sasl_compatible=true</c></seealso>. This will add a
- second instance of the standard logger handler
- named <c>sasl_h</c>, which will only print the SASL reports. No
- SASL reports will then be printed by the Kernel logger
- handler.</p>
- <p>The <c>sasl_h</c> handler will be configured according to the
- values of the following SASL application environment
- variables.</p>
+ variable <seealso marker="kernel:kernel_app#logger_sasl_compatible">
+ <c>logger_sasl_compatible</c></seealso> to <c>true</c>. This
+ adds a second instance of the standard Logger handler,
+ named <c>sasl</c>, which only prints the SASL reports. No SASL
+ reports are then printed by the Kernel logger handler.</p>
+ <p>The <c>sasl</c> handler is configured according to the values
+ of the following SASL application environment variables.</p>
<taglist>
<tag><c><![CDATA[sasl_error_logger = Value ]]></c></tag>
<item>
@@ -179,6 +171,12 @@
<c>sasl_error_logger</c> to error reports or progress reports,
or both. Default is <c>all</c>.</p>
</item>
+ <tag><marker id="utc_log"/><c><![CDATA[utc_log = true | false ]]></c></tag>
+ <item>
+ <p>If set to <c>true</c>, all dates in textual log outputs are
+ displayed in Universal Coordinated Time with the string
+ <c>UTC</c> appended.</p>
+ </item>
</taglist>
<p>The error logger event handler <c>log_mf_h</c> can also still
@@ -222,6 +220,7 @@
<title>See Also</title>
<p><seealso marker="alarm_handler"><c>alarm_handler(3)</c></seealso>,
<seealso marker="kernel:error_logger"><c>error_logger(3)</c></seealso>,
+ <seealso marker="kernel:logger"><c>logger(3)</c></seealso>,
<seealso marker="stdlib:log_mf_h"><c>log_mf_h(3)</c></seealso>,
<seealso marker="rb"><c>rb(3)</c></seealso>,
<seealso marker="release_handler"><c>release_handler(3)</c></seealso>,
diff --git a/lib/sasl/src/Makefile b/lib/sasl/src/Makefile
index 45cd814bf8..7338bdf016 100644
--- a/lib/sasl/src/Makefile
+++ b/lib/sasl/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2016. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/sasl/src/rb.erl b/lib/sasl/src/rb.erl
index 28829132a1..bef4268d3a 100644
--- a/lib/sasl/src/rb.erl
+++ b/lib/sasl/src/rb.erl
@@ -890,7 +890,7 @@ read_rep(Fd, FilePosition, Device, Abort, Log) ->
handle_bad_form(Date, Msg, Device, Abort, Log) ->
io:format("rb: ERROR! A report on bad form was encountered. " ++
- "It can not be printed to the log.~n~n"),
+ "It cannot be printed to the log.~n~n"),
io:format("Details:~n~p ~tp~n~n", [Date,Msg]),
case {Abort,Device,open_log_file(Log)} of
{true,standard_io,standard_io} ->
diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl
index 4fd3fc0d36..48feac1a21 100644
--- a/lib/sasl/src/release_handler.erl
+++ b/lib/sasl/src/release_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1120,7 +1120,7 @@ new_emulator_make_hybrid_config(CurrentVsn,ToVsn,TmpVsn,RelDir,Masters) ->
{ok,[FC]} ->
FC;
{error,Error1} ->
- io:format("Warning: ~w can not read ~tp: ~tp~n",
+ io:format("Warning: ~w cannot read ~tp: ~tp~n",
[?MODULE,FromFile,Error1]),
[]
end,
@@ -1130,7 +1130,7 @@ new_emulator_make_hybrid_config(CurrentVsn,ToVsn,TmpVsn,RelDir,Masters) ->
{ok,[ToConfig]} ->
[lists:keyfind(App,1,ToConfig) || App <- [kernel,stdlib,sasl]];
{error,Error2} ->
- io:format("Warning: ~w can not read ~tp: ~tp~n",
+ io:format("Warning: ~w cannot read ~tp: ~tp~n",
[?MODULE,ToFile,Error2]),
[false,false,false]
end,
diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl
index ca97515299..bf18691687 100644
--- a/lib/sasl/src/release_handler_1.erl
+++ b/lib/sasl/src/release_handler_1.erl
@@ -147,7 +147,7 @@ split_instructions([], Before) ->
%% If PrePurgeMethod == soft_purge, the function will succeed
%% only if there is no process running old code of any of the
%% modules. Else it will throw {error,Mod}, where Mod is the
-%% first module found that can not be soft_purged.
+%% first module found that cannot be soft_purged.
%%
%% If PrePurgeMethod == brutal_purge, the function will
%% always succeed and return a list of all modules that are
diff --git a/lib/sasl/src/sasl.app.src b/lib/sasl/src/sasl.app.src
index 60d08ffa54..688aff16f1 100644
--- a/lib/sasl/src/sasl.app.src
+++ b/lib/sasl/src/sasl.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/sasl/src/sasl.appup.src b/lib/sasl/src/sasl.appup.src
index 221427874c..83ee328af2 100644
--- a/lib/sasl/src/sasl.appup.src
+++ b/lib/sasl/src/sasl.appup.src
@@ -1,7 +1,7 @@
%% -*- erlang -*-
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/sasl/src/sasl.erl b/lib/sasl/src/sasl.erl
index 2bf11bdcdf..0c68c93dc6 100644
--- a/lib/sasl/src/sasl.erl
+++ b/lib/sasl/src/sasl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -129,33 +129,33 @@ get_mf_maxf() ->
add_sasl_logger(undefined, _Level) -> ok;
add_sasl_logger(std, undefined) -> ok;
add_sasl_logger(Dest, Level) ->
- FC0 = #{legacy_header=>true,
- single_line=>false,
- template=>[{logger_formatter,header},"\n",msg,"\n"]},
- FC = case application:get_env(sasl,utc_log) of
- {ok,Bool} when is_boolean(Bool) ->
- FC0#{utc=>Bool};
- _ ->
- FC0
- end,
- ok = logger:add_handler(sasl_h,logger_std_h,
+ FC = #{legacy_header=>true,
+ single_line=>false},
+ case Level of
+ info -> allow_progress();
+ _ -> ok
+ end,
+ ok = logger:add_handler(sasl,logger_std_h,
#{level=>Level,
filter_default=>stop,
filters=>
- [{sasl_domain,
+ [{remote_gl,
+ {fun logger_filters:remote_gl/2,stop}},
+ {sasl_domain,
{fun logger_filters:domain/2,
- {log,equals,[beam,erlang,otp,sasl]}}}],
- logger_std_h=>#{type=>Dest},
+ {log,equal,[otp,sasl]}}}],
+ config=>#{type=>Dest},
formatter=>{logger_formatter,FC}}).
delete_sasl_logger(undefined) -> ok;
delete_sasl_logger(std) -> ok;
delete_sasl_logger(_Type) ->
- _ = logger:remove_handler(sasl_h),
+ _ = logger:remove_handler(sasl),
ok.
add_error_logger_mf(undefined) -> ok;
add_error_logger_mf({Dir, MaxB, MaxF}) ->
+ allow_progress(),
error_logger:add_report_handler(
log_mf_h, log_mf_h:init(Dir, MaxB, MaxF, fun pred/1)).
@@ -166,6 +166,13 @@ delete_error_logger_mf(_) ->
pred({_Type, GL, _Msg}) when node(GL) =/= node() -> false;
pred(_) -> true.
+allow_progress() ->
+ #{level:=PL} = logger:get_primary_config(),
+ case logger:compare_levels(info,PL) of
+ lt -> ok = logger:set_primary_config(level,info);
+ _ -> ok
+ end.
+
%%%-----------------------------------------------------------------
%%% supervisor functionality
%%%-----------------------------------------------------------------
diff --git a/lib/sasl/src/sasl_report_file_h.erl b/lib/sasl/src/sasl_report_file_h.erl
index d3b5c7dc0d..05d6acd076 100644
--- a/lib/sasl/src/sasl_report_file_h.erl
+++ b/lib/sasl/src/sasl_report_file_h.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl
index f4b1b54fd1..6916107623 100644
--- a/lib/sasl/src/systools_make.erl
+++ b/lib/sasl/src/systools_make.erl
@@ -1551,7 +1551,7 @@ mandatory_modules() ->
logger_server,
logger_backend,
logger_config,
- logger_simple,
+ logger_simple_h,
lists,
proc_lib,
supervisor
diff --git a/lib/sasl/test/installer.erl b/lib/sasl/test/installer.erl
index e38d0cfa7b..5429008a5f 100644
--- a/lib/sasl/test/installer.erl
+++ b/lib/sasl/test/installer.erl
@@ -905,7 +905,7 @@ start_client(TestNode,Client,Sname) ->
wait_started(TestNode,Node)
after 30000 ->
?print([{start_client,failed,Node},net_adm:ping(Node)]),
- ?fail({"can not start", Node})
+ ?fail({"cannot start", Node})
end.
start_client_unix(TestNode,Sname,Node) ->
diff --git a/lib/sasl/test/rb_SUITE.erl b/lib/sasl/test/rb_SUITE.erl
index 4ba2540545..e5ca1775d5 100644
--- a/lib/sasl/test/rb_SUITE.erl
+++ b/lib/sasl/test/rb_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -423,7 +423,7 @@ start_stop_log(Config) ->
StdioResult2 = capture(fun() -> rb:log_list() end),
{ok,<<>>} = file:read_file(OutFile),
- %% Test that standard_io is used if log file can not be opened
+ %% Test that standard_io is used if log file cannot be opened
ok = rb:start_log(filename:join(nonexistingdir,"newfile.txt")),
StdioResult = capture(fun() -> rb:show(1) end),
{ok,<<>>} = file:read_file(OutFile),
diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl
index edd2efdf05..2ff2f29591 100644
--- a/lib/sasl/test/release_handler_SUITE.erl
+++ b/lib/sasl/test/release_handler_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/sasl/test/sasl_SUITE.erl b/lib/sasl/test/sasl_SUITE.erl
index 7b63684c53..fc80e37210 100644
--- a/lib/sasl/test/sasl_SUITE.erl
+++ b/lib/sasl/test/sasl_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/sasl/test/sasl_report_SUITE.erl b/lib/sasl/test/sasl_report_SUITE.erl
index 96975aaf69..a03932133e 100644
--- a/lib/sasl/test/sasl_report_SUITE.erl
+++ b/lib/sasl/test/sasl_report_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
-export([gen_server_crash/1, gen_server_crash_unicode/1]).
+-export([legacy_gen_server_crash/1, legacy_gen_server_crash_unicode/1]).
-export([crash_me/0,start_link/0,init/1,handle_cast/2,terminate/2]).
@@ -29,7 +30,10 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [gen_server_crash, gen_server_crash_unicode].
+ [gen_server_crash,
+ gen_server_crash_unicode,
+ legacy_gen_server_crash,
+ legacy_gen_server_crash_unicode].
groups() ->
[].
@@ -52,17 +56,77 @@ gen_server_crash(Config) ->
gen_server_crash_unicode(Config) ->
gen_server_crash(Config, unicode).
+legacy_gen_server_crash(Config) ->
+ legacy_gen_server_crash(Config,latin1).
+
+legacy_gen_server_crash_unicode(Config) ->
+ legacy_gen_server_crash(Config,unicode).
+
gen_server_crash(Config, Encoding) ->
+ TC = list_to_atom(lists:concat([?FUNCTION_NAME,"_",Encoding])),
+ PrivDir = filename:join(?config(priv_dir,Config),?MODULE),
+ ConfigFileName = filename:join(PrivDir,TC),
+ KernelLog = filename:join(PrivDir,lists:concat([TC,"_kernel.log"])),
+ SaslLog = filename:join(PrivDir,lists:concat([TC,"_sasl.log"])),
+ KernelConfig = [{logger,[{handler,default,logger_std_h,
+ #{config=>#{type=>{file,KernelLog}}}}]},
+ {logger_sasl_compatible,true}],
+ Modes = [write, {encoding, Encoding}],
+ SaslConfig = [{sasl_error_logger,{file,SaslLog,Modes}}],
+ ok = filelib:ensure_dir(SaslLog),
+
+ ok = file:write_file(ConfigFileName ++ ".config",
+ io_lib:format("[{kernel, ~p},~n{sasl, ~p}].",
+ [KernelConfig,SaslConfig])),
+ {ok,Node} =
+ test_server:start_node(
+ TC, peer,
+ [{args, ["-pa ",filename:dirname(code:which(?MODULE)),
+ " -boot start_sasl -kernel start_timer true "
+ "-config ",ConfigFileName]}]),
+
+ %% Set depth
+ ok = rpc:call(Node,logger,update_formatter_config,[default,depth,30]),
+ ok = rpc:call(Node,logger,update_formatter_config,[sasl,depth,30]),
+
+ %% Make sure remote node logs it's own logs, and current node does
+ %% not log them.
+ ok = rpc:call(Node,logger,remove_handler_filter,[default,remote_gl]),
+ ok = rpc:call(Node,logger,remove_handler_filter,[sasl,remote_gl]),
+ ok = logger:add_primary_filter(no_remote,{fun(#{meta:=#{pid:=Pid}},_)
+ when node(Pid)=/=node() -> stop;
+ (_,_) -> ignore
+ end,[]}),
+ ct:log("Local node Logger config:~n~p",
+ [rpc:call(Node,logger,get_config,[])]),
+ ct:log("Remote node Logger config:~n~p",
+ [rpc:call(Node,logger,get_config,[])]),
+ ct:log("Remote node error_logger handlers: ~p",
+ [rpc:call(Node,error_logger,which_report_handlers,[])]),
+
+ ok = rpc:call(Node,?MODULE,crash_me,[]),
+
+ test_server:stop_node(Node),
+ ok = logger:remove_primary_filter(no_remote),
+
+ check_file(KernelLog, utf8, 70000, 150000),
+ check_file(SaslLog, Encoding, 70000, 150000),
+
+ ok = file:delete(KernelLog),
+ ok = file:delete(SaslLog),
+
+ ok.
+
+legacy_gen_server_crash(Config, Encoding) ->
StopFilter = {fun(_,_) -> stop end, ok},
- logger:add_handler_filter(logger_std_h,stop_all,StopFilter),
+ logger:add_handler_filter(default,stop_all,StopFilter),
+ logger:add_handler_filter(sasl,stop_all,StopFilter),
logger:add_handler_filter(cth_log_redirect,stop_all,StopFilter),
try
do_gen_server_crash(Config, Encoding)
after
- ok = application:unset_env(kernel, logger_sasl_compatible),
- ok = application:unset_env(sasl, sasl_error_logger),
- ok = application:unset_env(kernel, error_logger_format_depth),
- logger:remove_handler_filter(logger_std_h,stop_all),
+ logger:remove_handler_filter(default,stop_all),
+ logger:remove_handler_filter(sasl,stop_all),
logger:remove_handler_filter(cth_log_redirect,stop_all)
end,
ok.
@@ -74,20 +138,17 @@ do_gen_server_crash(Config, Encoding) ->
SaslLog = filename:join(LogDir, "sasl.log"),
ok = filelib:ensure_dir(SaslLog),
- application:stop(sasl),
Modes = [write, {encoding, Encoding}],
- ok = application:set_env(kernel, logger_sasl_compatible, true),
- ok = application:set_env(sasl, sasl_error_logger, {file,SaslLog,Modes},
- [{persistent,true}]),
application:set_env(kernel, error_logger_format_depth, 30),
error_logger:logfile({open,KernelLog}),
- application:start(sasl),
- logger:i(print),
+ error_logger:add_report_handler(sasl_report_file_h,{SaslLog,Modes,all}),
+ ct:log("Logger config:~n~p",[logger:get_config()]),
+ ct:log("error_logger handlers: ~p",[error_logger:which_report_handlers()]),
crash_me(),
error_logger:logfile(close),
- application:stop(sasl),
+ error_logger:delete_report_handler(sasl_report_file_h),
check_file(KernelLog, utf8, 70000, 150000),
check_file(SaslLog, Encoding, 70000, 150000),
diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl
index ad61186921..6c913850b9 100644
--- a/lib/sasl/test/systools_SUITE.erl
+++ b/lib/sasl/test/systools_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1654,7 +1654,7 @@ abnormal_relup(Config) when is_list(Config) ->
ok.
-%% make_relup: Check relup can not be created is sasl is not in rel file.
+%% make_relup: Check relup cannot be created is sasl is not in rel file.
no_sasl_relup(Config) when is_list(Config) ->
{ok, OldDir} = file:get_cwd(),
{Dir1,Name1} = create_script(latest1_no_sasl,Config),
diff --git a/lib/sasl/vsn.mk b/lib/sasl/vsn.mk
index 52b168598a..0972ae20ba 100644
--- a/lib/sasl/vsn.mk
+++ b/lib/sasl/vsn.mk
@@ -1 +1 @@
-SASL_VSN = 3.1.2
+SASL_VSN = 3.2
diff --git a/lib/snmp/doc/src/Makefile b/lib/snmp/doc/src/Makefile
index 3ebee792f9..a6a9477b05 100644
--- a/lib/snmp/doc/src/Makefile
+++ b/lib/snmp/doc/src/Makefile
@@ -140,6 +140,7 @@ clean_man:
clean_html:
@echo "cleaning html:"
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
$(MAN7DIR)/%.7: $(MIBSDIR)/%.mib
@echo "processing $*"
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index 8d48cb911d..f64e0cca97 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -34,7 +34,23 @@
</header>
- <section><title>SNMP 5.2.10</title>
+ <section><title>SNMP 5.2.11</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The Snmp MIB compiler now allows using a
+ TEXTUAL-CONVENTION type before defining it.</p>
+ <p>
+ Own Id: OTP-14196 Aux Id: ERIERL-161 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SNMP 5.2.10</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/snmp/src/agent/snmpa_set_lib.erl b/lib/snmp/src/agent/snmpa_set_lib.erl
index 57507a36e8..97b8ddf7c4 100644
--- a/lib/snmp/src/agent/snmpa_set_lib.erl
+++ b/lib/snmp/src/agent/snmpa_set_lib.erl
@@ -46,9 +46,9 @@
%%* 6) IF value is outside the acceptable range THEN wrongValue.
%% 7) IF variable does not exist and could not ever be created
%% THEN noCreation.
-%% 8) IF variable can not be created now THEN inconsistentName.
-%% 9) IF value can not be set now THEN inconsistentValue.
-%%* 9) IF instances of the variable can not be modified THEN notWritable.
+%% 8) IF variable cannot be created now THEN inconsistentName.
+%% 9) IF value cannot be set now THEN inconsistentValue.
+%%* 9) IF instances of the variable cannot be modified THEN notWritable.
%% 10) IF an unavailable resource is needed THEN resourceUnavailable.
%% 11) IF any other error THEN genErr.
%% 12) Otherwise ok!
diff --git a/lib/snmp/src/agent/snmpa_trap.erl b/lib/snmp/src/agent/snmpa_trap.erl
index e75016f7ec..293d1f3ccf 100644
--- a/lib/snmp/src/agent/snmpa_trap.erl
+++ b/lib/snmp/src/agent/snmpa_trap.erl
@@ -830,11 +830,11 @@ do_send_v1_trap(Enter, Spec, V1Res, NVbs, ExtraInfo, NetIf, SysUpTime) ->
case lists:keyfind(transportDomainUdpIpv4, 1, Transports) of
false ->
?vtrace(
- "snmpa_trap: can not send v1 trap "
+ "snmpa_trap: cannot send v1 trap "
"without IPv4 domain: ~p",
[Transports]),
user_err(
- "snmpa_trap: can not send v1 trap "
+ "snmpa_trap: cannot send v1 trap "
"without IPv4 domain: ~p",
[Transports]);
DomainAddr ->
diff --git a/lib/snmp/src/compile/snmpc.erl b/lib/snmp/src/compile/snmpc.erl
index 4416626a4c..7f627d66d9 100644
--- a/lib/snmp/src/compile/snmpc.erl
+++ b/lib/snmp/src/compile/snmpc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -456,6 +456,7 @@ compile_parsed_data(#pdata{mib_name = MibName,
RelChk = get_relaxed_row_name_assign_check(Opts),
Data = #dldata{deprecated = Deprecated,
relaxed_row_name_assign_check = RelChk},
+ mc_new_type_loop(Definitions),
put(augmentations, false),
definitions_loop(Definitions, Data),
MibName.
@@ -481,7 +482,40 @@ do_update_imports([{{Mib, ImportsFromMib0},_Line}|Imports], Acc) ->
update_status(Name, Status) ->
#cdata{status_ets = Ets} = get(cdata),
ets:insert(Ets, {Name, Status}).
-
+
+
+mc_new_type_loop(
+ [{#mc_new_type{
+ name = NewTypeName,
+ macro = Macro,
+ syntax = OldType,
+ display_hint = DisplayHint},Line}|T]) ->
+ ?vlog2("typeloop -> new_type:"
+ "~n Macro: ~p"
+ "~n NewTypeName: ~p"
+ "~n OldType: ~p"
+ "~n DisplayHint: ~p",
+ [Macro, NewTypeName, OldType, DisplayHint], Line),
+ ensure_macro_imported(Macro,Line),
+ Types = (get(cdata))#cdata.asn1_types,
+ case lists:keysearch(NewTypeName, #asn1_type.aliasname, Types) of
+ {value,_} ->
+ snmpc_lib:print_error("Type ~w already defined.",
+ [NewTypeName],Line);
+ false ->
+ %% NameOfOldType = element(2,OldType),
+ ASN1 = snmpc_lib:make_ASN1type(OldType),
+ snmpc_lib:add_cdata(#cdata.asn1_types,
+ [ASN1#asn1_type{aliasname = NewTypeName,
+ imported = false,
+ display_hint = DisplayHint}])
+ end,
+ mc_new_type_loop(T);
+mc_new_type_loop([_|T]) ->
+ mc_new_type_loop(T);
+mc_new_type_loop([]) ->
+ ok.
+
%% A deprecated object
definitions_loop([{#mc_object_type{name = ObjName, status = deprecated},
@@ -745,32 +779,8 @@ definitions_loop([{#mc_object_type{name = NameOfTable,
ColMEs]),
definitions_loop(RestObjs, Data);
-definitions_loop([{#mc_new_type{name = NewTypeName,
- macro = Macro,
- syntax = OldType,
- display_hint = DisplayHint},Line}|T],
- Data) ->
- ?vlog2("defloop -> new_type:"
- "~n Macro: ~p"
- "~n NewTypeName: ~p"
- "~n OldType: ~p"
- "~n DisplayHint: ~p",
- [Macro, NewTypeName, OldType, DisplayHint], Line),
- ensure_macro_imported(Macro,Line),
- Types = (get(cdata))#cdata.asn1_types,
- case lists:keysearch(NewTypeName, #asn1_type.aliasname, Types) of
- {value,_} ->
- snmpc_lib:print_error("Type ~w already defined.",
- [NewTypeName],Line);
- false ->
- %% NameOfOldType = element(2,OldType),
- ASN1 = snmpc_lib:make_ASN1type(OldType),
- snmpc_lib:add_cdata(#cdata.asn1_types,
- [ASN1#asn1_type{aliasname = NewTypeName,
- imported = false,
- display_hint = DisplayHint}])
- end,
- definitions_loop(T, Data);
+definitions_loop([{#mc_new_type{},_}|T], Data) ->
+ definitions_loop(T, Data);
%% Plain variable
definitions_loop([{#mc_object_type{name = NewVarName,
diff --git a/lib/snmp/test/snmp_compiler_test.erl b/lib/snmp/test/snmp_compiler_test.erl
index 2b6bba4ee6..0a7b729d1f 100644
--- a/lib/snmp/test/snmp_compiler_test.erl
+++ b/lib/snmp/test/snmp_compiler_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -58,7 +58,8 @@
otp_10799/1,
otp_10808/1,
otp_14145/1,
- otp_13014/1
+ otp_13014/1,
+ otp_14196/1
]).
%%----------------------------------------------------------------------
@@ -138,7 +139,7 @@ all() ->
groups() ->
[{tickets, [],
[otp_6150, otp_8574, otp_8595, otp_10799, otp_10808, otp_14145,
- otp_13014]}].
+ otp_13014, otp_14196]}].
init_per_group(_GroupName, Config) ->
Config.
@@ -489,6 +490,22 @@ otp_13014(Config) when is_list(Config) ->
TableInfo,
ok.
+%%======================================================================
+
+otp_14196(suite) ->
+ [];
+otp_14196(Config) when is_list(Config) ->
+ put(tname, otp14196),
+ p("starting with Config: ~p~n", [Config]),
+
+ Dir = ?config(case_top_dir, Config),
+ MibDir = ?config(mib_dir, Config),
+ MibFile = join(MibDir, "OTP14196-MIB.mib"),
+ ?line {ok, Mib} =
+ snmpc:compile(MibFile, [{outdir, Dir}, {verbosity, trace}]),
+ p("Mib: ~n~p~n", [Mib]),
+ ok.
+
%%======================================================================
diff --git a/lib/snmp/test/snmp_test_data/OTP14196-MIB.mib b/lib/snmp/test/snmp_test_data/OTP14196-MIB.mib
new file mode 100644
index 0000000000..0b3c718a02
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/OTP14196-MIB.mib
@@ -0,0 +1,47 @@
+OTP14196-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, snmpModules, mib-2
+ FROM SNMPv2-SMI
+ TEXTUAL-CONVENTION
+ FROM SNMPv2-TC
+ OBJECT-GROUP
+ FROM SNMPv2-CONF
+ ;
+
+otp14196MIB MODULE-IDENTITY
+ LAST-UPDATED "1004210000Z"
+ ORGANIZATION ""
+ CONTACT-INFO
+ ""
+ DESCRIPTION
+ "Test mib for OTP-14196"
+ ::= { snmpModules 1 }
+
+testCompliances OBJECT IDENTIFIER ::= { otp14196MIB 1 }
+test OBJECT IDENTIFIER ::= { mib-2 15 }
+
+typeA OBJECT-TYPE
+ SYNTAX TypeAType
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "Test type for OTP-14196"
+ ::= { test 4711 }
+
+TypeAType ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ ""
+ SYNTAX INTEGER
+
+testGroups OBJECT IDENTIFIER ::= { testCompliances 1 }
+
+testGroupA OBJECT-GROUP
+ OBJECTS { typeA }
+ STATUS current
+ DESCRIPTION
+ ""
+ ::= { testGroups 17 }
+
+END
diff --git a/lib/snmp/test/test-mibs/ALARM-MIB.mib b/lib/snmp/test/test-mibs/ALARM-MIB.mib
index 18e43d4b4b..10d2adbff9 100644
--- a/lib/snmp/test/test-mibs/ALARM-MIB.mib
+++ b/lib/snmp/test/test-mibs/ALARM-MIB.mib
@@ -330,7 +330,7 @@ alarmModelRowStatus OBJECT-TYPE
cannot be used as an alarm suppression mechanism. Entries
that are notInService will disappear as described in RFC2579.
- This row can not be modified while it is being
+ This row cannot be modified while it is being
referenced by a value of alarmActiveModelPointer. In these
cases, an error of `inconsistentValue' will be returned to
the manager.
diff --git a/lib/snmp/test/test-mibs/SNMPv2-TC.mib b/lib/snmp/test/test-mibs/SNMPv2-TC.mib
index fd6a728ab5..1d75c4bbd8 100644
--- a/lib/snmp/test/test-mibs/SNMPv2-TC.mib
+++ b/lib/snmp/test/test-mibs/SNMPv2-TC.mib
@@ -454,7 +454,7 @@ value | | see 1| ->C| ->D
associated with this column or that there is no
conceptual row for which this column would be
accessible in the MIB view used by the retrieval. As
- such, the management station can not issue any
+ such, the management station cannot issue any
management protocol set operations to create an
instance of this column.
@@ -576,7 +576,7 @@ value | | see 1| ->C| ->D
associated with this column or that there is no
conceptual row for which this column would be
accessible in the MIB view used by the retrieval. As
- such, the management station can not issue any
+ such, the management station cannot issue any
management protocol set operations to create an
instance of this column.
diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk
index 2c97683625..96123f02f5 100644
--- a/lib/snmp/vsn.mk
+++ b/lib/snmp/vsn.mk
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = snmp
-SNMP_VSN = 5.2.10
+SNMP_VSN = 5.2.11
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)"
diff --git a/lib/ssh/doc/src/Makefile b/lib/ssh/doc/src/Makefile
index 7c4dbd7af8..77fa356092 100644
--- a/lib/ssh/doc/src/Makefile
+++ b/lib/ssh/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2017. All Rights Reserved.
+# Copyright Ericsson AB 2004-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -119,6 +119,7 @@ html: images $(HTML_REF_MAN_FILE)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f $(SPECS_FILES)
diff --git a/lib/ssh/doc/src/configure_algos.xml b/lib/ssh/doc/src/configure_algos.xml
index 15aece8968..fa45b1cb4c 100644
--- a/lib/ssh/doc/src/configure_algos.xml
+++ b/lib/ssh/doc/src/configure_algos.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2017</year>
- <year>2017</year>
+ <year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/ssh/doc/src/introduction.xml b/lib/ssh/doc/src/introduction.xml
index 6fd8425adf..8444daf0cc 100644
--- a/lib/ssh/doc/src/introduction.xml
+++ b/lib/ssh/doc/src/introduction.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2012</year>
- <year>2016</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index d0ed674eee..58e8c9ab5b 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -30,6 +30,195 @@
<file>notes.xml</file>
</header>
+<section><title>Ssh 4.7</title>
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ If the daemon port listener is restarted, it could
+ potentially fail with <c>eaddrinuse</c> if the timing is
+ unlucky. It will now retry and exponentially back off the
+ listener restart a few times before failing.</p>
+ <p>
+ Own Id: OTP-14955</p>
+ </item>
+ <item>
+ <p>
+ A channel callback module always got the module name as
+ reason in a call to terminate. Now it will get the proper
+ Reason, usually 'normal'.</p>
+ <p>
+ Own Id: OTP-15084</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The option <c>exec</c> has new option values defined to
+ make it much more easy to implement an own <c>exec</c>
+ server.</p>
+ <p>
+ An option called <c>exec</c> for daemons implementing the
+ handling of 'exec' requests has existed a long time but
+ has been undocumented. The old undocumented value - as
+ well as its behavior - is kept for compatibility EXCEPT
+ that error messages are changed and are sent as
+ "stderror" text.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14851</p>
+ </item>
+ <item>
+ <p>
+ Updated ssh_connection:shell/2 documentation.</p>
+ <p>
+ Own Id: OTP-14880</p>
+ </item>
+ <item>
+ <p>
+ The experimental <c>ssh_dbg</c> module is completely
+ re-written. Its purpose is to make tracing and debugging
+ easier on deployed systems.</p>
+ <p>
+ Own Id: OTP-14896</p>
+ </item>
+ <item>
+ <p>
+ The SSH supervisor structure has been slightly changed.
+ This makes stopping the ssh application considerably
+ faster if there are open connections. This is important
+ in for example restarts.</p>
+ <p>
+ Own Id: OTP-14988</p>
+ </item>
+ <item>
+ <p>
+ The type specifications in SSH are completly reworked and
+ the following types are renamed:</p>
+ <p>
+ <c>ssh:ssh_connection_ref()</c> is changed to
+ <c>ssh:connection_ref()</c>, </p>
+ <p>
+ <c>ssh:ssh_daemon_ref()</c> is changed to
+ <c>ssh:daemon_ref()</c>,</p>
+ <p>
+ <c>ssh:ssh_channel_id()</c> is changed to
+ <c>ssh:channel_id()</c>.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15002 Aux Id: OTP-15030 </p>
+ </item>
+ <item>
+ <p>
+ The internal timer handling in SSH is now based on the
+ gen_statem timers.</p>
+ <p>
+ Own Id: OTP-15019</p>
+ </item>
+ <item>
+ <p>
+ Removed the undocumented and unused modules
+ <c>ssh_client_key.erl</c> and <c>ssh_server_key.erl</c>.</p>
+ <p>
+ Own Id: OTP-15028</p>
+ </item>
+ <item>
+ <p>
+ The Reference Manual pages are partly updated.</p>
+ <p>
+ The ssh page is now generated from specs and types, is
+ restructured and is partly rephrased.</p>
+ <p>
+ The ssh_channel, ssh_connection, ssh_client_key_api,
+ ssh_server_key_api and ssh_sftp pages are updated with
+ links, correct type names and some minor changes.</p>
+ <p>
+ Own Id: OTP-15030 Aux Id: OTP-15002 </p>
+ </item>
+ <item>
+ <p>
+ The behaviors <c>ssh_channel</c> and
+ <c>ssh_daemon_channel</c> are renamed to
+ <c>ssh_client_channel</c> and <c>ssh_server_channel</c>
+ respectively.</p>
+ <p>
+ The old modules are kept for compatibility but should
+ preferably be replaced when updating callback modules
+ referring them.</p>
+ <p>
+ Own Id: OTP-15041</p>
+ </item>
+ <item>
+ <p>
+ New test suite for channels.</p>
+ <p>
+ Own Id: OTP-15051</p>
+ </item>
+ <item>
+ <p>
+ The <c>rekey_limit</c> option could now set the max time
+ as well as the previously max data amount.</p>
+ <p>
+ Own Id: OTP-15069 Aux Id: ERL-617 </p>
+ </item>
+ <item>
+ <p>
+ Changed process exit supervision from links to monitors.</p>
+ <p>
+ Own Id: OTP-15082</p>
+ </item>
+ <item>
+ <p>
+ Better handling of misbehaving channel callback modules.</p>
+ <p>
+ Own Id: OTP-15083</p>
+ </item>
+ <item>
+ <p>
+ A new moduli file is generated. This file is used for the
+ recommended <c>diffie-hellman-group-exchange-sha256</c>
+ key exchange algorithm in SSH.</p>
+ <p>
+ Own Id: OTP-15113</p>
+ </item>
+ </list>
+ </section>
+</section>
+
+<section><title>Ssh 4.6.9.1</title>
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ SFTP clients reported the error reason <c>""</c> if a
+ non-OTP sftp server was killed during a long file
+ transmission.</p>
+ <p>
+ Now the signal name (for example <c>"KILL"</c>) will be
+ the error reason if the server's reason is empty.</p>
+ <p>
+ The documentation also lacked type information about this
+ class of errors.</p>
+ <p>
+ Own Id: OTP-15148 Aux Id: ERIERL-194 </p>
+ </item>
+ <item>
+ <p>
+ Fix ssh_sftp decode error for sftp protocol version 4</p>
+ <p>
+ Own Id: OTP-15149 Aux Id: ERIERL-199 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Ssh 4.6.9</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -2576,7 +2765,7 @@
</item>
<item>
<p>
- Fixed internal error on when client and server can not
+ Fixed internal error on when client and server cannot
agree o which authmethod to use.</p>
<p>
Own Id: OTP-10731 Aux Id: seq12237 </p>
diff --git a/lib/ssh/doc/src/ref_man.xml b/lib/ssh/doc/src/ref_man.xml
index 76e6520f94..df37b0244f 100644
--- a/lib/ssh/doc/src/ref_man.xml
+++ b/lib/ssh/doc/src/ref_man.xml
@@ -4,7 +4,7 @@
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index 407956cc6f..3bc62073a2 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -46,7 +46,7 @@
In that encrypted connection one or more channels could be opened with
<seealso marker="ssh_connection#session_channel/2">ssh_connection:session_channel/2,4</seealso>.
</p>
- <p>Each channel is an isolated "pipe" between a client-side process and a server-side process. Thoose process
+ <p>Each channel is an isolated "pipe" between a client-side process and a server-side process. Those process
pairs could handle for example file transfers (sftp) or remote command execution (shell, exec and/or cli).
If a custom shell is implemented, the user of the client could execute the special commands remotely. Note that
the user is not necessarily a human but probably a system interfacing the SSH app.
diff --git a/lib/ssh/doc/src/ssh_app.xml b/lib/ssh/doc/src/ssh_app.xml
index 6d180a5272..9ec909d733 100644
--- a/lib/ssh/doc/src/ssh_app.xml
+++ b/lib/ssh/doc/src/ssh_app.xml
@@ -4,7 +4,7 @@
<appref>
<header>
<copyright>
- <year>2012</year><year>2017</year>
+ <year>2012</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -130,39 +130,47 @@
For the list on a particular installation, use the command
<seealso marker="ssh:ssh#default_algorithms/0">ssh:default_algorithms/0</seealso>.
The user may override the default algorithm configuration both on the server side and the client side.
- See the option <c>preferred_algorithms</c> in the <seealso marker="ssh:ssh#daemon/1">ssh:daemon/1,2,3</seealso> and
+ See the options
+ <seealso marker="ssh:ssh#type-preferred_algorithms_common_option">preferred_algorithms</seealso>
+ and
+ <seealso marker="ssh:ssh#type-modify_algorithms_common_option">modify_algorithms</seealso>
+ in the <seealso marker="ssh:ssh#daemon/1">ssh:daemon/1,2,3</seealso> and
<seealso marker="ssh:ssh#connect/3">ssh:connect/3,4</seealso> functions.
</p>
- <p>Supported algorithms are:</p>
+ <p>Supported algorithms are (in the default order):</p>
<marker id="supported_algos"></marker>
<taglist>
<tag>Key exchange algorithms</tag>
<item>
<list type="bulleted">
- <item>ecdh-sha2-nistp256</item>
<item>ecdh-sha2-nistp384</item>
<item>ecdh-sha2-nistp521</item>
- <item>diffie-hellman-group-exchange-sha1</item>
+ <item>ecdh-sha2-nistp256</item>
<item>diffie-hellman-group-exchange-sha256</item>
- <item>diffie-hellman-group14-sha1</item>
- <item>diffie-hellman-group14-sha256</item>
<item>diffie-hellman-group16-sha512</item>
<item>diffie-hellman-group18-sha512</item>
- <item>(diffie-hellman-group1-sha1, retired: can be enabled with the <c>preferred_algorithms</c> option)</item>
+ <item>diffie-hellman-group14-sha256</item>
+ <item>diffie-hellman-group14-sha1</item>
+ <item>diffie-hellman-group-exchange-sha1</item>
+ <item>(diffie-hellman-group1-sha1, retired: It can be enabled with the
+ <seealso marker="ssh:ssh#type-preferred_algorithms_common_option">preferred_algorithms</seealso>
+ or
+ <seealso marker="ssh:ssh#type-modify_algorithms_common_option">modify_algorithms</seealso>
+ options)</item>
</list>
</item>
<tag>Public key algorithms</tag>
<item>
<list type="bulleted">
- <item>ecdsa-sha2-nistp256</item>
<item>ecdsa-sha2-nistp384</item>
<item>ecdsa-sha2-nistp521</item>
+ <item>ecdsa-sha2-nistp256</item>
<item>ssh-rsa</item>
- <item>ssh-dss</item>
<item>rsa-sha2-256</item>
<item>rsa-sha2-512</item>
+ <item>ssh-dss</item>
</list>
</item>
@@ -178,11 +186,11 @@
<tag>Encryption algorithms (ciphers)</tag>
<item>
<list type="bulleted">
- <item>[email protected]</item>
<item>[email protected]</item>
- <item>aes128-ctr</item>
- <item>aes192-ctr</item>
<item>aes256-ctr</item>
+ <item>aes192-ctr</item>
+ <item>[email protected]</item>
+ <item>aes128-ctr</item>
<item>aes128-cbc</item>
<item>3des-cbc</item>
<item>(AEAD_AES_128_GCM, not enabled per default)</item>
@@ -241,7 +249,11 @@
<item><url href="https://tools.ietf.org/html/rfc4253">RFC 4253</url>, The Secure Shell (SSH) Transport Layer Protocol.
<p>Except</p>
<list type="bulleted">
- <item>8.1. diffie-hellman-group1-sha1. Disabled by default, can be enabled with the <c>preferred_algorithms</c> option.</item>
+ <item>8.1. diffie-hellman-group1-sha1. Disabled by default, can be enabled with the
+ <seealso marker="ssh:ssh#type-preferred_algorithms_common_option">preferred_algorithms</seealso>
+ or
+ <seealso marker="ssh:ssh#type-modify_algorithms_common_option">modify_algorithms</seealso>
+ options.</item>
</list>
<p/>
</item>
@@ -280,7 +292,10 @@
<p><marker id="rfc5647_note"/>There is an ambiguity in the synchronized selection of cipher and mac algorithm.
This is resolved by OpenSSH in the ciphers [email protected] and [email protected] which are implemented.
If the explicit ciphers and macs AEAD_AES_128_GCM or AEAD_AES_256_GCM are needed,
- they could be enabled with the option preferred_algorithms.
+ they could be enabled with the options
+ <seealso marker="ssh:ssh#type-preferred_algorithms_common_option">preferred_algorithms</seealso>
+ or
+ <seealso marker="ssh:ssh#type-modify_algorithms_common_option">modify_algorithms</seealso>.
</p>
<warning>
<p>
@@ -322,10 +337,18 @@
<p>Deviations:</p>
<list type="bulleted">
<item>The <c>diffie-hellman-group1-sha1</c> is not enabled by default, but is still supported and can be enabled
- with the option <c>preferred-algorithms</c></item>
+ with the options
+ <seealso marker="ssh:ssh#type-preferred_algorithms_common_option">preferred_algorithms</seealso>
+ or
+ <seealso marker="ssh:ssh#type-modify_algorithms_common_option">modify_algorithms</seealso>.
+ </item>
<item>The questionable sha1-based algorithms <c>diffie-hellman-group-exchange-sha1</c> and
<c>diffie-hellman-group14-sha1</c> are still enabled by default for compatibility with ancient clients and servers.
- They can be disabled with the option <c>preferred-algorithms</c></item>
+ They can be disabled with the options
+ <seealso marker="ssh:ssh#type-preferred_algorithms_common_option">preferred_algorithms</seealso>
+ or
+ <seealso marker="ssh:ssh#type-modify_algorithms_common_option">modify_algorithms</seealso>.
+ They will be disabled by default when the draft is turned into an RFC.</item>
</list>
<p/>
</item>
diff --git a/lib/ssh/doc/src/ssh_client_channel.xml b/lib/ssh/doc/src/ssh_client_channel.xml
index eed49beffa..9be4007c68 100644
--- a/lib/ssh/doc/src/ssh_client_channel.xml
+++ b/lib/ssh/doc/src/ssh_client_channel.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2009</year>
- <year>2016</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/ssh/doc/src/ssh_client_key_api.xml b/lib/ssh/doc/src/ssh_client_key_api.xml
index 9fc54341ed..bc77756147 100644
--- a/lib/ssh/doc/src/ssh_client_key_api.xml
+++ b/lib/ssh/doc/src/ssh_client_key_api.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2012</year>
- <year>2016</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/ssh/doc/src/ssh_connection.xml b/lib/ssh/doc/src/ssh_connection.xml
index 821dfef93d..8e1cf156a8 100644
--- a/lib/ssh/doc/src/ssh_connection.xml
+++ b/lib/ssh/doc/src/ssh_connection.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2008</year>
- <year>2015</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/ssh/doc/src/ssh_protocol.xml b/lib/ssh/doc/src/ssh_protocol.xml
index 53f0524b97..0d99a96997 100644
--- a/lib/ssh/doc/src/ssh_protocol.xml
+++ b/lib/ssh/doc/src/ssh_protocol.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2013</year><year>2016</year>
+ <year>2013</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/ssh/doc/src/ssh_server_channel.xml b/lib/ssh/doc/src/ssh_server_channel.xml
index af51ec470b..31ba9a3231 100644
--- a/lib/ssh/doc/src/ssh_server_channel.xml
+++ b/lib/ssh/doc/src/ssh_server_channel.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2009</year>
- <year>2016</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/ssh/doc/src/ssh_server_key_api.xml b/lib/ssh/doc/src/ssh_server_key_api.xml
index cf3b1d319f..e2a31bd5f5 100644
--- a/lib/ssh/doc/src/ssh_server_key_api.xml
+++ b/lib/ssh/doc/src/ssh_server_key_api.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2012</year>
- <year>2015</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/ssh/doc/src/ssh_sftp.xml b/lib/ssh/doc/src/ssh_sftp.xml
index 60f643d052..ea55126cb3 100644
--- a/lib/ssh/doc/src/ssh_sftp.xml
+++ b/lib/ssh/doc/src/ssh_sftp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2005</year><year>2017</year>
+ <year>2005</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -46,9 +46,9 @@
<taglist>
<tag><c>reason()</c></tag>
<item>
- <p>= <c>atom()</c> A description of the reason why an operation failed.</p>
+ <p>= <c>atom() | string() | tuple() </c>A description of the reason why an operation failed.</p>
<p>
- The value is formed from the sftp error codes in the protocol-level responses as defined in
+ The <c>atom()</c> value is formed from the sftp error codes in the protocol-level responses as defined in
<url href="https://tools.ietf.org/id/draft-ietf-secsh-filexfer-13.txt">draft-ietf-secsh-filexfer-13.txt</url>
section 9.1.
</p>
@@ -57,6 +57,10 @@
E.g. the error code <c>SSH_FX_NO_SUCH_FILE</c>
will cause the <c>reason()</c> to be <c>no_such_file</c>.
</p>
+ <p>The <c>string()</c> reason is the error information from the server in case of an exit-signal. If that information is empty, the reason is the exit signal name.
+ </p>
+ <p>The <c>tuple()</c> reason are other errors like the <c>{exit_status,integer()}</c> if the exit status is not 0.
+ </p>
</item>
<tag><c>connection_ref() =</c></tag>
diff --git a/lib/ssh/doc/src/ssh_sftpd.xml b/lib/ssh/doc/src/ssh_sftpd.xml
index a25ce123b3..3b34150e98 100644
--- a/lib/ssh/doc/src/ssh_sftpd.xml
+++ b/lib/ssh/doc/src/ssh_sftpd.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2005</year><year>2016</year>
+ <year>2005</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/ssh/doc/src/usersguide.xml b/lib/ssh/doc/src/usersguide.xml
index d902df6848..38ffa48cde 100644
--- a/lib/ssh/doc/src/usersguide.xml
+++ b/lib/ssh/doc/src/usersguide.xml
@@ -4,7 +4,7 @@
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2012</year><year>2016</year>
+ <year>2012</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/ssh/doc/src/using_ssh.xml b/lib/ssh/doc/src/using_ssh.xml
index efd2a997f5..80662e9a70 100644
--- a/lib/ssh/doc/src/using_ssh.xml
+++ b/lib/ssh/doc/src/using_ssh.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2012</year>
- <year>2017</year>
+ <year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile
index 5e4efb6b99..6d64a45112 100644
--- a/lib/ssh/src/Makefile
+++ b/lib/ssh/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2017. All Rights Reserved.
+# Copyright Ericsson AB 2004-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 7ddb1ca5be..086fa6e5f8 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -1,7 +1,7 @@
%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index 2efd239aae..01c44cb371 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -492,4 +492,29 @@
-define(wr_record(N), ?wr_record(N, [])).
+%% Circular trace buffer macros
+
+-record(circ_buf_entry,
+ {
+ module,
+ line,
+ function,
+ pid = self(),
+ value
+ }).
+
+-define(CIRC_BUF_IN(VALUE),
+ ssh_dbg:cbuf_in(
+ #circ_buf_entry{module = ?MODULE,
+ line = ?LINE,
+ function = {?FUNCTION_NAME,?FUNCTION_ARITY},
+ pid = self(),
+ value = (VALUE)
+ })
+ ).
+
+-define(CIRC_BUF_IN_ONCE(VALUE),
+ ((fun(V) -> ?CIRC_BUF_IN(V), V end)(VALUE))
+ ).
+
-endif. % SSH_HRL defined
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index 516a9febaa..11ce80354e 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_acceptor_sup.erl b/lib/ssh/src/ssh_acceptor_sup.erl
index 10fd4452bf..15a2238dd3 100644
--- a/lib/ssh/src/ssh_acceptor_sup.erl
+++ b/lib/ssh/src/ssh_acceptor_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index bf3f5a68e4..4e4aa440de 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_channel.erl b/lib/ssh/src/ssh_channel.erl
index 81c495a815..443bd05086 100644
--- a/lib/ssh/src/ssh_channel.erl
+++ b/lib/ssh/src/ssh_channel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl
index fcc1d3d59f..af51356355 100644
--- a/lib/ssh/src/ssh_cli.erl
+++ b/lib/ssh/src/ssh_cli.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_client_channel.erl b/lib/ssh/src/ssh_client_channel.erl
index f20007baaf..f985d8e273 100644
--- a/lib/ssh/src/ssh_client_channel.erl
+++ b/lib/ssh/src/ssh_client_channel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -180,6 +180,8 @@ init([Options]) ->
{stop, Why} ->
{stop, Why}
catch
+ _:undef ->
+ {stop, {bad_channel_callback_module,Cb}};
_:Reason ->
{stop, Reason}
end.
@@ -305,8 +307,8 @@ terminate(Reason, #state{cm = ConnectionManager,
close_sent = false} = State) ->
catch ssh_connection:close(ConnectionManager, ChannelId),
terminate(Reason, State#state{close_sent = true});
-terminate(_, #state{channel_cb = Cb, channel_state = ChannelState}) ->
- catch Cb:terminate(Cb, ChannelState),
+terminate(Reason, #state{channel_cb = Cb, channel_state = ChannelState}) ->
+ catch Cb:terminate(Reason, ChannelState),
ok.
%%--------------------------------------------------------------------
diff --git a/lib/ssh/src/ssh_client_key_api.erl b/lib/ssh/src/ssh_client_key_api.erl
index d0d8ab25d6..384740b786 100644
--- a/lib/ssh/src/ssh_client_key_api.erl
+++ b/lib/ssh/src/ssh_client_key_api.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_connect.hrl b/lib/ssh/src/ssh_connect.hrl
index 3c61638285..9a060b8304 100644
--- a/lib/ssh/src/ssh_connect.hrl
+++ b/lib/ssh/src/ssh_connect.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index ed03b4e2ed..83f85b1d8e 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -498,25 +498,24 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
data = Data},
#connection{channel_cache = Cache} = Connection, server) ->
<<?DEC_BIN(SsName,_SsLen)>> = Data,
-
- #channel{remote_id = RemoteId} = Channel0 =
+ #channel{remote_id=RemoteId} = Channel =
ssh_client_channel:cache_lookup(Cache, ChannelId),
-
- ReplyMsg = {subsystem, ChannelId, WantReply, binary_to_list(SsName)},
-
- try
- {ok, Pid} = start_subsystem(SsName, Connection, Channel0, ReplyMsg),
- erlang:monitor(process, Pid),
- Channel = Channel0#channel{user = Pid},
- ssh_client_channel:cache_update(Cache, Channel),
- Reply = {connection_reply,
- channel_success_msg(RemoteId)},
- {[Reply], Connection}
- catch
- _:_ ->
- ErrorReply = {connection_reply, channel_failure_msg(RemoteId)},
- {[ErrorReply], Connection}
- end;
+ Reply =
+ try
+ start_subsystem(SsName, Connection, Channel,
+ {subsystem, ChannelId, WantReply, binary_to_list(SsName)})
+ of
+ {ok, Pid} ->
+ erlang:monitor(process, Pid),
+ ssh_client_channel:cache_update(Cache, Channel#channel{user=Pid}),
+ channel_success_msg(RemoteId);
+ {error,_Error} ->
+ channel_failure_msg(RemoteId)
+ catch
+ _:_ ->
+ channel_failure_msg(RemoteId)
+ end,
+ {[{connection_reply,Reply}], Connection};
handle_msg(#ssh_msg_channel_request{request_type = "subsystem"},
Connection, client) ->
@@ -822,7 +821,12 @@ start_channel(Cb, Id, Args, SubSysSup, Exec, Opts) ->
ChannelSup = ssh_subsystem_sup:channel_supervisor(SubSysSup),
case max_num_channels_not_exceeded(ChannelSup, Opts) of
true ->
- ssh_server_channel_sup:start_child(ChannelSup, Cb, Id, Args, Exec);
+ case ssh_server_channel_sup:start_child(ChannelSup, Cb, Id, Args, Exec) of
+ {error,{Error,_Info}} ->
+ throw(Error);
+ Others ->
+ Others
+ end;
false ->
throw(max_num_channels_exceeded)
end.
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index f1ff3a70e2..8e4831a601 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1345,11 +1345,11 @@ handle_event(info, {Proto, Sock, NewData}, StateName, D0 = #data{socket = Sock,
{next_event, internal, Msg}
]}
catch
- C:E ->
+ C:E:ST ->
{Shutdown, D} =
?send_disconnect(?SSH_DISCONNECT_PROTOCOL_ERROR,
io_lib:format("Bad packet: Decrypted, but can't decode~n~p:~p~n~p",
- [C,E,erlang:get_stacktrace()]),
+ [C,E,ST]),
StateName, D1),
{stop, Shutdown, D}
end;
@@ -1378,10 +1378,10 @@ handle_event(info, {Proto, Sock, NewData}, StateName, D0 = #data{socket = Sock,
StateName, D0),
{stop, Shutdown, D}
catch
- C:E ->
+ C:E:ST ->
{Shutdown, D} =
?send_disconnect(?SSH_DISCONNECT_PROTOCOL_ERROR,
- io_lib:format("Bad packet: Couldn't decrypt~n~p:~p~n~p",[C,E,erlang:get_stacktrace()]),
+ io_lib:format("Bad packet: Couldn't decrypt~n~p:~p~n~p",[C,E,ST]),
StateName, D0),
{stop, Shutdown, D}
end;
@@ -1770,6 +1770,10 @@ set_kex_overload_prefix(Msg = <<?BYTE(Op),_/binary>>, #data{ssh_params=SshParams
case catch atom_to_list(kex(SshParams)) of
"ecdh-sha2-" ++ _ ->
<<"ecdh",Msg/binary>>;
+ "curve25519-" ++ _ ->
+ <<"ecdh",Msg/binary>>;
+ "curve448-" ++ _ ->
+ <<"ecdh",Msg/binary>>;
"diffie-hellman-group-exchange-" ++ _ ->
<<"dh_gex",Msg/binary>>;
"diffie-hellman-group" ++ _ ->
diff --git a/lib/ssh/src/ssh_connection_sup.erl b/lib/ssh/src/ssh_connection_sup.erl
index 2e8450090a..79804b8630 100644
--- a/lib/ssh/src/ssh_connection_sup.erl
+++ b/lib/ssh/src/ssh_connection_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_daemon_channel.erl b/lib/ssh/src/ssh_daemon_channel.erl
index fdb6c10971..30c4773a7a 100644
--- a/lib/ssh/src/ssh_daemon_channel.erl
+++ b/lib/ssh/src/ssh_daemon_channel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_dbg.erl b/lib/ssh/src/ssh_dbg.erl
index 2ee4237e05..4fe15b24d3 100644
--- a/lib/ssh/src/ssh_dbg.erl
+++ b/lib/ssh/src/ssh_dbg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -54,7 +54,13 @@
start_tracer/0, start_tracer/1,
on/1, on/0,
off/1, off/0,
- go_on/0
+ go_on/0,
+ %% Circular buffer
+ cbuf_start/0, cbuf_start/1,
+ cbuf_stop_clear/0,
+ cbuf_in/1,
+ cbuf_list/0,
+ fmt_cbuf_items/0, fmt_cbuf_item/1
]).
-export([shrink_bin/1,
@@ -71,6 +77,8 @@
-behaviour(gen_server).
-define(SERVER, ?MODULE).
+-define(CALL_TIMEOUT, 15000). % 3x the default
+
%%%================================================================
-define(ALL_DBG_TYPES, get_all_dbg_types()).
@@ -107,7 +115,7 @@ start_tracer(WriteFun) when is_function(WriteFun,3) ->
start_tracer(WriteFun, InitAcc) when is_function(WriteFun, 3) ->
Handler =
fun(Arg, Acc0) ->
- try_all_types_in_all_modules(gen_server:call(?SERVER, get_on),
+ try_all_types_in_all_modules(gen_server:call(?SERVER, get_on, ?CALL_TIMEOUT),
Arg, WriteFun,
Acc0)
end,
@@ -122,7 +130,7 @@ off() -> off(?ALL_DBG_TYPES). % A bit overkill...
off(Type) -> switch(off, Type).
go_on() ->
- IsOn = gen_server:call(?SERVER, get_on),
+ IsOn = gen_server:call(?SERVER, get_on, ?CALL_TIMEOUT),
on(IsOn).
%%%----------------------------------------------------------------
@@ -253,7 +261,7 @@ switch(X, Types) when is_list(Types) ->
end,
case lists:usort(Types) -- ?ALL_DBG_TYPES of
[] ->
- gen_server:call(?SERVER, {switch,X,Types});
+ gen_server:call(?SERVER, {switch,X,Types}, ?CALL_TIMEOUT);
L ->
{error, {unknown, L}}
end.
@@ -331,3 +339,103 @@ ts({_,_,Usec}=Now) when is_integer(Usec) ->
io_lib:format("~.2.0w:~.2.0w:~.2.0w.~.6.0w",[HH,MM,SS,Usec]);
ts(_) ->
"-".
+
+%%%================================================================
+-define(CIRC_BUF, circ_buf).
+
+cbuf_start() ->
+ cbuf_start(20).
+
+cbuf_start(CbufMaxLen) ->
+ put(?CIRC_BUF, {CbufMaxLen,queue:new()}),
+ ok.
+
+
+cbuf_stop_clear() ->
+ case erase(?CIRC_BUF) of
+ undefined ->
+ [];
+ {_CbufMaxLen,Queue} ->
+ queue:to_list(Queue)
+ end.
+
+
+cbuf_in(Value) ->
+ case get(?CIRC_BUF) of
+ undefined ->
+ disabled;
+ {CbufMaxLen,Queue} ->
+ UpdatedQueue =
+ try queue:head(Queue) of
+ {Value, TS0, Cnt0} ->
+ %% Same Value as last saved in the queue
+ queue:in_r({Value, TS0, Cnt0+1},
+ queue:drop(Queue)
+ );
+ _ ->
+ queue:in_r({Value, erlang:timestamp(), 1},
+ truncate_cbuf(Queue, CbufMaxLen)
+ )
+ catch
+ error:empty ->
+ queue:in_r({Value, erlang:timestamp(), 1}, Queue)
+ end,
+ put(?CIRC_BUF, {CbufMaxLen,UpdatedQueue}),
+ ok
+ end.
+
+
+cbuf_list() ->
+ case get(?CIRC_BUF) of
+ undefined ->
+ [];
+ {_CbufMaxLen,Queue} ->
+ queue:to_list(Queue)
+ end.
+
+
+truncate_cbuf(Q, CbufMaxLen) ->
+ case queue:len(Q) of
+ N when N>=CbufMaxLen ->
+ truncate_cbuf(element(2,queue:out_r(Q)), CbufMaxLen);
+ _ ->
+ Q
+ end.
+
+fmt_cbuf_items() ->
+ lists:flatten(
+ io_lib:format("Circular trace buffer. Latest item first.~n~s~n",
+ [case get(?CIRC_BUF) of
+ {Max,_} ->
+ L = cbuf_list(),
+ [io_lib:format("==== ~.*w: ~s~n",[num_digits(Max),N,fmt_cbuf_item(X)]) ||
+ {N,X} <- lists:zip(lists:seq(1,length(L)), L)
+ ];
+ _ ->
+ io_lib:format("Not started.~n",[])
+ end])).
+
+
+num_digits(0) -> 1;
+num_digits(N) when N>0 -> 1+trunc(math:log10(N)).
+
+
+fmt_cbuf_item({Value, TimeStamp, N}) ->
+ io_lib:format("~s~s~n~s~n",
+ [fmt_ts(TimeStamp),
+ [io_lib:format(" (Repeated ~p times)",[N]) || N>1],
+ fmt_value(Value)]).
+
+
+fmt_ts(TS = {_,_,Us}) ->
+ {{YY,MM,DD},{H,M,S}} = calendar:now_to_universal_time(TS),
+ io_lib:format("~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w.~.6.0w UTC",[YY,MM,DD,H,M,S,Us]).
+
+fmt_value(#circ_buf_entry{module = M,
+ line = L,
+ function = {F,A},
+ pid = Pid,
+ value = V}) ->
+ io_lib:format("~p:~p ~p/~p ~p~n~s",[M,L,F,A,Pid,fmt_value(V)]);
+fmt_value(Value) ->
+ io_lib:format("~p",[Value]).
diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl
index 9cab2fe0bd..832952ed52 100644
--- a/lib/ssh/src/ssh_file.erl
+++ b/lib/ssh/src/ssh_file.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_info.erl b/lib/ssh/src/ssh_info.erl
index ee244f1432..79cd95e422 100644
--- a/lib/ssh/src/ssh_info.erl
+++ b/lib/ssh/src/ssh_info.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl
index a2251eab97..55c0548c9b 100644
--- a/lib/ssh/src/ssh_message.erl
+++ b/lib/ssh/src/ssh_message.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_no_io.erl b/lib/ssh/src/ssh_no_io.erl
index 25be0023e9..31963118cb 100644
--- a/lib/ssh/src/ssh_no_io.erl
+++ b/lib/ssh/src/ssh_no_io.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_options.erl b/lib/ssh/src/ssh_options.erl
index fe95d2ac54..bc9f2156bc 100644
--- a/lib/ssh/src/ssh_options.erl
+++ b/lib/ssh/src/ssh_options.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_server_channel.erl b/lib/ssh/src/ssh_server_channel.erl
index f1c9a85639..555080e9ee 100644
--- a/lib/ssh/src/ssh_server_channel.erl
+++ b/lib/ssh/src/ssh_server_channel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_server_channel_sup.erl b/lib/ssh/src/ssh_server_channel_sup.erl
index 70799db714..ff74061bb3 100644
--- a/lib/ssh/src/ssh_server_channel_sup.erl
+++ b/lib/ssh/src/ssh_server_channel_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_server_key_api.erl b/lib/ssh/src/ssh_server_key_api.erl
index a285bf9475..ef1fe7d69c 100644
--- a/lib/ssh/src/ssh_server_key_api.erl
+++ b/lib/ssh/src/ssh_server_key_api.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl
index 5984713ec9..1b2ba5a50b 100644
--- a/lib/ssh/src/ssh_sftp.erl
+++ b/lib/ssh/src/ssh_sftp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -171,21 +171,16 @@ start_channel(Host, Port, UserOptions) ->
stop_channel(Pid) ->
case is_process_alive(Pid) of
true ->
- OldValue = process_flag(trap_exit, true),
- link(Pid),
- exit(Pid, ssh_sftp_stop_channel),
- receive
- {'EXIT', Pid, normal} ->
- ok
- after 5000 ->
- exit(Pid, kill),
- receive
- {'EXIT', Pid, killed} ->
- ok
- end
- end,
- process_flag(trap_exit, OldValue),
- ok;
+ MonRef = erlang:monitor(process, Pid),
+ unlink(Pid),
+ exit(Pid, ssh_sftp_stop_channel),
+ receive {'DOWN',MonRef,_,_,_} -> ok
+ after
+ 1000 ->
+ exit(Pid, kill),
+ erlang:demonitor(MonRef, [flush]),
+ ok
+ end;
false ->
ok
end.
@@ -803,13 +798,22 @@ handle_ssh_msg({ssh_cm, _, {signal, _, _}}, State) ->
%% Ignore signals according to RFC 4254 section 6.9.
{ok, State};
-handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, _, Error, _}},
+handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, Signal, Error0, _}},
State0) ->
+ Error =
+ case Error0 of
+ "" -> Signal;
+ _ -> Error0
+ end,
State = reply_all(State0, {error, Error}),
{stop, ChannelId, State};
handle_ssh_msg({ssh_cm, _, {exit_status, ChannelId, Status}}, State0) ->
- State = reply_all(State0, {error, {exit_status, Status}}),
+ State =
+ case State0 of
+ 0 -> State0;
+ _ -> reply_all(State0, {error, {exit_status, Status}})
+ end,
{stop, ChannelId, State}.
%%--------------------------------------------------------------------
diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl
index cb2eab1fec..278f6a9780 100644
--- a/lib/ssh/src/ssh_sftpd.erl
+++ b/lib/ssh/src/ssh_sftpd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -125,9 +125,9 @@ handle_ssh_msg({ssh_cm, _, {signal, _, _}}, State) ->
%% Ignore signals according to RFC 4254 section 6.9.
{ok, State};
-handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, _, Error, _}}, State) ->
- Report = io_lib:format("Connection closed by peer ~n Error ~p~n",
- [Error]),
+handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, Signal, Error, _}}, State) ->
+ Report = io_lib:format("Connection closed by peer signal ~p~n Error ~p~n",
+ [Signal,Error]),
error_logger:error_report(Report),
{stop, ChannelId, State};
diff --git a/lib/ssh/src/ssh_shell.erl b/lib/ssh/src/ssh_shell.erl
index 084daa6821..cdc9a6df5b 100644
--- a/lib/ssh/src/ssh_shell.erl
+++ b/lib/ssh/src/ssh_shell.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_subsystem_sup.erl b/lib/ssh/src/ssh_subsystem_sup.erl
index f80be7f20b..5fc8f7e764 100644
--- a/lib/ssh/src/ssh_subsystem_sup.erl
+++ b/lib/ssh/src/ssh_subsystem_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_sup.erl b/lib/ssh/src/ssh_sup.erl
index 8183016ba5..61afbcd2ed 100644
--- a/lib/ssh/src/ssh_sup.erl
+++ b/lib/ssh/src/ssh_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl
index 469f9560e9..ed7c0c2bd5 100644
--- a/lib/ssh/src/ssh_system_sup.erl
+++ b/lib/ssh/src/ssh_system_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 631c4d0213..b6d7aa0b1b 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -104,7 +104,12 @@ algo_two_spec_class(_) -> false.
default_algorithms(kex) ->
supported_algorithms(kex, [
- 'diffie-hellman-group1-sha1' % Gone in OpenSSH 7.3.p1
+ %% Under devolpment:
+ 'curve25519-sha256',
+ 'curve448-sha512',
+ %% Gone in OpenSSH 7.3.p1:
+ 'diffie-hellman-group1-sha1'
]);
default_algorithms(cipher) ->
@@ -123,9 +128,14 @@ supported_algorithms() -> [{K,supported_algorithms(K)} || K <- algo_classes()].
supported_algorithms(kex) ->
select_crypto_supported(
[
- {'ecdh-sha2-nistp384', [{public_keys,ecdh}, {ec_curve,secp384r1}, {hashs,sha384}]},
- {'ecdh-sha2-nistp521', [{public_keys,ecdh}, {ec_curve,secp521r1}, {hashs,sha512}]},
- {'ecdh-sha2-nistp256', [{public_keys,ecdh}, {ec_curve,secp256r1}, {hashs,sha256}]},
+ {'ecdh-sha2-nistp384', [{public_keys,ecdh}, {curves,secp384r1}, {hashs,sha384}]},
+ {'ecdh-sha2-nistp521', [{public_keys,ecdh}, {curves,secp521r1}, {hashs,sha512}]},
+ {'ecdh-sha2-nistp256', [{public_keys,ecdh}, {curves,secp256r1}, {hashs,sha256}]},
+ %% https://tools.ietf.org/html/draft-ietf-curdle-ssh-curves
+ %% Secure Shell (SSH) Key Exchange Method using Curve25519 and Curve448
+ {'curve25519-sha256', [{public_keys,eddh}, {curves,x25519}, {hashs,sha256}]},
+ {'[email protected]', [{public_keys,eddh}, {curves,x25519}, {hashs,sha256}]},
+ {'curve448-sha512', [{public_keys,eddh}, {curves,x448}, {hashs,sha512}]},
{'diffie-hellman-group-exchange-sha256', [{public_keys,dh}, {hashs,sha256}]},
{'diffie-hellman-group16-sha512', [{public_keys,dh}, {hashs,sha512}]}, % In OpenSSH 7.3.p1
{'diffie-hellman-group18-sha512', [{public_keys,dh}, {hashs,sha512}]}, % In OpenSSH 7.3.p1
@@ -137,9 +147,9 @@ supported_algorithms(kex) ->
supported_algorithms(public_key) ->
select_crypto_supported(
[
- {'ecdsa-sha2-nistp384', [{public_keys,ecdsa}, {hashs,sha384}, {ec_curve,secp384r1}]},
- {'ecdsa-sha2-nistp521', [{public_keys,ecdsa}, {hashs,sha512}, {ec_curve,secp521r1}]},
- {'ecdsa-sha2-nistp256', [{public_keys,ecdsa}, {hashs,sha256}, {ec_curve,secp256r1}]},
+ {'ecdsa-sha2-nistp384', [{public_keys,ecdsa}, {hashs,sha384}, {curves,secp384r1}]},
+ {'ecdsa-sha2-nistp521', [{public_keys,ecdsa}, {hashs,sha512}, {curves,secp521r1}]},
+ {'ecdsa-sha2-nistp256', [{public_keys,ecdsa}, {hashs,sha256}, {curves,secp256r1}]},
{'ssh-rsa', [{public_keys,rsa}, {hashs,sha} ]},
{'rsa-sha2-256', [{public_keys,rsa}, {hashs,sha256} ]},
{'rsa-sha2-512', [{public_keys,rsa}, {hashs,sha512} ]},
@@ -164,9 +174,9 @@ supported_algorithms(cipher) ->
supported_algorithms(mac) ->
same(
select_crypto_supported(
- [{'hmac-sha2-256', [{hashs,sha256}]},
- {'hmac-sha2-512', [{hashs,sha512}]},
- {'hmac-sha1', [{hashs,sha}]},
+ [{'hmac-sha2-256', [{macs,hmac}, {hashs,sha256}]},
+ {'hmac-sha2-512', [{macs,hmac}, {hashs,sha512}]},
+ {'hmac-sha1', [{macs,hmac}, {hashs,sha}]},
{'AEAD_AES_128_GCM', [{ciphers,{aes_gcm,128}}]},
{'AEAD_AES_256_GCM', [{ciphers,{aes_gcm,256}}]}
]
@@ -403,7 +413,10 @@ key_exchange_first_msg(Kex, Ssh0=#ssh{opts=Opts}) when Kex == 'diffie-hellman-gr
key_exchange_first_msg(Kex, Ssh0) when Kex == 'ecdh-sha2-nistp256' ;
Kex == 'ecdh-sha2-nistp384' ;
- Kex == 'ecdh-sha2-nistp521' ->
+ Kex == 'ecdh-sha2-nistp521' ;
+ Kex == 'curve25519-sha256' ;
+ Kex == '[email protected]';
+ Kex == 'curve448-sha512' ->
Curve = ecdh_curve(Kex),
{Public, Private} = generate_key(ecdh, Curve),
{SshPacket, Ssh1} = ssh_packet(#ssh_msg_kex_ecdh_init{q_c=Public}, Ssh0),
@@ -666,8 +679,10 @@ handle_kex_ecdh_init(#ssh_msg_kex_ecdh_init{q_c = PeerPublic},
catch
Class:Error ->
?DISCONNECT(?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- io_lib:format("ECDH compute key failed in server: ~p:~p",
- [Class,Error])
+ io_lib:format("ECDH compute key failed in server: ~p:~p~n"
+ "Kex: ~p, Curve: ~p~n"
+ "PeerPublic: ~p",
+ [Class,Error,Kex,Curve,PeerPublic])
)
end.
@@ -1874,6 +1889,11 @@ sha(?'secp521r1') -> sha(secp521r1);
sha('ecdh-sha2-nistp256') -> sha(secp256r1);
sha('ecdh-sha2-nistp384') -> sha(secp384r1);
sha('ecdh-sha2-nistp521') -> sha(secp521r1);
+sha('curve25519-sha256' ) -> sha256;
+sha('[email protected]' ) -> sha256;
+sha('curve448-sha512') -> sha512;
+sha(x25519) -> sha256;
+sha(x448) -> sha512;
sha(Str) when is_list(Str), length(Str)<50 -> sha(list_to_atom(Str)).
@@ -1938,7 +1958,10 @@ dh_bits(#alg{encrypt = Encrypt,
ecdh_curve('ecdh-sha2-nistp256') -> secp256r1;
ecdh_curve('ecdh-sha2-nistp384') -> secp384r1;
-ecdh_curve('ecdh-sha2-nistp521') -> secp521r1.
+ecdh_curve('ecdh-sha2-nistp521') -> secp521r1;
+ecdh_curve('curve448-sha512' ) -> x448;
+ecdh_curve('curve25519-sha256' ) -> x25519;
+ecdh_curve('[email protected]' ) -> x25519.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1955,15 +1978,10 @@ supported_algorithms(Key, BlackList) ->
select_crypto_supported(L) ->
- Sup = [{ec_curve,crypto_supported_curves()} | crypto:supports()],
+ Sup = crypto:supports(),
[Name || {Name,CryptoRequires} <- L,
crypto_supported(CryptoRequires, Sup)].
-crypto_supported_curves() ->
- try crypto:ec_curves()
- catch _:_ -> []
- end.
-
crypto_supported(Conditions, Supported) ->
lists:all( fun({Tag,CryptoName}) when is_atom(CryptoName) ->
crypto_name_supported(Tag,CryptoName,Supported);
@@ -1973,7 +1991,11 @@ crypto_supported(Conditions, Supported) ->
end, Conditions).
crypto_name_supported(Tag, CryptoName, Supported) ->
- lists:member(CryptoName, proplists:get_value(Tag,Supported,[])).
+ Vs = case proplists:get_value(Tag,Supported,[]) of
+ [] when Tag == curves -> crypto:ec_curves();
+ L -> L
+ end,
+ lists:member(CryptoName, Vs).
len_supported(Name, Len) ->
try
diff --git a/lib/ssh/src/ssh_transport.hrl b/lib/ssh/src/ssh_transport.hrl
index 7d5a4c153e..f424a4ff63 100644
--- a/lib/ssh/src/ssh_transport.hrl
+++ b/lib/ssh/src/ssh_transport.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/ssh_xfer.erl b/lib/ssh/src/ssh_xfer.erl
index e1680c120e..7bb9c2d101 100644
--- a/lib/ssh/src/ssh_xfer.erl
+++ b/lib/ssh/src/ssh_xfer.erl
@@ -734,7 +734,7 @@ decode_ATTR(Vsn, <<?UINT32(Flags), Tail/binary>>) ->
{Type,Tail2} =
if Vsn =< 3 ->
{?SSH_FILEXFER_TYPE_UNKNOWN, Tail};
- Vsn >= 5 ->
+ true ->
<<?BYTE(T), TL/binary>> = Tail,
{T, TL}
end,
diff --git a/lib/ssh/src/sshc_sup.erl b/lib/ssh/src/sshc_sup.erl
index f4b39dbbdc..869de244ac 100644
--- a/lib/ssh/src/sshc_sup.erl
+++ b/lib/ssh/src/sshc_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/src/sshd_sup.erl b/lib/ssh/src/sshd_sup.erl
index 779a861a54..b5361abba5 100644
--- a/lib/ssh/src/sshd_sup.erl
+++ b/lib/ssh/src/sshd_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile
index 0a99d31a63..e221e94075 100644
--- a/lib/ssh/test/Makefile
+++ b/lib/ssh/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2017. All Rights Reserved.
+# Copyright Ericsson AB 2004-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -36,6 +36,7 @@ MODULES= \
ssh_options_SUITE \
ssh_basic_SUITE \
ssh_bench_SUITE \
+ ssh_chan_behaviours_SUITE \
ssh_compat_SUITE \
ssh_connection_SUITE \
ssh_dbg_SUITE \
@@ -53,6 +54,8 @@ MODULES= \
ssh_key_cb_options \
ssh_key_cb_engine_keys \
ssh_trpt_test_lib \
+ ssh_chan_behaviours_client \
+ ssh_chan_behaviours_server \
ssh_echo_server \
ssh_bench_dev_null \
ssh_peername_sockname_server \
@@ -136,6 +139,6 @@ release_tests_spec: opt
$(INSTALL_DATA) ssh.spec ssh_bench.spec ssh.cover "$(RELSYSDIR)"
$(INSTALL_DATA) $(HRL_FILES_NEEDED_IN_TEST) "$(RELSYSDIR)"
chmod -R u+w "$(RELSYSDIR)"
- @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
+ @tar cf - *_SUITE_data property_test | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl b/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl
index 19e2754eba..6d0d8f5d99 100644
--- a/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl
+++ b/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/property_test/ssh_eqc_subsys.erl b/lib/ssh/test/property_test/ssh_eqc_subsys.erl
index e7de3ea068..087b3ebfa7 100644
--- a/lib/ssh/test/property_test/ssh_eqc_subsys.erl
+++ b/lib/ssh/test/property_test/ssh_eqc_subsys.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl
index 0ce4bd8699..5e589e585f 100644
--- a/lib/ssh/test/ssh_algorithms_SUITE.erl
+++ b/lib/ssh/test/ssh_algorithms_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -100,7 +100,7 @@ init_per_suite(Config) ->
ct:log("all() ->~n ~p.~n~ngroups()->~n ~p.~n",[all(),groups()]),
ssh:start(),
[{std_simple_sftp_size,25000} % Sftp transferred data size
- | setup_pubkey(Config)]
+ | Config]
end
).
@@ -459,17 +459,6 @@ pubkey_opts(Config) ->
{system_dir, SystemDir}].
-setup_pubkey(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- UserDir = proplists:get_value(priv_dir, Config),
- Keys =
- [ssh_test_lib:setup_dsa(DataDir, UserDir),
- ssh_test_lib:setup_rsa(DataDir, UserDir),
- ssh_test_lib:setup_ecdsa("256", DataDir, UserDir)
- ],
- ssh_test_lib:write_auth_keys(Keys, UserDir), % 'authorized_keys' shall contain ALL pub keys
- Config.
-
setup_pubkey(Alg, Config) ->
DataDir = proplists:get_value(data_dir, Config),
UserDir = proplists:get_value(priv_dir, Config),
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 807e23ff01..778ae1e7b6 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_bench_dev_null.erl b/lib/ssh/test/ssh_bench_dev_null.erl
index f9da80b6d7..868eea5643 100644
--- a/lib/ssh/test/ssh_bench_dev_null.erl
+++ b/lib/ssh/test/ssh_bench_dev_null.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_chan_behaviours_SUITE.erl b/lib/ssh/test/ssh_chan_behaviours_SUITE.erl
new file mode 100644
index 0000000000..16ed152bcd
--- /dev/null
+++ b/lib/ssh/test/ssh_chan_behaviours_SUITE.erl
@@ -0,0 +1,152 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% 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(ssh_chan_behaviours_SUITE).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("ssh/src/ssh.hrl").
+-include("ssh_test_lib.hrl").
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap,{seconds,60}}].
+
+all() ->
+ [
+ noexist_subsystem,
+ undefined_subsystem,
+ defined_subsystem,
+ subsystem_client
+ ].
+
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ ?CHECK_CRYPTO(
+ begin
+ ssh:start(),
+ Config
+ end).
+
+end_per_suite(_Config) ->
+ {Time,R} = timer:tc(ssh, stop, []),
+ ct:log("Stop ssh: ~p ms",[(100*(Time div 1000)) / 100]),
+ R.
+
+init_per_testcase(_TC, Config) ->
+ SubSystems = [
+ {"bad_cb", {ssh_chan_behaviours_undefined, []}}, % A non-existing file
+ {"ch1", {ssh_chan_behaviours_server, [self(),true]}}
+ ],
+ {Pid, Host, Port} = ssh_test_lib:std_daemon(Config, [{subsystems,SubSystems}]),
+ C = ssh_test_lib:std_connect(Config, Host, Port, []),
+ [{connref,C}, {daemon_pid,Pid}| Config].
+
+end_per_testcase(_TC, Config) ->
+ {Time,_} = timer:tc(ssh, stop_daemon, [proplists:get_value(daemon_pid,Config)]),
+ ct:log("Stop daemon: ~p ms",[(100*(Time div 1000)) / 100]),
+ case flush() of
+ [] -> ok;
+ Msgs -> ct:pal("Unhandled messages:~n~p", [Msgs])
+ end.
+
+
+-define(EXPECT(What, Bind),
+ Bind =
+ (fun() ->
+ receive What ->
+ ct:log("~p:~p ~p got ~p",[?MODULE,?LINE,self(),What]),
+ Bind
+ after 5000 ->
+ ct:log("~p:~p ~p Flushed:~n~p",[?MODULE,?LINE,self(),flush()]),
+ ct:fail("Timeout!",[])
+ end
+ end)()
+ ).
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+%% Try start a subsystem whos name is not known by the server
+noexist_subsystem(Config) ->
+ C = proplists:get_value(connref, Config),
+ {ok, Ch} = ssh_connection:session_channel(C, infinity),
+ failure = ssh_connection:subsystem(C, Ch, "noexist", infinity),
+ ok = ssh_connection:close(C, Ch),
+ ?EXPECT({ssh_cm,C,{closed,Ch}},[]),
+ ok.
+
+%% Try to start a subsystem with a known name, but without any callback file
+undefined_subsystem(Config) ->
+ C = proplists:get_value(connref, Config),
+ {ok, Ch} = ssh_connection:session_channel(C, infinity),
+ failure = ssh_connection:subsystem(C, Ch, "bad_cb", infinity),
+ ok = ssh_connection:close(C, Ch),
+ ?EXPECT({ssh_cm,C,{closed,Ch}},[]), % self() is instead of a proper channel handler
+ ok.
+
+%% Try to start and stop a subsystem with known name and defined callback file
+defined_subsystem(Config) ->
+ C = proplists:get_value(connref, Config),
+ {ok, Ch1} = ssh_connection:session_channel(C, infinity),
+
+ success = ssh_connection:subsystem(C, Ch1, "ch1", infinity),
+ IDsrv = ?EXPECT({{_Csrv,_Ch1srv}, {ssh_channel_up,_Ch1srv,_Csrv}}, {_Csrv,_Ch1srv}),
+
+ ok = ssh_connection:close(C, Ch1),
+ ?EXPECT({IDsrv, {terminate,normal}}, []),
+ ?EXPECT({ssh_cm, C, {closed,Ch1}}, []), % self() is instead of a proper channel handler
+ ok.
+
+%% Try to start and stop a subsystem from a ssh_client_channel behviour
+subsystem_client(Config) ->
+ C = proplists:get_value(connref, Config),
+
+ {ok,ChRef} = ssh_chan_behaviours_client:start_link(C),
+ IDclt = ?EXPECT({{C,Ch1clt}, {ssh_channel_up,Ch1clt,C}}, {C,Ch1clt}),
+ IDsrv = ?EXPECT({{_Csrv,Ch1srv}, {ssh_channel_up,Ch1srv,_Csrv}}, {_Csrv,Ch1srv}),
+
+ ok = ssh_chan_behaviours_client:stop(ChRef),
+ ?EXPECT({IDclt, {terminate,normal}}, []), % From the proper channel handler
+ ?EXPECT({IDsrv, {terminate,normal}}, []),
+ ok.
+
+%%%================================================================
+%%%
+%%%
+
+flush() -> lists:reverse(flush([])).
+
+flush(Acc) ->
+ receive
+ M ->
+ flush([M|Acc])
+ after 0 ->
+ Acc
+ end.
+
diff --git a/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_dsa_key
new file mode 100644
index 0000000000..51ab6fbd88
--- /dev/null
+++ b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_dsa_key
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK
+wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q
+diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA
+l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X
+skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF
+Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP
+ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah
+/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U
+ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W
+Lv62jKcdskxNyz2NQoBx
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_dsa_key.pub
new file mode 100644
index 0000000000..4dbb1305b0
--- /dev/null
+++ b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_dsa_key.pub
@@ -0,0 +1,11 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j
+YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2
+KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU
+aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI
+fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT
+MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh
+DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48
+wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2
+/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_ecdsa_key b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_ecdsa_key
new file mode 100644
index 0000000000..fb1a862ded
--- /dev/null
+++ b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_ecdsa_key
@@ -0,0 +1,6 @@
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDArxbDfh3p1okrD9wQw6jJ4d4DdlBPD5GqXE8bIeRJiK41Sh40LgvPw
+mkqEDSXK++CgBwYFK4EEACKhZANiAAScl43Ih2lWTDKrSox5ve5uiTXil4smsup3
+CfS1XPjKxgBAmlfBim8izbdrT0BFdQzz2joduNMtpt61wO4rGs6jm0UP7Kim9PC7
+Hneb/99fIYopdMH5NMnk60zGO1uZ2vc=
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_ecdsa_key.pub b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_ecdsa_key.pub
new file mode 100644
index 0000000000..428d5fb7d7
--- /dev/null
+++ b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_ecdsa_key.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBJyXjciHaVZMMqtKjHm97m6JNeKXiyay6ncJ9LVc+MrGAECaV8GKbyLNt2tPQEV1DPPaOh240y2m3rXA7isazqObRQ/sqKb08Lsed5v/318hiil0wfk0yeTrTMY7W5na9w== uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_rsa_key
new file mode 100644
index 0000000000..79968bdd7d
--- /dev/null
+++ b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_rsa_key
@@ -0,0 +1,16 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337
+zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB
+6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB
+AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW
+NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++
+udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW
+WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt
+n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5
+sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY
++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt
+64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB
+m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT
+tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR
+-----END RSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_rsa_key.pub b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_rsa_key.pub
new file mode 100644
index 0000000000..75d2025c71
--- /dev/null
+++ b/lib/ssh/test/ssh_chan_behaviours_SUITE_data/ssh_host_rsa_key.pub
@@ -0,0 +1,5 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8
+semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RW
+RWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_chan_behaviours_client.erl b/lib/ssh/test/ssh_chan_behaviours_client.erl
new file mode 100644
index 0000000000..15f17733d6
--- /dev/null
+++ b/lib/ssh/test/ssh_chan_behaviours_client.erl
@@ -0,0 +1,143 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% 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%
+%%
+
+%%
+
+%%% Description: Example ssh client
+-module(ssh_chan_behaviours_client).
+-behaviour(ssh_client_channel).
+-record(state, {
+ parent,
+ cm,
+ ch,
+ dbg
+ }).
+-export([start_link/1, start/1,
+ stop/1, send_eof/1,
+ init/1, handle_msg/2, handle_ssh_msg/2, terminate/2,
+ code_change/3, handle_call/3, handle_cast/2
+ ]).
+
+-define(DBG(State,Fmt,Args),
+ case State#state.dbg of
+ true -> ct:log("~p:~p ~p C=~p Ch=~p "++Fmt,
+ [?MODULE,?LINE,self(),State#state.cm,State#state.ch|Args]);
+ false -> ok
+ end).
+
+
+start_link(C) ->
+ {ok, Ch} = ssh_connection:session_channel(C, infinity),
+ ssh_client_channel:start_link(C, Ch, ssh_chan_behaviours_client, [C, Ch, self(), true]).
+
+start(C) ->
+ {ok, Ch} = ssh_connection:session_channel(C, infinity),
+ ssh_client_channel:start(C, Ch, ssh_chan_behaviours_client, [C, Ch, self(), true]).
+
+send_eof(ChRef) ->
+ ssh_client_channel:call(ChRef, send_eof).
+
+stop(ChRef) ->
+ ssh_client_channel:call(ChRef, stop).
+
+
+init([C, Ch, Parent, Dbg|_Exec]) ->
+ case ssh_connection:subsystem(C, Ch, "ch1", infinity) of
+ success ->
+ State = #state{cm = C,
+ ch = Ch,
+ parent=Parent,
+ dbg=Dbg},
+ ?DBG(State, "callback spawned, parent = ~p", [Parent]),
+ {ok, State};
+
+ Other ->
+ {stop, Other}
+ end.
+
+handle_msg({ssh_channel_up, ChannelId, ConnectionManager}=M, State0) ->
+ State = State0#state{cm = ConnectionManager,
+ ch = ChannelId},
+ tell_parent(M, State),
+ ?DBG(State, "ssh_channel_up",[]),
+ {ok, State}.
+
+handle_ssh_msg({ssh_cm, C, {data, Ch, 0, Data}}=M, #state{ch=Ch,cm=C} = State) ->
+ tell_parent(M, State),
+ ?DBG(State, "ssh_cm data size(Data)=~p",[size(Data)]),
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, C, {data, Ch, Type, Data}}=M, #state{ch=Ch,cm=C} = State) ->
+ tell_parent(M, State),
+ ?DBG(State, "ssh_cm data Type=~p : ~p",[Type,Data]),
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, C, {eof, Ch}}=M, #state{ch=Ch,cm=C} = State) ->
+ tell_parent(M, State),
+ ?DBG(State, "eof",[]),
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, C, {signal, _Ch, _SigNameStr}=Sig} = M, #state{ch=Ch,cm=C} = State) ->
+ %% Ignore signals according to RFC 4254 section 6.9.
+ tell_parent(M, State),
+ ?DBG(State, "~p",[Sig]),
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, C, {exit_signal, Ch, _, _Error, _}=Sig}=M, #state{ch=Ch,cm=C} = State) ->
+ tell_parent(M, State),
+ ?DBG(State, "~p",[Sig]),
+ {stop, Ch, State};
+
+handle_ssh_msg({ssh_cm, C, {exit_status, Ch, _Status}=Sig}=M, #state{ch=Ch,cm=C} = State) ->
+ tell_parent(M, State),
+ ?DBG(State, "~p",[Sig]),
+ {stop, Ch, State}.
+
+
+handle_call(send_eof, _From,#state{ch=Ch,cm=C} = State) ->
+ {reply, ssh_connection:send_eof(C,Ch), State};
+
+handle_call(stop, _From, State) ->
+ {stop, normal, ok, State};
+
+handle_call(Msg, _From, State) ->
+ ?DBG(State, "Unknown call ~p", [Msg]),
+ {reply, {unknown_call,Msg}, State}.
+
+
+terminate(Reason, State) ->
+ tell_parent({terminate,Reason}, State),
+ ?DBG(State, "terminate Reason = ~p",[Reason]).
+
+
+handle_cast(Msg, State) ->
+ ?DBG(State, "Unknown cast ~p", [Msg]),
+ {noreply, State}.
+
+code_change(_OldVsn, State, _Extra) -> {ok, State}.
+
+%%%================================================================
+%%%
+%%%
+
+tell_parent(Msg, #state{parent = Parent,
+ cm = C,
+ ch = Ch}) -> Parent ! {{C,Ch}, Msg}.
+
diff --git a/lib/ssh/test/ssh_chan_behaviours_server.erl b/lib/ssh/test/ssh_chan_behaviours_server.erl
new file mode 100644
index 0000000000..1408675a6e
--- /dev/null
+++ b/lib/ssh/test/ssh_chan_behaviours_server.erl
@@ -0,0 +1,96 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% 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%
+%%
+
+%%
+
+%%% Description: Example ssh server
+-module(ssh_chan_behaviours_server).
+-behaviour(ssh_server_channel).
+-record(state, {
+ parent,
+ cm,
+ ch,
+ dbg
+ }).
+-export([init/1, handle_msg/2, handle_ssh_msg/2, terminate/2]).
+
+-define(DBG(State,Fmt,Args),
+ case State#state.dbg of
+ true -> ct:log("~p:~p ~p C=~p Ch=~p "++Fmt,
+ [?MODULE,?LINE,self(),State#state.cm,State#state.ch|Args]);
+ false -> ok
+ end).
+
+
+init([Pid,Dbg|_Exec]) ->
+ {ok, #state{parent=Pid,
+ dbg=Dbg}}.
+
+handle_msg({ssh_channel_up, ChannelId, ConnectionManager}=M, State0) ->
+ State = State0#state{cm = ConnectionManager,
+ ch = ChannelId},
+ tell_parent(M, State),
+ ?DBG(State, "ssh_channel_up",[]),
+ {ok, State}.
+
+handle_ssh_msg({ssh_cm, C, {data, Ch, 0, Data}}=M, #state{ch=Ch,cm=C} = State) ->
+ tell_parent(M, State),
+ ?DBG(State, "ssh_cm data size(Data)=~p",[size(Data)]),
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, C, {data, Ch, Type, Data}}=M, #state{ch=Ch,cm=C} = State) ->
+ tell_parent(M, State),
+ ?DBG(State, "ssh_cm data Type=~p : ~p",[Type,Data]),
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, C, {eof, Ch}}=M, #state{ch=Ch,cm=C} = State) ->
+ tell_parent(M, State),
+ ?DBG(State, "eof",[]),
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, C, {signal, _Ch, _SigNameStr}=Sig} = M, #state{ch=Ch,cm=C} = State) ->
+ %% Ignore signals according to RFC 4254 section 6.9.
+ tell_parent(M, State),
+ ?DBG(State, "~p",[Sig]),
+ {ok, State};
+
+handle_ssh_msg({ssh_cm, C, {exit_signal, Ch, _, _Error, _}=Sig}=M, #state{ch=Ch,cm=C} = State) ->
+ tell_parent(M, State),
+ ?DBG(State, "~p",[Sig]),
+ {stop, Ch, State};
+
+handle_ssh_msg({ssh_cm, C, {exit_status, Ch, _Status}=Sig}=M, #state{ch=Ch,cm=C} = State) ->
+ tell_parent(M, State),
+ ?DBG(State, "~p",[Sig]),
+ {stop, Ch, State}.
+
+terminate(Reason, State) ->
+ tell_parent({terminate,Reason}, State),
+ ?DBG(State, "terminate Reason = ~p",[Reason]),
+ ok.
+
+%%%================================================================
+%%%
+%%%
+
+tell_parent(Msg, #state{parent = Parent,
+ cm = C,
+ ch = Ch}) -> Parent ! {{C,Ch}, Msg}.
+
diff --git a/lib/ssh/test/ssh_compat_SUITE.erl b/lib/ssh/test/ssh_compat_SUITE.erl
index 6c0e010bf5..1c607bebe8 100644
--- a/lib/ssh/test/ssh_compat_SUITE.erl
+++ b/lib/ssh/test/ssh_compat_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl
index 257f2f70d7..778e4a5fc8 100644
--- a/lib/ssh/test/ssh_connection_SUITE.erl
+++ b/lib/ssh/test/ssh_connection_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_dbg_SUITE.erl b/lib/ssh/test/ssh_dbg_SUITE.erl
index 5439817d10..ab7918fa90 100644
--- a/lib/ssh/test/ssh_dbg_SUITE.erl
+++ b/lib/ssh/test/ssh_dbg_SUITE.erl
@@ -38,11 +38,20 @@ suite() ->
{timetrap,{seconds,60}}].
all() ->
- [basic,
- dbg_alg_terminate,
- dbg_ssh_messages,
- dbg_connections,
- dbg_channels
+ [{group, dbg},
+ {group, circ_buf}
+ ].
+
+groups() ->
+ [{dbg, [], [dbg_basic,
+ dbg_alg_terminate,
+ dbg_ssh_messages,
+ dbg_connections,
+ dbg_channels]},
+ {circ_buf, [], [cb_basic,
+ cb_print,
+ cb_macros_print
+ ]}
].
%%--------------------------------------------------------------------
@@ -82,7 +91,7 @@ end_per_testcase(_TC, Config) ->
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
-basic(_Config) ->
+dbg_basic(_Config) ->
L0 = ssh_dbg:start(),
true = is_pid(whereis(ssh_dbg)),
true = is_list(L0),
@@ -342,6 +351,53 @@ dbg_channels(Config) ->
stop_and_fail_if_unhandled_dbg_msgs(Ref, [C,D], Pid).
%%--------------------------------------------------------------------
+cb_basic(_Config) ->
+ %% Check that the circular buffer is disabled at start:
+ [] = ssh_dbg:cbuf_list(),
+ disabled = ssh_dbg:cbuf_in(anything),
+ [] = ssh_dbg:cbuf_list(),
+ %% Start it and enter three values, first is duplicated;
+ ok = ssh_dbg:cbuf_start(3),
+ ok = ssh_dbg:cbuf_in(v1),
+ ok = ssh_dbg:cbuf_in(v1),
+ ok = ssh_dbg:cbuf_in(v2),
+ ok = ssh_dbg:cbuf_in(v3),
+ [{v3,_,1}, {v2,_,1}, {v1,_,2}] = ssh_dbg:cbuf_list(),
+ %% Check that a fourth value erase the first entered:
+ ok = ssh_dbg:cbuf_in(v4),
+ [{v4,_,1}, {v3,_,1}, {v2,_,1}] = ssh_dbg:cbuf_list(),
+ %% Check that entering a value that is in the tail but not in the head is treated as a new value:
+ ok = ssh_dbg:cbuf_in(v2),
+ [{v2,_,1}, {v4,_,1}, {v3,_,1}] = ssh_dbg:cbuf_list(),
+ %% Stop and check that the buffer is returned:
+ [{v2,_,1}, {v4,_,1}, {v3,_,1}] = ssh_dbg:cbuf_stop_clear(),
+ %% Stopping a stopped buffer returns empty:
+ [] = ssh_dbg:cbuf_stop_clear(),
+ %% Check that a value can't be entered in a stopped buffer:
+ disabled = ssh_dbg:cbuf_in(v2).
+
+%%--------------------------------------------------------------------
+cb_print(_Config) ->
+ ssh_dbg:cbuf_start(),
+ [begin
+ ssh_dbg:cbuf_in(V),
+ ct:log("Enter ~p",[V])
+ end || V <- lists:seq(1,10)],
+ ct:log("~s",[ssh_dbg:fmt_cbuf_items()]),
+ ssh_dbg:cbuf_stop_clear().
+
+%%--------------------------------------------------------------------
+cb_macros_print(_Config) ->
+ ssh_dbg:cbuf_start(),
+ [begin
+ V = {test,V0},
+ ?CIRC_BUF_IN(V),
+ ct:log("Enter ~p",[V])
+ end || V0 <- lists:seq(1,5)],
+ ct:log("~s",[ssh_dbg:fmt_cbuf_items()]),
+ ssh_dbg:cbuf_stop_clear().
+
+%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
diff --git a/lib/ssh/test/ssh_echo_server.erl b/lib/ssh/test/ssh_echo_server.erl
index d03fe9543e..e039439f87 100644
--- a/lib/ssh/test/ssh_echo_server.erl
+++ b/lib/ssh/test/ssh_echo_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_engine_SUITE.erl b/lib/ssh/test/ssh_engine_SUITE.erl
index c131a70973..c2e6ac1fee 100644
--- a/lib/ssh/test/ssh_engine_SUITE.erl
+++ b/lib/ssh/test/ssh_engine_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl
index 86a8ac5aa8..daf62483cd 100644
--- a/lib/ssh/test/ssh_options_SUITE.erl
+++ b/lib/ssh/test/ssh_options_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_peername_sockname_server.erl b/lib/ssh/test/ssh_peername_sockname_server.erl
index 5e35fd6612..1cc53edf6d 100644
--- a/lib/ssh/test/ssh_peername_sockname_server.erl
+++ b/lib/ssh/test/ssh_peername_sockname_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_dsa_key
new file mode 100644
index 0000000000..51ab6fbd88
--- /dev/null
+++ b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_dsa_key
@@ -0,0 +1,13 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK
+wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q
+diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA
+l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X
+skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF
+Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP
+ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah
+/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U
+ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W
+Lv62jKcdskxNyz2NQoBx
+-----END DSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_dsa_key.pub
new file mode 100644
index 0000000000..4dbb1305b0
--- /dev/null
+++ b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_dsa_key.pub
@@ -0,0 +1,11 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j
+YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2
+KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU
+aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI
+fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT
+MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh
+DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48
+wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2
+/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_ecdsa_key b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_ecdsa_key
new file mode 100644
index 0000000000..2979ea88ed
--- /dev/null
+++ b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_ecdsa_key
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIMe4MDoit0t8RzSVPwkCBemQ9fhXL+xnTSAWISw8HNCioAoGCCqGSM49
+AwEHoUQDQgAEo2q7U3P6r0W5WGOLtM78UQtofM9UalEhiZeDdiyylsR/RR17Op0s
+VPGSADLmzzgcucLEKy17j2S+oz42VUJy5A==
+-----END EC PRIVATE KEY-----
diff --git a/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_ecdsa_key.pub b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_ecdsa_key.pub
new file mode 100644
index 0000000000..85dc419345
--- /dev/null
+++ b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_ecdsa_key.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKNqu1Nz+q9FuVhji7TO/FELaHzPVGpRIYmXg3YsspbEf0UdezqdLFTxkgAy5s84HLnCxCste49kvqM+NlVCcuQ= uabhnil@elxadlj3q32
diff --git a/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_rsa_key
new file mode 100644
index 0000000000..79968bdd7d
--- /dev/null
+++ b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_rsa_key
@@ -0,0 +1,16 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337
+zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB
+6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB
+AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW
+NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++
+udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW
+WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt
+n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5
+sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY
++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt
+64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB
+m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT
+tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR
+-----END RSA PRIVATE KEY-----
+
diff --git a/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_rsa_key.pub b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_rsa_key.pub
new file mode 100644
index 0000000000..75d2025c71
--- /dev/null
+++ b/lib/ssh/test/ssh_property_test_SUITE_data/ssh_host_rsa_key.pub
@@ -0,0 +1,5 @@
+---- BEGIN SSH2 PUBLIC KEY ----
+AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8
+semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RW
+RWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q==
+---- END SSH2 PUBLIC KEY ----
diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl
index b81f66948d..a0e3d809be 100644
--- a/lib/ssh/test/ssh_sup_SUITE.erl
+++ b/lib/ssh/test/ssh_sup_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 65970535f4..416cc301db 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index 9df404d7ed..334281f53b 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index f10e7aa96a..c3572b5b70 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,5 +1,4 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.6.9
-
+SSH_VSN = 4.7
APP_VSN = "ssh-$(SSH_VSN)"
diff --git a/lib/ssl/doc/src/Makefile b/lib/ssl/doc/src/Makefile
index f9128e8e45..d459463322 100644
--- a/lib/ssl/doc/src/Makefile
+++ b/lib/ssl/doc/src/Makefile
@@ -102,6 +102,7 @@ html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 34fe352d08..87bf25452f 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1999</year><year>2017</year>
+ <year>1999</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -27,6 +27,201 @@
</header>
<p>This document describes the changes made to the SSL application.</p>
+<section><title>SSL 9.0</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Correct handling of ECDH suites.</p>
+ <p>
+ Own Id: OTP-14974</p>
+ </item>
+ <item>
+ <p>
+ Proper handling of clients that choose to send an empty
+ answer to a certificate request</p>
+ <p>
+ Own Id: OTP-15050</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Distribution over SSL (inet_tls) has, to improve
+ performance, been rewritten to not use intermediate
+ processes and ports.</p>
+ <p>
+ Own Id: OTP-14465</p>
+ </item>
+ <item>
+ <p>
+ Add suport for ECDHE_PSK cipher suites</p>
+ <p>
+ Own Id: OTP-14547</p>
+ </item>
+ <item>
+ <p>
+ For security reasons no longer support 3-DES cipher
+ suites by default</p>
+ <p>
+ *** INCOMPATIBILITY with possibly ***</p>
+ <p>
+ Own Id: OTP-14768</p>
+ </item>
+ <item>
+ <p>
+ For security reasons RSA-key exchange cipher suites are
+ no longer supported by default</p>
+ <p>
+ *** INCOMPATIBILITY with possible ***</p>
+ <p>
+ Own Id: OTP-14769</p>
+ </item>
+ <item>
+ <p>
+ The interoperability option to fallback to insecure
+ renegotiation now has to be explicitly turned on.</p>
+ <p>
+ *** INCOMPATIBILITY with possibly ***</p>
+ <p>
+ Own Id: OTP-14789</p>
+ </item>
+ <item>
+ <p>
+ Drop support for SSLv2 enabled clients. SSLv2 has been
+ broken for decades and never supported by the Erlang
+ SSL/TLS implementation. This option was by default
+ disabled and enabling it has proved to sometimes break
+ connections not using SSLv2 enabled clients.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14824</p>
+ </item>
+ <item>
+ <p>
+ Remove CHACHA20_POLY1305 ciphers form default for now. We
+ have discovered interoperability problems, ERL-538, that
+ we believe needs to be solved in crypto.</p>
+ <p>
+ *** INCOMPATIBILITY with possibly ***</p>
+ <p>
+ Own Id: OTP-14882</p>
+ </item>
+ <item>
+ <p>
+ Generalize DTLS packet multiplexing to make it easier to
+ add future DTLS features and uses.</p>
+ <p>
+ Own Id: OTP-14888</p>
+ </item>
+ <item>
+ <p>
+ Use uri_string module instead of http_uri.</p>
+ <p>
+ Own Id: OTP-14902</p>
+ </item>
+ <item>
+ <p>
+ The SSL distribution protocol <c>-proto inet_tls</c> has
+ stopped setting the SSL option
+ <c>server_name_indication</c>. New verify funs for client
+ and server in <c>inet_tls_dist</c> has been added, not
+ documented yet, that checks node name if present in peer
+ certificate. Usage is still also yet to be documented.</p>
+ <p>
+ Own Id: OTP-14969 Aux Id: OTP-14465, ERL-598 </p>
+ </item>
+ <item>
+ <p>
+ Deprecate ssl:ssl_accept/[1,2,3] in favour of
+ ssl:handshake/[1,2,3]</p>
+ <p>
+ Own Id: OTP-15056</p>
+ </item>
+ <item>
+ <p>
+ Customizes the hostname verification of the peer
+ certificate, as different protocols that use TLS such as
+ HTTP or LDAP may want to do it differently</p>
+ <p>
+ Own Id: OTP-15102 Aux Id: ERL-542, OTP-14962 </p>
+ </item>
+ <item>
+ <p>
+ Add utility function for converting erlang cipher suites
+ to a string represenation (ERL-600).</p>
+ <p>
+ Own Id: OTP-15106</p>
+ </item>
+ <item>
+ <p>
+ First version with support for DTLS</p>
+ <p>
+ Own Id: OTP-15142</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 8.2.6.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Correct handling of empty server SNI extension</p>
+ <p>
+ Own Id: OTP-15168</p>
+ </item>
+ <item>
+ <p>
+ Correct cipher suite handling for ECDHE_*, the incorrect
+ handling could cause an incorrrect suite to be selected
+ and most likly fail the handshake.</p>
+ <p>
+ Own Id: OTP-15203</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 8.2.6.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improve cipher suite handling correcting ECC and TLS-1.2
+ requierments. Backport of solution for ERL-641</p>
+ <p>
+ Own Id: OTP-15178</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Option keyfile defaults to certfile and should be trumped
+ with key. This failed for engine keys.</p>
+ <p>
+ Own Id: OTP-15193</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SSL 8.2.6</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -196,7 +391,7 @@
<p>
TLS sessions must be registered with SNI if provided, so
that sessions where client hostname verification would
- fail can not connect reusing a session created when the
+ fail cannot connect reusing a session created when the
server name verification succeeded.</p>
<p>
Own Id: OTP-14632</p>
@@ -374,7 +569,7 @@
public_key:pkix_verify_hostname/2 to verify the hostname
of the connection with the server certificates specified
hostname during certificate path validation. The user may
- explicitly disables it. Also if the hostname can not be
+ explicitly disables it. Also if the hostname cannot be
derived from the first argument to connect or is not
supplied by the server name indication option, the check
will not be performed.</p>
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 029f29cdb3..6efa022a79 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1999</year><year>2017</year>
+ <year>1999</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -88,7 +88,9 @@
<p><c>| {client_preferred_next_protocols, {client | server,
[binary()]} | {client | server, [binary()], binary()}}</c></p>
<p><c>| {log_alert, boolean()}</c></p>
+ <p><c>| {log_level, atom()}</c></p>
<p><c>| {server_name_indication, hostname() | disable}</c></p>
+ <p><c>| {customize_hostname_check, list()}</c></p>
<p><c>| {sni_hosts, [{hostname(), [ssl_option()]}]}</c></p>
<p><c>| {sni_fun, SNIfun::fun()}</c></p>
</item>
@@ -198,14 +200,14 @@
| sect163r1 | sect163r2 | secp160k1 | secp160r1 | secp160r2</c></p></item>
<tag><c>hello_extensions() =</c></tag>
- <item><p><c>#{renegotiation_info =>
+ <item><p><c>#{renegotiation_info => binary() | undefined,
signature_algs => [{hash(), ecsda| rsa| dsa}] | undefined
alpn => binary() | undefined,
- next_protocol_negotiation,
+ next_protocol_negotiation => binary() | undefined,
srp => string() | undefined,
- ec_point_formats ,
- elliptic_curves = [oid] | undefined
- sni = string()}
+ ec_point_formats => list() | undefined,
+ elliptic_curves => [oid] | undefined,
+ sni => string() | undefined}
}</c></p></item>
@@ -408,7 +410,7 @@ marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_valid
<item>check is only performed on the peer certificate.</item>
<tag><c>best_effort</c></tag>
- <item>if certificate revocation status can not be determined
+ <item>if certificate revocation status cannot be determined
it will be accepted as valid.</item>
</taglist>
@@ -649,6 +651,14 @@ fun(srp, Username :: string(), UserState :: term()) ->
disables the hostname verification check
<seealso marker="public_key:public_key#pkix_verify_hostname-2">public_key:pkix_verify_hostname/2</seealso> </p>
</item>
+
+ <tag><c>{customize_hostname_check, Options::list()}</c></tag>
+ <item>
+ <p> Customizes the hostname verification of the peer certificate, as different protocols that use
+ TLS such as HTTP or LDAP may want to do it differently, for possible options see
+ <seealso marker="public_key:public_key#pkix_verify_hostname-3">public_key:pkix_verify_hostname/3</seealso> </p>
+ </item>
+
<tag><c>{fallback, boolean()}</c></tag>
<item>
<p> Send special cipher suite TLS_FALLBACK_SCSV to avoid undesired TLS version downgrade.
@@ -787,7 +797,17 @@ fun(srp, Username :: string(), UserState :: term()) ->
the client.</p></item>
<tag><c>{log_alert, boolean()}</c></tag>
- <item><p>If set to <c>false</c>, error reports are not displayed.</p></item>
+ <item><p>If set to <c>false</c>, error reports are not displayed.</p>
+ <p>Deprecated in OTP 22, use <seealso marker="#log_level">log_level</seealso> instead.</p>
+ </item>
+
+ <tag><marker id="log_level"/><c>{log_level, atom()}</c></tag>
+ <item><p>Specifies the log level for TLS/DTLS. It can take the following
+ values (ordered by increasing verbosity level): <c>emergency, alert, critical, error,
+ warning, notice, info, debug.</c></p>
+ <p>At verbosity level <c>notice</c> and above error reports are
+ displayed in TLS. The level <c>debug</c> triggers verbose logging of TLS protocol
+ messages and logging of ignored alerts in DTLS.</p></item>
<tag><c>{honor_cipher_order, boolean()}</c></tag>
<item><p>If set to <c>true</c>, use the server preference for cipher
@@ -887,16 +907,7 @@ fun(srp, Username :: string(), UserState :: term()) ->
<v>Type = erlang | openssl | all</v>
</type>
<desc>
- <p>Returns a list of supported cipher suites.
- This function will become deprecated in OTP 21, and replaced
- by <seealso marker="#cipher_suites-2">ssl:cipher-suites/2</seealso>
- <c>cipher_suites()</c> is equivalent to <c>cipher_suites(erlang).</c>
- Type <c>openssl</c> is provided for backwards compatibility with the
- old SSL, which used OpenSSL. <c>cipher_suites(all)</c> returns
- all available cipher suites. The cipher suites not present
- in <c>cipher_suites(erlang)</c> but included in
- <c>cipher_suites(all)</c> are not used unless explicitly configured
- by the user.</p>
+ <p>Deprecated in OTP 21, use <seealso marker="#cipher_suites-2">cipher_suites/2</seealso> instead.</p>
</desc>
</func>
@@ -939,7 +950,7 @@ fun(srp, Username :: string(), UserState :: term()) ->
<func>
<name>connect(Socket, SslOptions) -> </name>
- <name>connect(Socket, SslOptions, Timeout) -> {ok, TLSSocket} | {ok, TLSSocket, Ext}
+ <name>connect(Socket, SslOptions, Timeout) -> {ok, SslSocket} | {ok, SslSocket, Ext}
| {error, Reason}</name>
<fsummary>Upgrades a <c>gen_tcp</c>, or
equivalent, connected socket to an TLS socket.</fsummary>
@@ -947,7 +958,7 @@ fun(srp, Username :: string(), UserState :: term()) ->
<v>Socket = socket()</v>
<v>SslOptions = [{handshake, hello| full} | ssl_option()]</v>
<v>Timeout = integer() | infinity</v>
- <v>TLSSocket = sslsocket()</v>
+ <v>SslSocket = sslsocket()</v>
<v>Ext = hello_extensions()</v>
<v>Reason = term()</v>
</type>
@@ -964,8 +975,8 @@ fun(srp, Username :: string(), UserState :: term()) ->
<p> If the option <c>{handshake, hello}</c> is used the
handshake is paused after receiving the server hello message
- and the success response is <c>{ok, TLSSocket, Ext}</c>
- instead of <c>{ok, TLSSocket}</c>. Thereafter the handshake is continued or
+ and the success response is <c>{ok, SslSocket, Ext}</c>
+ instead of <c>{ok, SslSocket}</c>. Thereafter the handshake is continued or
canceled by calling <seealso marker="#handshake_continue-3">
<c>handshake_continue/3</c></seealso> or <seealso
marker="#handshake_cancel-1"><c>handshake_cancel/1</c></seealso>.
@@ -977,7 +988,7 @@ fun(srp, Username :: string(), UserState :: term()) ->
<func>
<name>connect(Host, Port, Options) -></name>
<name>connect(Host, Port, Options, Timeout) ->
- {ok, SslSocket}| {ok, TLSSocket, Ext} | {error, Reason}</name>
+ {ok, SslSocket}| {ok, SslSocket, Ext} | {error, Reason}</name>
<fsummary>Opens an TLS/DTLS connection to <c>Host</c>, <c>Port</c>.</fsummary>
<type>
<v>Host = host()</v>
@@ -1008,8 +1019,8 @@ fun(srp, Username :: string(), UserState :: term()) ->
<p> If the option <c>{handshake, hello}</c> is used the
handshake is paused after receiving the server hello message
- and the success response is <c>{ok, TLSSocket, Ext}</c>
- instead of <c>{ok, TLSSocket}</c>. Thereafter the handshake is continued or
+ and the success response is <c>{ok, SslSocket, Ext}</c>
+ instead of <c>{ok, SslSocket}</c>. Thereafter the handshake is continued or
canceled by calling <seealso marker="#handshake_continue-3">
<c>handshake_continue/3</c></seealso> or <seealso
marker="#handshake_cancel-1"><c>handshake_cancel/1</c></seealso>.
@@ -1065,7 +1076,8 @@ fun(srp, Username :: string(), UserState :: term()) ->
<fsummary>Returns all the connection information.
</fsummary>
<type>
- <v>Item = protocol | cipher_suite | sni_hostname | ecc | session_id | atom()</v>
+ <v>SslSocket = sslsocket()</v>
+ <v>Item = protocol | selected_cipher_suite | sni_hostname | ecc | session_id | atom()</v>
<d>Meaningful atoms, not specified above, are the ssl option names.</d>
<v>Result = [{Item::atom(), Value::term()}]</v>
<v>Reason = term()</v>
@@ -1073,6 +1085,9 @@ fun(srp, Username :: string(), UserState :: term()) ->
<desc><p>Returns the most relevant information about the connection, ssl options that
are undefined will be filtered out. Note that values that affect the security of the
connection will only be returned if explicitly requested by connection_information/2.</p>
+ <note><p>The legacy <c>Item = cipher_suite</c> is still supported
+ and returns the cipher suite on its (undocumented) legacy format.
+ It should be replaced by <c>selected_cipher_suite</c>.</p></note>
</desc>
</func>
@@ -1082,6 +1097,7 @@ fun(srp, Username :: string(), UserState :: term()) ->
<fsummary>Returns the requested connection information.
</fsummary>
<type>
+ <v>SslSocket = sslsocket()</v>
<v>Items = [Item]</v>
<v>Item = protocol | cipher_suite | sni_hostname | ecc | session_id | client_random
| server_random | master_secret | atom()</v>
@@ -1124,7 +1140,7 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>getopts(Socket, OptionNames) ->
+ <name>getopts(SslSocket, OptionNames) ->
{ok, [socketoption()]} | {error, Reason}</name>
<fsummary>Gets the values of the specified options.</fsummary>
<type>
@@ -1138,13 +1154,13 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>getstat(Socket) ->
+ <name>getstat(SslSocket) ->
{ok, OptionValues} | {error, inet:posix()}</name>
- <name>getstat(Socket, OptionNames) ->
+ <name>getstat(SslSocket, OptionNames) ->
{ok, OptionValues} | {error, inet:posix()}</name>
<fsummary>Get one or more statistic options for a socket</fsummary>
<type>
- <v>Socket = sslsocket()</v>
+ <v>SslSocket = sslsocket()</v>
<v>OptionNames = [atom()]</v>
<v>OptionValues = [{inet:stat_option(), integer()}]</v>
</type>
@@ -1155,28 +1171,27 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>handshake(Socket) -> </name>
- <name>handshake(Socket, Timeout) -> {ok, Socket} | {error, Reason}</name>
+ <name>handshake(HsSocket) -> </name>
+ <name>handshake(HsSocket, Timeout) -> {ok, SslSocket} | {error, Reason}</name>
<fsummary>Performs server-side SSL/TLS handshake.</fsummary>
<type>
- <v>Socket = sslsocket()</v>
+ <v>HsSocket = SslSocket = sslsocket()</v>
<v>Timeout = integer()</v>
<v>Reason = term()</v>
</type>
<desc>
<p>Performs the SSL/TLS/DTLS server-side handshake.</p>
- <p><c>Socket</c> is a socket as returned by
- <seealso marker="#transport_accept-2">ssl:transport_accept/[1,2]</seealso>.
- </p>
+ <p>Returns a new TLS/DTLS socket if the handshake is successful.</p>
</desc>
</func>
<func>
<name>handshake(Socket, SslOptions) -> </name>
- <name>handshake(Socket, SslOptions, Timeout) -> {ok, Socket} | {ok, Socket, Ext} | {error, Reason}</name>
+ <name>handshake(Socket, SslOptions, Timeout) -> {ok, SslSocket} | {ok, SslSocket, Ext} | {error, Reason}</name>
<fsummary>Performs server-side SSL/TLS/DTLS handshake.</fsummary>
<type>
<v>Socket = socket() | sslsocket() </v>
+ <v>SslSocket = sslsocket() </v>
<v>Ext = hello_extensions()</v>
<v>SslOptions = [{handshake, hello| full} | ssl_option()]</v>
<v>Timeout = integer()</v>
@@ -1185,22 +1200,23 @@ fun(srp, Username :: string(), UserState :: term()) ->
<desc>
<p>If <c>Socket</c> is a ordinary <c>socket()</c>: upgrades a <c>gen_tcp</c>,
or equivalent, socket to an SSL socket, that is, performs
- the SSL/TLS server-side handshake and returns the SSL socket.</p>
+ the SSL/TLS server-side handshake and returns a TLS socket.</p>
- <warning><p>The Socket shall be in passive mode ({active,
- false}) before calling this function or the handshake can fail
- due to a race condition.</p></warning>
+ <warning><p>The <c>Socket</c> shall be in passive mode ({active,
+ false}) before calling this function or else the behavior of this function
+ is undefined.
+ </p></warning>
<p>If <c>Socket</c> is an <c>sslsocket()</c>: provides extra SSL/TLS/DTLS
options to those specified in
- <seealso marker="#listen-2">ssl:listen/2 </seealso> and then performs
- the SSL/TLS/DTLS handshake.</p>
-
+ <seealso marker="#listen-2">listen/2 </seealso> and then performs
+ the SSL/TLS/DTLS handshake. Returns a new TLS/DTLS socket if the handshake is successful.</p>
+
<p>
If option <c>{handshake, hello}</c> is specified the handshake is
paused after receiving the client hello message and the
- sucess response is <c>{ok, TLSSocket, Ext}</c> instead of <c>{ok,
- TLSSocket}</c>. Thereafter the handshake is continued or
+ success response is <c>{ok, SslSocket, Ext}</c> instead of <c>{ok,
+ SslSocket}</c>. Thereafter the handshake is continued or
canceled by calling <seealso marker="#handshake_continue-3">
<c>handshake_continue/3</c></seealso> or <seealso
marker="#handshake_cancel-1"><c>handshake_cancel/1</c></seealso>.
@@ -1209,10 +1225,10 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>handshake_cancel(Socket) -> ok </name>
+ <name>handshake_cancel(SslSocket) -> ok </name>
<fsummary>Cancel handshake with a fatal alert</fsummary>
<type>
- <v>Socket = sslsocket()</v>
+ <v>SslSocket = sslsocket()</v>
</type>
<desc>
<p>Cancel the handshake with a fatal <c>USER_CANCELED</c> alert.</p>
@@ -1220,10 +1236,11 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>handshake_continue(Socket, SSLOptions, Timeout) -> {ok, Socket} | {error, Reason}</name>
+ <name>handshake_continue(HsSocket, SSLOptions) -> {ok, SslSocket} | {error, Reason}</name>
+ <name>handshake_continue(HsSocket, SSLOptions, Timeout) -> {ok, SslSocket} | {error, Reason}</name>
<fsummary>Continue the SSL/TLS handshake.</fsummary>
<type>
- <v>Socket = sslsocket()</v>
+ <v>HsSocket = SslSocket = sslsocket()</v>
<v>SslOptions = [ssl_option()]</v>
<v>Timeout = integer()</v>
<v>Reason = term()</v>
@@ -1248,10 +1265,10 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>negotiated_protocol(Socket) -> {ok, Protocol} | {error, protocol_not_negotiated}</name>
+ <name>negotiated_protocol(SslSocket) -> {ok, Protocol} | {error, protocol_not_negotiated}</name>
<fsummary>Returns the protocol negotiated through ALPN or NPN extensions.</fsummary>
<type>
- <v>Socket = sslsocket()</v>
+ <v>SslSocket = sslsocket()</v>
<v>Protocol = binary()</v>
</type>
<desc>
@@ -1262,25 +1279,26 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>peercert(Socket) -> {ok, Cert} | {error, Reason}</name>
+ <name>peercert(SslSocket) -> {ok, Cert} | {error, Reason}</name>
<fsummary>Returns the peer certificate.</fsummary>
<type>
- <v>Socket = sslsocket()</v>
+ <v>SslSocket = sslsocket()</v>
<v>Cert = binary()</v>
</type>
<desc>
<p>The peer certificate is returned as a DER-encoded binary.
The certificate can be decoded with
- <c>public_key:pkix_decode_cert/2</c>.</p>
+ <seealso marker="public_key:public_key#pkix_decode_cert-2">public_key:pkix_decode_cert/2</seealso>
+ </p>
</desc>
</func>
<func>
- <name>peername(Socket) -> {ok, {Address, Port}} |
+ <name>peername(SslSocket) -> {ok, {Address, Port}} |
{error, Reason}</name>
<fsummary>Returns the peer address and port.</fsummary>
<type>
- <v>Socket = sslsocket()</v>
+ <v>SslSocket = sslsocket()</v>
<v>Address = ipaddress()</v>
<v>Port = integer()</v>
</type>
@@ -1326,12 +1344,12 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>recv(Socket, Length) -> </name>
- <name>recv(Socket, Length, Timeout) -> {ok, Data} | {error,
+ <name>recv(SslSocket, Length) -> </name>
+ <name>recv(SslSocket, Length, Timeout) -> {ok, Data} | {error,
Reason}</name>
<fsummary>Receives data on a socket.</fsummary>
<type>
- <v>Socket = sslsocket()</v>
+ <v>SslSocket = sslsocket()</v>
<v>Length = integer()</v>
<v>Timeout = integer()</v>
<v>Data = [char()] | binary()</v>
@@ -1353,10 +1371,10 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>renegotiate(Socket) -> ok | {error, Reason}</name>
+ <name>renegotiate(SslSocket) -> ok | {error, Reason}</name>
<fsummary>Initiates a new handshake.</fsummary>
<type>
- <v>Socket = sslsocket()</v>
+ <v>SslSocket = sslsocket()</v>
</type>
<desc><p>Initiates a new handshake. A notable return value is
<c>{error, renegotiation_rejected}</c> indicating that the peer
@@ -1366,10 +1384,10 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>send(Socket, Data) -> ok | {error, Reason}</name>
+ <name>send(SslSocket, Data) -> ok | {error, Reason}</name>
<fsummary>Writes data to a socket.</fsummary>
<type>
- <v>Socket = sslsocket()</v>
+ <v>SslSocket = sslsocket()</v>
<v>Data = iodata()</v>
</type>
<desc>
@@ -1380,10 +1398,10 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>setopts(Socket, Options) -> ok | {error, Reason}</name>
+ <name>setopts(SslSocket, Options) -> ok | {error, Reason}</name>
<fsummary>Sets socket options.</fsummary>
<type>
- <v>Socket = sslsocket()</v>
+ <v>SslSocket = sslsocket()</v>
<v>Options = [socketoption]()</v>
</type>
<desc>
@@ -1393,10 +1411,21 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>shutdown(Socket, How) -> ok | {error, Reason}</name>
+ <name>set_log_level(Level) -> ok | {error, Reason}</name>
+ <fsummary>Sets log level for the SSL application.</fsummary>
+ <type>
+ <v>Level = atom()</v>
+ </type>
+ <desc>
+ <p>Sets log level for the SSL application.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>shutdown(SslSocket, How) -> ok | {error, Reason}</name>
<fsummary>Immediately closes a socket.</fsummary>
<type>
- <v>Socket = sslsocket()</v>
+ <v>SslSocket = sslsocket()</v>
<v>How = read | write | read_write</v>
<v>Reason = reason()</v>
</type>
@@ -1411,19 +1440,17 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>ssl_accept(Socket) -> </name>
- <name>ssl_accept(Socket, Timeout) -> ok | {error, Reason}</name>
+ <name>ssl_accept(SslSocket) -> </name>
+ <name>ssl_accept(SslSocket, Timeout) -> ok | {error, Reason}</name>
<fsummary>Performs server-side SSL/TLS handshake.</fsummary>
<type>
- <v>Socket = sslsocket()</v>
+ <v>SslSocket = sslsocket()</v>
<v>Timeout = integer()</v>
<v>Reason = term()</v>
</type>
<desc>
- <p>Performs the SSL/TLS/DTLS server-side handshake.</p>
- <p><c>Socket</c> is a socket as returned by
- <seealso marker="#transport_accept-2">ssl:transport_accept/[1,2]</seealso>
- </p>
+ <p>Deprecated in OTP 21, use <seealso marker="#handshake-1">handshake/[1,2]</seealso> instead.</p>
+ <note><p>handshake/[1,2] always returns a new socket.</p></note>
</desc>
</func>
@@ -1438,29 +1465,17 @@ fun(srp, Username :: string(), UserState :: term()) ->
<v>Reason = term()</v>
</type>
<desc>
- <p>If <c>Socket</c> is a <c>socket()</c>: upgrades a <c>gen_tcp</c>,
- or equivalent, socket to an SSL socket, that is, performs
- the SSL/TLS server-side handshake and returns the SSL socket.</p>
-
- <warning><p>The listen socket is to be in mode <c>{active, false}</c>
- before telling the client that the server is ready to upgrade
- by calling this function, else the upgrade succeeds or does not
- succeed depending on timing.</p></warning>
-
- <p>If <c>Socket</c> is an <c>sslsocket()</c>: provides extra SSL/TLS/DTLS
- options to those specified in
- <seealso marker="#listen-2">ssl:listen/2 </seealso> and then performs
- the SSL/TLS/DTLS handshake.
- </p>
+ <p>Deprecated in OTP 21, use <seealso marker="#handshake-3">handshake/[2,3]</seealso> instead.</p>
+ <note><p>handshake/[2,3] always returns a new socket.</p></note>
</desc>
</func>
<func>
- <name>sockname(Socket) -> {ok, {Address, Port}} |
+ <name>sockname(SslSocket) -> {ok, {Address, Port}} |
{error, Reason}</name>
<fsummary>Returns the local address and port.</fsummary>
<type>
- <v>Socket = sslsocket()</v>
+ <v>SslSocket = sslsocket()</v>
<v>Address = ipaddress()</v>
<v>Port = integer()</v>
</type>
@@ -1492,32 +1507,44 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
+ <name>suite_to_str(CipherSuite) -> String</name>
+ <fsummary>Returns the string representation of a cipher suite.</fsummary>
+ <type>
+ <v>CipherSuite = erl_cipher_suite()</v>
+ <v>String = string()</v>
+ </type>
+ <desc>
+ <p>Returns the string representation of a cipher suite.</p>
+ </desc>
+ </func>
+
+ <func>
<name>transport_accept(ListenSocket) -></name>
<name>transport_accept(ListenSocket, Timeout) ->
- {ok, NewSocket} | {error, Reason}</name>
+ {ok, SslSocket} | {error, Reason}</name>
<fsummary>Accepts an incoming connection and
prepares for <c>ssl_accept</c>.</fsummary>
<type>
- <v>ListenSocket = NewSocket = sslsocket()</v>
+ <v>ListenSocket = SslSocket = sslsocket()</v>
<v>Timeout = integer()</v>
<v>Reason = reason()</v>
</type>
<desc>
<p>Accepts an incoming connection request on a listen socket.
<c>ListenSocket</c> must be a socket returned from
- <seealso marker="#listen-2"> ssl:listen/2</seealso>.
+ <seealso marker="#listen-2"> listen/2</seealso>.
The socket returned is to be passed to
- <seealso marker="#ssl_accept-2"> ssl:ssl_accept[2,3]</seealso>
+ <seealso marker="#handshake-2"> handshake/[2,3]</seealso>
to complete handshaking, that is,
establishing the SSL/TLS/DTLS connection.</p>
<warning>
- <p>The socket returned can only be used with
- <seealso marker="#ssl_accept-2"> ssl:ssl_accept[2,3]</seealso>.
- No traffic can be sent or received before that call.</p>
+ <p>Most API functions require that the TLS/DTLS
+ connection is established to work as expected.
+ </p>
</warning>
<p>The accepted socket inherits the options set for
<c>ListenSocket</c> in
- <seealso marker="#listen-2"> ssl:listen/2</seealso>.</p>
+ <seealso marker="#listen-2"> listen/2</seealso>.</p>
<p>The default
value for <c>Timeout</c> is <c>infinity</c>. If
<c>Timeout</c> is specified and no connection is accepted
@@ -1548,7 +1575,7 @@ fun(srp, Username :: string(), UserState :: term()) ->
<seealso marker="#listen-2"> listen/2</seealso>, and <seealso
marker="#ssl_accept-2">ssl_accept/[1,2,3]</seealso>.
For the negotiated SSL/TLS version, see <seealso
- marker="#connection_information-1">ssl:connection_information/1
+ marker="#connection_information-1">connection_information/1
</seealso>.</item>
<tag><c>supported_dtls</c></tag>
@@ -1558,7 +1585,7 @@ fun(srp, Username :: string(), UserState :: term()) ->
<seealso marker="#listen-2"> listen/2</seealso>, and <seealso
marker="#ssl_accept-2">ssl_accept/[1,2,3]</seealso>.
For the negotiated DTLS version, see <seealso
- marker="#connection_information-1">ssl:connection_information/1
+ marker="#connection_information-1">connection_information/1
</seealso>.</item>
<tag><c>available</c></tag>
diff --git a/lib/ssl/doc/src/ssl_app.xml b/lib/ssl/doc/src/ssl_app.xml
index e22d43db0e..f6d9021d4a 100644
--- a/lib/ssl/doc/src/ssl_app.xml
+++ b/lib/ssl/doc/src/ssl_app.xml
@@ -4,7 +4,7 @@
<appref>
<header>
<copyright>
- <year>1999</year><year>2016</year>
+ <year>1999</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/ssl/doc/src/ssl_crl_cache.xml b/lib/ssl/doc/src/ssl_crl_cache.xml
index 738487759a..71c6d5e49e 100644
--- a/lib/ssl/doc/src/ssl_crl_cache.xml
+++ b/lib/ssl/doc/src/ssl_crl_cache.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2015</year><year>2015</year>
+ <year>2015</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/ssl/doc/src/ssl_distribution.xml b/lib/ssl/doc/src/ssl_distribution.xml
index e14f3f90dc..1774bd8f77 100644
--- a/lib/ssl/doc/src/ssl_distribution.xml
+++ b/lib/ssl/doc/src/ssl_distribution.xml
@@ -191,7 +191,7 @@ Eshell V5.0 (abort with ^G)
Any available SSL/TLS option can be specified in an options file,
but note that options that take a <c>fun()</c> has to use
the syntax <c>fun Mod:Func/Arity</c> since a function
- body can not be compiled when consulting a file.
+ body cannot be compiled when consulting a file.
</p>
<p>
Do not tamper with the socket options
diff --git a/lib/ssl/doc/src/ssl_introduction.xml b/lib/ssl/doc/src/ssl_introduction.xml
index a416924eb1..adcfb091b7 100644
--- a/lib/ssl/doc/src/ssl_introduction.xml
+++ b/lib/ssl/doc/src/ssl_introduction.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2015</year>
- <year>2017</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/ssl/doc/src/ssl_protocol.xml b/lib/ssl/doc/src/ssl_protocol.xml
index 0b12dc7dc5..3ab836443f 100644
--- a/lib/ssl/doc/src/ssl_protocol.xml
+++ b/lib/ssl/doc/src/ssl_protocol.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2015</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/ssl/doc/src/using_ssl.xml b/lib/ssl/doc/src/using_ssl.xml
index 3ef33df719..f2f9b66a31 100644
--- a/lib/ssl/doc/src/using_ssl.xml
+++ b/lib/ssl/doc/src/using_ssl.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2016</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -66,7 +66,7 @@ ssl:listen(9999, [{certfile, "cert.pem"}, {keyfile, "key.pem"},{reuseaddr, true}
{ok,{sslsocket, [...]}}</code>
<p><em>Step 3:</em> Do a transport accept on the TLS listen socket:</p>
- <code type="erl">3 server> {ok, Socket} = ssl:transport_accept(ListenSocket).
+ <code type="erl">3 server> {ok, TLSTransportSocket} = ssl:transport_accept(ListenSocket).
{ok,{sslsocket, [...]}}</code>
<p><em>Step 4:</em> Start the client side: </p>
@@ -77,7 +77,7 @@ ok</code>
{ok,{sslsocket, [...]}}</code>
<p><em>Step 5:</em> Do the TLS handshake:</p>
- <code type="erl">4 server> ok = ssl:ssl_accept(Socket).
+ <code type="erl">4 server> {ok, Socket} = ssl:handshake(TLSTransportSocket).
ok</code>
<p><em>Step 6:</em> Send a message over TLS:</p>
@@ -126,13 +126,13 @@ ok</code>
ok</code>
<p><em>Step 6:</em> Do the TLS handshake:</p>
- <code type="erl">5 server> {ok, TLSSocket} = ssl:ssl_accept(Socket, [{cacertfile, "cacerts.pem"},
+ <code type="erl">5 server> {ok, TLSSocket} = ssl:handshake(Socket, [{cacertfile, "cacerts.pem"},
{certfile, "cert.pem"}, {keyfile, "key.pem"}]).
{ok,{sslsocket,[...]}}</code>
<p><em>Step 7:</em> Upgrade to an TLS connection. The client and server
must agree upon the upgrade. The server must call
- <c>ssl:accept/2</c> before the client calls <c>ssl:connect/3.</c></p>
+ <c>ssl:handshake/2</c> before the client calls <c>ssl:connect/3.</c></p>
<code type="erl">3 client>{ok, TLSSocket} = ssl:connect(Socket, [{cacertfile, "cacerts.pem"},
{certfile, "cert.pem"}, {keyfile, "key.pem"}], infinity).
{ok,{sslsocket,[...]}}</code>
diff --git a/lib/ssl/examples/src/client_server.erl b/lib/ssl/examples/src/client_server.erl
index c150f43bff..7a266f544d 100644
--- a/lib/ssl/examples/src/client_server.erl
+++ b/lib/ssl/examples/src/client_server.erl
@@ -39,15 +39,15 @@ start() ->
%% Accept
{ok, ASock} = ssl:transport_accept(LSock),
- ok = ssl:ssl_accept(ASock),
+ {ok, SslSocket} = ssl:handshake(ASock),
io:fwrite("Accept: accepted.~n"),
- {ok, Cert} = ssl:peercert(ASock),
+ {ok, Cert} = ssl:peercert(SslSocket),
io:fwrite("Accept: peer cert:~n~p~n", [public_key:pkix_decode_cert(Cert, otp)]),
io:fwrite("Accept: sending \"hello\".~n"),
- ssl:send(ASock, "hello"),
- {error, closed} = ssl:recv(ASock, 0),
+ ssl:send(SslSocket, "hello"),
+ {error, closed} = ssl:recv(SslSocket, 0),
io:fwrite("Accept: detected closed.~n"),
- ssl:close(ASock),
+ ssl:close(SslSocket),
io:fwrite("Listen: closing and terminating.~n"),
ssl:close(LSock),
@@ -75,7 +75,7 @@ mk_opts(Role) ->
[{active, false},
{verify, 2},
{depth, 2},
+ {server_name_indication, disable},
{cacertfile, filename:join([Dir, Role, "cacerts.pem"])},
{certfile, filename:join([Dir, Role, "cert.pem"])},
{keyfile, filename:join([Dir, Role, "key.pem"])}].
-
diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile
index 11b3e65912..1db18d4e5a 100644
--- a/lib/ssl/src/Makefile
+++ b/lib/ssl/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2017. All Rights Reserved.
+# Copyright Ericsson AB 1999-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -54,8 +54,8 @@ MODULES= \
ssl_connection_sup \
ssl_listen_tracker_sup\
dtls_connection_sup \
- dtls_udp_listener\
- dtls_udp_sup \
+ dtls_packet_demux \
+ dtls_listener_sup \
ssl_dist_sup\
ssl_dist_admin_sup\
ssl_dist_connection_sup\
@@ -86,7 +86,8 @@ MODULES= \
ssl_record \
ssl_v3 \
tls_v1 \
- dtls_v1
+ dtls_v1 \
+ ssl_logger
INTERNAL_HRL_FILES = \
ssl_alert.hrl ssl_cipher.hrl \
@@ -118,7 +119,7 @@ EXTRA_ERLC_FLAGS = +warn_unused_vars
ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/kernel/src \
-pz $(EBIN) \
-pz $(ERL_TOP)/lib/public_key/ebin \
- $(EXTRA_ERLC_FLAGS) -DVSN=\"$(VSN)\"
+ $(EXTRA_ERLC_FLAGS)
# ----------------------------------------------------
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index 0fe568759d..c0e81d6a28 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
-include("ssl_internal.hrl").
-include("ssl_srp.hrl").
-include_lib("public_key/include/public_key.hrl").
+-include_lib("kernel/include/logger.hrl").
%% Internal application API
@@ -91,13 +92,14 @@ start_link(Role, Host, Port, Socket, Options, User, CbInfo) ->
init([Role, Host, Port, Socket, Options, User, CbInfo]) ->
process_flag(trap_exit, true),
- State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo),
+ State0 = #state{protocol_specific = Map} = initial_state(Role, Host, Port, Socket, Options, User, CbInfo),
try
State = ssl_connection:ssl_config(State0#state.ssl_options, Role, State0),
gen_statem:enter_loop(?MODULE, [], init, State)
catch
throw:Error ->
- gen_statem:enter_loop(?MODULE, [], error, {Error,State0})
+ EState = State0#state{protocol_specific = Map#{error => Error}},
+ gen_statem:enter_loop(?MODULE, [], error, EState)
end.
%%====================================================================
%% State transition handling
@@ -137,9 +139,8 @@ next_record(#state{protocol_buffers =
Buffers#protocol_buffers{dtls_cipher_texts = Rest},
connection_states = ConnectionStates});
next_record(#state{role = server,
- socket = {Listener, {Client, _}},
- transport_cb = gen_udp} = State) ->
- dtls_udp_listener:active_once(Listener, Client, self()),
+ socket = {Listener, {Client, _}}} = State) ->
+ dtls_packet_demux:active_once(Listener, Client, self()),
{no_record, State};
next_record(#state{role = client,
socket = {_Server, Socket} = DTLSSocket,
@@ -448,7 +449,7 @@ init({call, From}, {start, Timeout},
},
{Record, State} = next_record(State3),
next_event(hello, Record, State, Actions);
-init({call, _} = Type, Event, #state{role = server, transport_cb = gen_udp} = State) ->
+init({call, _} = Type, Event, #state{role = server, data_tag = udp} = State) ->
Result = gen_handshake(?FUNCTION_NAME, Type, Event,
State#state{flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT},
protocol_specific = #{current_cookie_secret => dtls_v1:cookie_secret(),
@@ -471,7 +472,8 @@ init(Type, Event, State) ->
%%--------------------------------------------------------------------
error(enter, _, State) ->
{keep_state, State};
-error({call, From}, {start, _Timeout}, {Error, State}) ->
+error({call, From}, {start, _Timeout},
+ #state{protocol_specific = #{error := Error}} = State) ->
ssl_connection:stop_and_reply(
normal, {reply, From, {error, Error}}, State);
error({call, _} = Call, Msg, State) ->
@@ -922,12 +924,12 @@ handle_alerts([Alert | Alerts], {next_state, StateName, State}) ->
handle_alerts([Alert | Alerts], {next_state, StateName, State, _Actions}) ->
handle_alerts(Alerts, ssl_connection:handle_alert(Alert, StateName, State)).
-handle_own_alert(Alert, Version, StateName, #state{transport_cb = gen_udp,
+handle_own_alert(Alert, Version, StateName, #state{data_tag = udp,
role = Role,
ssl_options = Options} = State0) ->
case ignore_alert(Alert, State0) of
{true, State} ->
- log_ignore_alert(Options#ssl_options.log_alert, StateName, Alert, Role),
+ log_ignore_alert(Options#ssl_options.log_level, StateName, Alert, Role),
{next_state, StateName, State};
{false, State} ->
ssl_connection:handle_own_alert(Alert, Version, StateName, State)
@@ -1013,10 +1015,10 @@ next_flight(Flight) ->
change_cipher_spec => undefined,
handshakes_after_change_cipher_spec => []}.
-handle_flight_timer(#state{transport_cb = gen_udp,
+handle_flight_timer(#state{data_tag = udp,
flight_state = {retransmit, Timeout}} = State) ->
start_retransmision_timer(Timeout, State);
-handle_flight_timer(#state{transport_cb = gen_udp,
+handle_flight_timer(#state{data_tag = udp,
flight_state = connection} = State) ->
{State, []};
handle_flight_timer(State) ->
@@ -1124,9 +1126,9 @@ is_ignore_alert(#alert{description = ?ILLEGAL_PARAMETER}) ->
is_ignore_alert(_) ->
false.
-log_ignore_alert(true, StateName, Alert, Role) ->
+log_ignore_alert(debug, StateName, Alert, Role) ->
Txt = ssl_alert:alert_txt(Alert),
- error_logger:format("DTLS over UDP ~p: In state ~p ignored to send ALERT ~s as DoS-attack mitigation \n",
- [Role, StateName, Txt]);
-log_ignore_alert(false, _, _,_) ->
+ ?LOG_ERROR("DTLS over UDP ~p: In state ~p ignored to send ALERT ~s as DoS-attack mitigation \n",
+ [Role, StateName, Txt]);
+log_ignore_alert(_, _, _, _) ->
ok.
diff --git a/lib/ssl/src/dtls_handshake.erl b/lib/ssl/src/dtls_handshake.erl
index 1a415a5f76..35c213a182 100644
--- a/lib/ssl/src/dtls_handshake.erl
+++ b/lib/ssl/src/dtls_handshake.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/src/dtls_udp_sup.erl b/lib/ssl/src/dtls_listener_sup.erl
index 197882e92f..dc30696a2c 100644
--- a/lib/ssl/src/dtls_udp_sup.erl
+++ b/lib/ssl/src/dtls_listener_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2016-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2016-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@
%% Purpose: Supervisor for a procsses dispatching upd datagrams to
%% correct DTLS handler
%%----------------------------------------------------------------------
--module(dtls_udp_sup).
+-module(dtls_listener_sup).
-behaviour(supervisor).
@@ -52,10 +52,10 @@ init(_O) ->
MaxT = 3600,
Name = undefined, % As simple_one_for_one is used.
- StartFunc = {dtls_udp_listener, start_link, []},
+ StartFunc = {dtls_packet_demux, start_link, []},
Restart = temporary, % E.g. should not be restarted
Shutdown = 4000,
- Modules = [dtls_udp_listener],
+ Modules = [dtls_packet_demux],
Type = worker,
ChildSpec = {Name, StartFunc, Restart, Shutdown, Type, Modules},
diff --git a/lib/ssl/src/dtls_udp_listener.erl b/lib/ssl/src/dtls_packet_demux.erl
index 0608c6bd2b..e03a4e9cb9 100644
--- a/lib/ssl/src/dtls_udp_listener.erl
+++ b/lib/ssl/src/dtls_packet_demux.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2016-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2016-2018. 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
@@ -19,15 +19,16 @@
%%
--module(dtls_udp_listener).
+-module(dtls_packet_demux).
-behaviour(gen_server).
-include("ssl_internal.hrl").
+-include_lib("kernel/include/logger.hrl").
%% API
--export([start_link/4, active_once/3, accept/2, sockname/1, close/1,
- get_all_opts/1, get_sock_opts/2, set_sock_opts/2]).
+-export([start_link/5, active_once/3, accept/2, sockname/1, close/1,
+ get_all_opts/1, get_sock_opts/2, set_sock_opts/2]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -36,6 +37,7 @@
-record(state,
{port,
listener,
+ transport,
dtls_options,
emulated_options,
dtls_msq_queues = kv_new(),
@@ -50,35 +52,36 @@
%%% API
%%%===================================================================
-start_link(Port, EmOpts, InetOptions, DTLSOptions) ->
- gen_server:start_link(?MODULE, [Port, EmOpts, InetOptions, DTLSOptions], []).
+start_link(Port, TransportInfo, EmOpts, InetOptions, DTLSOptions) ->
+ gen_server:start_link(?MODULE, [Port, TransportInfo, EmOpts, InetOptions, DTLSOptions], []).
-active_once(UDPConnection, Client, Pid) ->
- gen_server:cast(UDPConnection, {active_once, Client, Pid}).
+active_once(PacketSocket, Client, Pid) ->
+ gen_server:cast(PacketSocket, {active_once, Client, Pid}).
-accept(UDPConnection, Accepter) ->
- call(UDPConnection, {accept, Accepter}).
+accept(PacketSocket, Accepter) ->
+ call(PacketSocket, {accept, Accepter}).
-sockname(UDPConnection) ->
- call(UDPConnection, sockname).
-close(UDPConnection) ->
- call(UDPConnection, close).
-get_sock_opts(UDPConnection, SplitSockOpts) ->
- call(UDPConnection, {get_sock_opts, SplitSockOpts}).
-get_all_opts(UDPConnection) ->
- call(UDPConnection, get_all_opts).
-set_sock_opts(UDPConnection, Opts) ->
- call(UDPConnection, {set_sock_opts, Opts}).
+sockname(PacketSocket) ->
+ call(PacketSocket, sockname).
+close(PacketSocket) ->
+ call(PacketSocket, close).
+get_sock_opts(PacketSocket, SplitSockOpts) ->
+ call(PacketSocket, {get_sock_opts, SplitSockOpts}).
+get_all_opts(PacketSocket) ->
+ call(PacketSocket, get_all_opts).
+set_sock_opts(PacketSocket, Opts) ->
+ call(PacketSocket, {set_sock_opts, Opts}).
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
-init([Port, EmOpts, InetOptions, DTLSOptions]) ->
+init([Port, {TransportModule, _,_,_} = TransportInfo, EmOpts, InetOptions, DTLSOptions]) ->
try
- {ok, Socket} = gen_udp:open(Port, InetOptions),
+ {ok, Socket} = TransportModule:open(Port, InetOptions),
{ok, #state{port = Port,
first = true,
+ transport = TransportInfo,
dtls_options = DTLSOptions,
emulated_options = EmOpts,
listener = Socket,
@@ -134,21 +137,21 @@ handle_cast({active_once, Client, Pid}, State0) ->
State = handle_active_once(Client, Pid, State0),
{noreply, State}.
-handle_info({udp, Socket, IP, InPortNo, _} = Msg, #state{listener = Socket} = State0) ->
+handle_info({Transport, Socket, IP, InPortNo, _} = Msg, #state{listener = Socket, transport = {_,Transport,_,_}} = State0) ->
State = handle_datagram({IP, InPortNo}, Msg, State0),
next_datagram(Socket),
{noreply, State};
%% UDP socket does not have a connection and should not receive an econnreset
-%% This does however happens on on some windows versions. Just ignoring it
+%% This does however happens on some windows versions. Just ignoring it
%% appears to make things work as expected!
-handle_info({udp_error, Socket, econnreset = Error}, #state{listener = Socket} = State) ->
+handle_info({Error, Socket, econnreset = Error}, #state{listener = Socket, transport = {_,_,_, udp_error}} = State) ->
Report = io_lib:format("Ignore SSL UDP Listener: Socket error: ~p ~n", [Error]),
- error_logger:info_report(Report),
+ ?LOG_NOTICE(Report),
{noreply, State};
-handle_info({udp_error, Socket, Error}, #state{listener = Socket} = State) ->
- Report = io_lib:format("SSL UDP Listener shutdown: Socket error: ~p ~n", [Error]),
- error_logger:info_report(Report),
+handle_info({Error, Socket, Error}, #state{listener = Socket, transport = {_,_,_, Error}} = State) ->
+ Report = io_lib:format("SSL Packet muliplxer shutdown: Socket error: ~p ~n", [Error]),
+ ?LOG_NOTICE(Report),
{noreply, State#state{close=true}};
handle_info({'DOWN', _, process, Pid, _}, #state{clients = Clients,
@@ -231,7 +234,7 @@ setup_new_connection(User, From, Client, Msg, #state{dtls_processes = Processes,
listener = Socket,
emulated_options = EmOpts} = State) ->
ConnArgs = [server, "localhost", Port, {self(), {Client, Socket}},
- {DTLSOpts, EmOpts, udp_listener}, User, dtls_socket:default_cb_info()],
+ {DTLSOpts, EmOpts, dtls_listener}, User, dtls_socket:default_cb_info()],
case dtls_connection_sup:start_child(ConnArgs) of
{ok, Pid} ->
erlang:monitor(process, Pid),
diff --git a/lib/ssl/src/dtls_record.erl b/lib/ssl/src/dtls_record.erl
index 2938fd460f..9eb0d8e2d7 100644
--- a/lib/ssl/src/dtls_record.erl
+++ b/lib/ssl/src/dtls_record.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/src/dtls_socket.erl b/lib/ssl/src/dtls_socket.erl
index 0e4ab089dc..b26d3ae41a 100644
--- a/lib/ssl/src/dtls_socket.erl
+++ b/lib/ssl/src/dtls_socket.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2016-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2016-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,31 +22,31 @@
-include("ssl_internal.hrl").
-include("ssl_api.hrl").
--export([send/3, listen/3, accept/3, connect/4, socket/4, setopts/3, getopts/3, getstat/3,
+-export([send/3, listen/2, accept/3, connect/4, socket/4, setopts/3, getopts/3, getstat/3,
peername/2, sockname/2, port/2, close/2]).
-export([emulated_options/0, emulated_options/1, internal_inet_values/0, default_inet_values/0, default_cb_info/0]).
send(Transport, {{IP,Port},Socket}, Data) ->
Transport:send(Socket, IP, Port, Data).
-listen(gen_udp = Transport, Port, #config{transport_info = {Transport, _, _, _},
- ssl = SslOpts,
- emulated = EmOpts,
- inet_user = Options} = Config) ->
+listen(Port, #config{transport_info = TransportInfo,
+ ssl = SslOpts,
+ emulated = EmOpts,
+ inet_user = Options} = Config) ->
- case dtls_udp_sup:start_child([Port, emulated_socket_options(EmOpts, #socket_options{}),
+ case dtls_listener_sup:start_child([Port, TransportInfo, emulated_socket_options(EmOpts, #socket_options{}),
Options ++ internal_inet_values(), SslOpts]) of
{ok, Pid} ->
- {ok, #sslsocket{pid = {udp, Config#config{udp_handler = {Pid, Port}}}}};
+ {ok, #sslsocket{pid = {dtls, Config#config{dtls_handler = {Pid, Port}}}}};
Err = {error, _} ->
Err
end.
-accept(udp, #config{transport_info = {Transport = gen_udp,_,_,_},
+accept(dtls, #config{transport_info = {Transport,_,_,_},
connection_cb = ConnectionCb,
- udp_handler = {Listner, _}}, _Timeout) ->
- case dtls_udp_listener:accept(Listner, self()) of
+ dtls_handler = {Listner, _}}, _Timeout) ->
+ case dtls_packet_demux:accept(Listner, self()) of
{ok, Pid, Socket} ->
{ok, socket(Pid, Transport, {Listner, Socket}, ConnectionCb)};
{error, Reason} ->
@@ -69,7 +69,9 @@ connect(Address, Port, #config{transport_info = {Transport, _, _, _} = CbInfo,
end.
close(gen_udp, {_Client, _Socket}) ->
- ok.
+ ok;
+close(Transport, {_Client, Socket}) ->
+ Transport:close(Socket).
socket(Pid, gen_udp = Transport, {{_, _}, Socket}, ConnectionCb) ->
#sslsocket{pid = Pid,
@@ -79,18 +81,18 @@ socket(Pid, Transport, Socket, ConnectionCb) ->
#sslsocket{pid = Pid,
%% "The name "fd" is keept for backwards compatibility
fd = {Transport, Socket, ConnectionCb}}.
-setopts(_, #sslsocket{pid = {udp, #config{udp_handler = {ListenPid, _}}}}, Options) ->
+setopts(_, #sslsocket{pid = {dtls, #config{dtls_handler = {ListenPid, _}}}}, Options) ->
SplitOpts = tls_socket:split_options(Options),
- dtls_udp_listener:set_sock_opts(ListenPid, SplitOpts);
+ dtls_packet_demux:set_sock_opts(ListenPid, SplitOpts);
%%% Following clauses will not be called for emulated options, they are handled in the connection process
setopts(gen_udp, Socket, Options) ->
inet:setopts(Socket, Options);
setopts(Transport, Socket, Options) ->
Transport:setopts(Socket, Options).
-getopts(_, #sslsocket{pid = {udp, #config{udp_handler = {ListenPid, _}}}}, Options) ->
+getopts(_, #sslsocket{pid = {dtls, #config{dtls_handler = {ListenPid, _}}}}, Options) ->
SplitOpts = tls_socket:split_options(Options),
- dtls_udp_listener:get_sock_opts(ListenPid, SplitOpts);
+ dtls_packet_demux:get_sock_opts(ListenPid, SplitOpts);
getopts(gen_udp, #sslsocket{pid = {Socket, #config{emulated = EmOpts}}}, Options) ->
{SockOptNames, EmulatedOptNames} = tls_socket:split_options(Options),
EmulatedOpts = get_emulated_opts(EmOpts, EmulatedOptNames),
@@ -112,7 +114,7 @@ getstat(gen_udp, {_,Socket}, Options) ->
inet:getstat(Socket, Options);
getstat(Transport, Socket, Options) ->
Transport:getstat(Socket, Options).
-peername(udp, _) ->
+peername(_, undefined) ->
{error, enotconn};
peername(gen_udp, {_, {Client, _Socket}}) ->
{ok, Client};
diff --git a/lib/ssl/src/dtls_v1.erl b/lib/ssl/src/dtls_v1.erl
index 0f6344b6f7..df687f579b 100644
--- a/lib/ssl/src/dtls_v1.erl
+++ b/lib/ssl/src/dtls_v1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/src/inet_tls_dist.erl b/lib/ssl/src/inet_tls_dist.erl
index 3e9828a2fe..1194f4fc72 100644
--- a/lib/ssl/src/inet_tls_dist.erl
+++ b/lib/ssl/src/inet_tls_dist.erl
@@ -31,7 +31,7 @@
-export([nodelay/0]).
--export([verify_client/3, verify_server/3, cert_nodes/1]).
+-export([verify_client/3, cert_nodes/1]).
-export([dbg/0]). % Debug
@@ -41,6 +41,7 @@
-include_lib("public_key/include/public_key.hrl").
-include("ssl_api.hrl").
+-include_lib("kernel/include/logger.hrl").
%% -------------------------------------------------------------------------
@@ -226,7 +227,7 @@ accept_loop(Driver, Listen, Kernel) ->
true ->
accept_loop(Driver, Listen, Kernel, Socket);
{false,IP} ->
- error_logger:error_msg(
+ ?LOG_ERROR(
"** Connection attempt from "
"disallowed IP ~w ** ~n", [IP]),
?shutdown2(no_node, trace({disallowed, IP}))
@@ -236,12 +237,10 @@ accept_loop(Driver, Listen, Kernel) ->
end.
accept_loop(Driver, Listen, Kernel, Socket) ->
- {Opts,CertNodesFun} =
- setup_verify_client(
- Driver, Socket, get_ssl_options(server)),
+ Opts = setup_verify_client(Socket, get_ssl_options(server)),
wait_for_code_server(),
case
- ssl:ssl_accept(
+ ssl:handshake(
Socket,
trace([{active, false},{packet, 4}|Opts]),
net_kernel:connecttime())
@@ -255,7 +254,7 @@ accept_loop(Driver, Listen, Kernel, Socket) ->
{Kernel, controller, Pid} ->
ok = ssl:controlling_process(SslSocket, Pid),
trace(
- Pid ! {self(), controller, CertNodesFun});
+ Pid ! {self(), controller});
{Kernel, unsupported_protocol} ->
exit(trace(unsupported_protocol))
end,
@@ -263,7 +262,7 @@ accept_loop(Driver, Listen, Kernel, Socket) ->
{error, {options, _}} = Error ->
%% Bad options: that's probably our fault.
%% Let's log that.
- error_logger:error_msg(
+ ?LOG_ERROR(
"Cannot accept TLS distribution connection: ~s~n",
[ssl:format_error(Error)]),
gen_tcp:close(Socket),
@@ -278,48 +277,59 @@ accept_loop(Driver, Listen, Kernel, Socket) ->
%% as a configuration marker that verify_client/3 shall be used.
%%
%% Replace the State in the first occurence of
-%% {verify_fun,{fun ?MODULE:verify_client/3,State}} and remove the rest.
+%% {verify_fun,{fun ?MODULE:verify_client/3,State}}
+%% and remove the rest.
%% The inserted state is not accesible from a configuration file
%% since it is dynamic and connection dependent.
%%
-setup_verify_client(Driver, Socket, Opts) ->
- setup_verify_client(Driver, Socket, Opts, undefined, []).
+setup_verify_client(Socket, Opts) ->
+ setup_verify_client(Socket, Opts, true, []).
%%
-setup_verify_client(_Driver, _Socket, [], CertNodesFun, OptsR) ->
- {lists:reverse(OptsR),CertNodesFun};
-setup_verify_client(Driver, Socket, [Opt|Opts], CertNodesFun, OptsR) ->
+setup_verify_client(_Socket, [], _, OptsR) ->
+ lists:reverse(OptsR);
+setup_verify_client(Socket, [Opt|Opts], First, OptsR) ->
case Opt of
- {verify_fun,{Fun,NewCertNodesFun}} ->
+ {verify_fun,{Fun,_}} ->
case Fun =:= fun ?MODULE:verify_client/3 of
- true when is_function(NewCertNodesFun, 1) ->
+ true ->
if
- CertNodesFun =:= undefined ->
+ First ->
case inet:peername(Socket) of
{ok,{PeerIP,_Port}} ->
+ {ok,Allowed} = net_kernel:allowed(),
+ AllowedHosts = allowed_hosts(Allowed),
setup_verify_client(
- Driver, Socket, Opts, NewCertNodesFun,
+ Socket, Opts, false,
[{verify_fun,
- {Fun,
- {NewCertNodesFun,Driver,PeerIP}}}
+ {Fun, {AllowedHosts,PeerIP}}}
|OptsR]);
{error,Reason} ->
exit(trace({no_peername,Reason}))
end;
true ->
setup_verify_client(
- Driver, Socket, Opts, CertNodesFun, OptsR)
+ Socket, Opts, First, OptsR)
end;
- true ->
- exit(
- trace(
- {verify_client_bad_argument,CertNodesFun}));
false ->
setup_verify_client(
- Driver, Socket, Opts, CertNodesFun, [Opt|OptsR])
+ Socket, Opts, First, [Opt|OptsR])
end;
_ ->
- setup_verify_client(
- Driver, Socket, Opts, CertNodesFun, [Opt|OptsR])
+ setup_verify_client(Socket, Opts, First, [Opt|OptsR])
+ end.
+
+allowed_hosts(Allowed) ->
+ lists:usort(allowed_node_hosts(Allowed)).
+%%
+allowed_node_hosts([]) -> [];
+allowed_node_hosts([Node|Allowed]) ->
+ case dist_util:split_node(Node) of
+ {node,_,Host} ->
+ [Host|allowed_node_hosts(Allowed)];
+ {host,Host} ->
+ [Host|allowed_node_hosts(Allowed)];
+ _ ->
+ allowed_node_hosts(Allowed)
end.
%% Same as verify_peer but check cert host names for
@@ -330,48 +340,19 @@ verify_client(_, {extension,_}, S) ->
{unknown,S};
verify_client(_, valid, S) ->
{valid,S};
-verify_client(PeerCert, valid_peer, {CertNodesFun,Driver,PeerIP} = S) ->
- %%
- %% Parse out all node names from the peer's certificate
- %%
- case CertNodesFun(PeerCert) of
- undefined ->
- %% Certificate allows all nodes
+verify_client(_, valid_peer, {[],_} = S) ->
+ %% Allow all hosts
+ {valid,S};
+verify_client(PeerCert, valid_peer, {AllowedHosts,PeerIP} = S) ->
+ case
+ public_key:pkix_verify_hostname(
+ PeerCert,
+ [{ip,PeerIP}|[{dns_id,Host} || Host <- AllowedHosts]])
+ of
+ true ->
{valid,S};
- [] ->
- %% Certificate allows no nodes
- {fail,cert_missing_node_name};
- CertNodes ->
- %% Check if the IP address of one of the nodes
- %% in the peer certificate has the peer's IP address
- case filter_nodes_by_ip(CertNodes, Driver, PeerIP) of
- [] ->
- {fail,cert_no_host_with_peer_ip};
- _ ->
- {valid,S}
- end
- end.
-
-%% Filter out the nodes that has got the given IP address
-%%
-filter_nodes_by_ip(Nodes, Driver, IP) ->
- [Node ||
- Node <- Nodes,
- case dist_util:split_node(Node) of
- {node,_,Host} ->
- filter_host_by_ip(Host, Driver, IP);
- {host,Host} ->
- filter_host_by_ip(Host, Driver, IP);
- {name,_Name} ->
- true
- end].
-
-filter_host_by_ip(Host, Driver, IP) ->
- case Driver:getaddr(Host) of
- {ok,IP} ->
- true;
- _ ->
- false
+ false ->
+ {fail,cert_no_hostname_nor_ip_match}
end.
@@ -417,19 +398,18 @@ gen_accept_connection(
spawn_opt(
fun() ->
do_accept(
- Driver, Kernel, AcceptPid, DistCtrl,
- MyNode, Allowed, SetupTime)
+ Driver, AcceptPid, DistCtrl,
+ MyNode, Allowed, SetupTime, Kernel)
end,
[link, {priority, max}])).
-do_accept(Driver, Kernel, AcceptPid, DistCtrl, MyNode, Allowed, SetupTime) ->
+do_accept(
+ _Driver, AcceptPid, DistCtrl, MyNode, Allowed, SetupTime, Kernel) ->
SslSocket = ssl_connection:get_sslsocket(DistCtrl),
receive
- {AcceptPid, controller, CertNodesFun} ->
+ {AcceptPid, controller} ->
Timer = dist_util:start_timer(SetupTime),
- NewAllowed =
- allowed_nodes(
- Driver, CertNodesFun, SslSocket, Allowed),
+ NewAllowed = allowed_nodes(SslSocket, Allowed),
HSData0 = hs_data_common(SslSocket),
HSData =
HSData0#hs_data{
@@ -443,65 +423,67 @@ do_accept(Driver, Kernel, AcceptPid, DistCtrl, MyNode, Allowed, SetupTime) ->
dist_util:handshake_other_started(trace(HSData))
end.
-%% Return a list of allowed nodes according to
-%% the given Allowed list that matches the peer certificate
-%%
-allowed_nodes(_Driver, undefined, _SslSocket, Allowed) ->
- Allowed;
-allowed_nodes(Driver, CertNodesFun, SslSocket, Allowed) ->
+allowed_nodes(_SslSocket, []) ->
+ %% Allow all
+ [];
+allowed_nodes(SslSocket, Allowed) ->
case ssl:peercert(SslSocket) of
{ok,PeerCertDER} ->
case ssl:peername(SslSocket) of
{ok,{PeerIP,_Port}} ->
- PeerCert = public_key:pkix_decode_cert(PeerCertDER, otp),
- %%
- %% Parse out all node names from the peer's certificate
- %%
- case CertNodesFun(PeerCert) of
- undefined ->
- %% Certificate allows all nodes
- Allowed;
+ PeerCert =
+ public_key:pkix_decode_cert(PeerCertDER, otp),
+ case
+ allowed_nodes(
+ PeerCert, allowed_hosts(Allowed), PeerIP)
+ of
[] ->
- %% Certificate allows no nodes
- ?shutdown(cert_missing_node_name);
- CertNodes ->
- %% Filter out all nodes in the
- %% allowed list that is in peer
- %% certificate and that has got
- %% the same IP address as the peer
- allowed(
- filter_nodes_by_ip(
- CertNodes, Driver, PeerIP),
- Allowed)
+ ?LOG_ERROR(
+ "** Connection attempt from "
+ "disallowed node(s) ~p ** ~n", [PeerIP]),
+ ?shutdown2(
+ PeerIP, trace({is_allowed, not_allowed}));
+ AllowedNodes ->
+ AllowedNodes
end;
Error1 ->
?shutdown2(no_peer_ip, trace(Error1))
end;
+ {error,no_peercert} ->
+ Allowed;
Error2 ->
?shutdown2(no_peer_cert, trace(Error2))
end.
-allowed(CertNodes, []) ->
- %% Empty allowed list means all allowed
- %% -> allow only certificate nodes
- CertNodes;
-allowed(CertNodes, Allowed) ->
- %% Find the intersection of the allowed list and certificate nodes
- case
- [CertNode ||
- CertNode <- CertNodes,
- dist_util:is_allowed(CertNode, Allowed)]
- of
- [] ->
- error_logger:error_msg(
- "** Connection attempt from "
- "disallowed node(s) ~p ** ~n", [CertNodes]),
- ?shutdown2(CertNodes, trace({is_allowed, not_allowed}));
- NewAllowed ->
- NewAllowed
+allowed_nodes(PeerCert, [], PeerIP) ->
+ case public_key:pkix_verify_hostname(PeerCert, [{ip,PeerIP}]) of
+ true ->
+ Host = inet:ntoa(PeerIP),
+ true = is_list(Host),
+ [Host];
+ false ->
+ []
+ end;
+allowed_nodes(PeerCert, [Node|Allowed], PeerIP) ->
+ case dist_util:split_node(Node) of
+ {node,_,Host} ->
+ allowed_nodes(PeerCert, Allowed, PeerIP, Node, Host);
+ {host,Host} ->
+ allowed_nodes(PeerCert, Allowed, PeerIP, Node, Host);
+ _ ->
+ allowed_nodes(PeerCert, Allowed, PeerIP)
+ end.
+
+allowed_nodes(PeerCert, Allowed, PeerIP, Node, Host) ->
+ case public_key:pkix_verify_hostname(PeerCert, [{dns_id,Host}]) of
+ true ->
+ [Node|allowed_nodes(PeerCert, Allowed, PeerIP)];
+ false ->
+ allowed_nodes(PeerCert, Allowed, PeerIP)
end.
+
setup(Node, Type, MyNode, LongOrShortNames, SetupTime) ->
gen_setup(inet_tcp, Node, Type, MyNode, LongOrShortNames, SetupTime).
@@ -518,51 +500,16 @@ gen_setup(Driver, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
{Name, Address} = split_node(Driver, Node, LongOrShortNames),
- case Driver:getaddr(Address) of
+ ErlEpmd = net_kernel:epmd_module(),
+ {ARMod, ARFun} = get_address_resolver(ErlEpmd, Driver),
+ Timer = trace(dist_util:start_timer(SetupTime)),
+ case ARMod:ARFun(Name,Address,Driver:family()) of
+ {ok, Ip, TcpPort, Version} ->
+ do_setup_connect(Driver, Kernel, Node, Address, Ip, TcpPort, Version, Type, MyNode, Timer);
{ok, Ip} ->
- Timer = trace(dist_util:start_timer(SetupTime)),
- ErlEpmd = net_kernel:epmd_module(),
case ErlEpmd:port_please(Name, Ip) of
{port, TcpPort, Version} ->
- Opts =
- trace(
- connect_options(
- %%
- %% Use verify_server/3 to verify that
- %% the server's certificate is for Node
- %%
- setup_verify_server(
- get_ssl_options(client), Node))),
- dist_util:reset_timer(Timer),
- case ssl:connect(
- Address, TcpPort,
- [binary, {active, false}, {packet, 4},
- Driver:family(), nodelay()] ++ Opts,
- net_kernel:connecttime()) of
- {ok, #sslsocket{pid = DistCtrl} = SslSocket} ->
- _ = monitor_pid(DistCtrl),
- ok = ssl:controlling_process(SslSocket, self()),
- HSData0 = hs_data_common(SslSocket),
- HSData =
- HSData0#hs_data{
- kernel_pid = Kernel,
- other_node = Node,
- this_node = MyNode,
- socket = DistCtrl,
- timer = Timer,
- this_flags = 0,
- other_version = Version,
- request_type = Type},
- link(DistCtrl),
- dist_util:handshake_we_started(trace(HSData));
- Other ->
- %% Other Node may have closed since
- %% port_please !
- ?shutdown2(
- Node,
- trace(
- {ssl_connect_failed, Ip, TcpPort, Other}))
- end;
+ do_setup_connect(Driver, Kernel, Node, Address, Ip, TcpPort, Version, Type, MyNode, Timer);
Other ->
?shutdown2(
Node,
@@ -575,74 +522,56 @@ do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
trace({getaddr_failed, Driver, Address, Other}))
end.
+do_setup_connect(Driver, Kernel, Node, Address, Ip, TcpPort, Version, Type, MyNode, Timer) ->
+ Opts = trace(connect_options(get_ssl_options(client))),
+ dist_util:reset_timer(Timer),
+ case ssl:connect(
+ Address, TcpPort,
+ [binary, {active, false}, {packet, 4},
+ Driver:family(), nodelay()] ++ Opts,
+ net_kernel:connecttime()) of
+ {ok, #sslsocket{pid = DistCtrl} = SslSocket} ->
+ _ = monitor_pid(DistCtrl),
+ ok = ssl:controlling_process(SslSocket, self()),
+ HSData0 = hs_data_common(SslSocket),
+ HSData =
+ HSData0#hs_data{
+ kernel_pid = Kernel,
+ other_node = Node,
+ this_node = MyNode,
+ socket = DistCtrl,
+ timer = Timer,
+ this_flags = 0,
+ other_version = Version,
+ request_type = Type},
+ link(DistCtrl),
+ dist_util:handshake_we_started(trace(HSData));
+ Other ->
+ %% Other Node may have closed since
+ %% port_please !
+ ?shutdown2(
+ Node,
+ trace(
+ {ssl_connect_failed, Ip, TcpPort, Other}))
+ end.
+
close(Socket) ->
gen_close(inet, Socket).
gen_close(Driver, Socket) ->
trace(Driver:close(Socket)).
-%% {verify_fun,{fun ?MODULE:verify_server/3,_}} is used
-%% as a configuration marker that verify_server/3 shall be used.
-%%
-%% Replace the State in the first occurence of
-%% {verify_fun,{fun ?MODULE:verify_server/3,State}} and remove the rest.
-%% The inserted state is not accesible from a configuration file
-%% since it is dynamic and connection dependent.
-%%
-setup_verify_server(Opts, Node) ->
- setup_verify_server(Opts, Node, true).
-%%
-setup_verify_server([], _Node, _) ->
- [];
-setup_verify_server([Opt|Opts], Node, Once) ->
- case Opt of
- {verify_fun,{Fun,CertNodesFun}} ->
- case Fun =:= fun ?MODULE:verify_server/3 of
- true when not is_function(CertNodesFun, 1) ->
- ?shutdown2(
- Node,
- {verify_server_bad_argument,CertNodesFun});
- true when Once ->
- [{verify_fun,{Fun,{CertNodesFun,Node}}}
- |setup_verify_server(Opts, Node, false)];
- true ->
- setup_verify_server(Opts, Node, Once);
- false ->
- [Opt|setup_verify_server(Opts, Node, Once)]
- end;
- _ ->
- [Opt|setup_verify_server(Opts, Node, Once)]
- end.
-verify_server(_, {bad_cert,_} = Reason, _) ->
- {fail,Reason};
-verify_server(_, {extension,_}, S) ->
- {unknown,S};
-verify_server(_, valid, S) ->
- {valid,S};
-verify_server(PeerCert, valid_peer, {CertNodesFun,Node} = S) ->
- %%
- %% Parse out all node names from the peer's certificate
- %%
- case CertNodesFun(PeerCert) of
- undefined ->
- %% Certificate allows all nodes
- {valid,S};
- [] ->
- %% Certificate allows no nodes
- {fail,cert_missing_node_name};
- CertNodes ->
- %% Check that the node we are connecting to
- %% is in the peer certificate
- case dist_util:is_allowed(Node, CertNodes) of
- true ->
- {valid,S};
- false ->
- {fail,wrong_nodes_in_cert}
- end
+%% ------------------------------------------------------------
+%% Determine if EPMD module supports address resolving. Default
+%% is to use inet_tcp:getaddr/2.
+%% ------------------------------------------------------------
+get_address_resolver(EpmdModule, Driver) ->
+ case erlang:function_exported(EpmdModule, address_please, 3) of
+ true -> {EpmdModule, address_please};
+ _ -> {Driver, getaddr}
end.
-
%% ------------------------------------------------------------
%% Do only accept new connection attempts from nodes at our
%% own LAN, if the check_ip environment parameter is true.
@@ -763,12 +692,12 @@ split_node(Driver, Node, LongOrShortNames) ->
{node, Name, Host} ->
check_node(Driver, Node, Name, Host, LongOrShortNames);
{host, _} ->
- error_logger:error_msg(
+ ?LOG_ERROR(
"** Nodename ~p illegal, no '@' character **~n",
[Node]),
?shutdown2(Node, trace({illegal_node_n@me, Node}));
_ ->
- error_logger:error_msg(
+ ?LOG_ERROR(
"** Nodename ~p illegal **~n", [Node]),
?shutdown2(Node, trace({illegal_node_name, Node}))
end.
@@ -780,7 +709,7 @@ check_node(Driver, Node, Name, Host, LongOrShortNames) ->
{ok, _} ->
{Name, Host};
_ ->
- error_logger:error_msg(
+ ?LOG_ERROR(
"** System running to use "
"fully qualified hostnames **~n"
"** Hostname ~s is illegal **~n",
@@ -788,7 +717,7 @@ check_node(Driver, Node, Name, Host, LongOrShortNames) ->
?shutdown2(Node, trace({not_longnames, Host}))
end;
[_,_|_] when LongOrShortNames =:= shortnames ->
- error_logger:error_msg(
+ ?LOG_ERROR(
"** System NOT running to use "
"fully qualified hostnames **~n"
"** Hostname ~s is illegal **~n",
@@ -918,13 +847,13 @@ monitor_pid(Pid) ->
%% MRef = erlang:monitor(process, Pid),
%% receive
%% {'DOWN', MRef, _, _, normal} ->
- %% error_logger:error_report(
- %% [dist_proc_died,
+ %% ?LOG_ERROR(
+ %% [{slogan, dist_proc_died},
%% {reason, normal},
%% {pid, Pid}]);
%% {'DOWN', MRef, _, _, Reason} ->
- %% error_logger:info_report(
- %% [dist_proc_died,
+ %% ?LOG_NOTICE(
+ %% [{slogan, dist_proc_died},
%% {reason, Reason},
%% {pid, Pid}])
%% end
diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src
index 2aecb6836e..9679ea4687 100644
--- a/lib/ssl/src/ssl.app.src
+++ b/lib/ssl/src/ssl.app.src
@@ -17,8 +17,8 @@
dtls_socket,
dtls_v1,
dtls_connection_sup,
- dtls_udp_listener,
- dtls_udp_sup,
+ dtls_packet_demux,
+ dtls_listener_sup,
%% API
ssl, %% Main API
tls, %% TLS specific
@@ -51,6 +51,8 @@
ssl_crl_cache,
ssl_crl_cache_api,
ssl_crl_hash_dir,
+ %% Logging
+ ssl_logger,
%% App structure
ssl_app,
ssl_sup,
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 5b6d92ebf4..09953908ce 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,40 +23,44 @@
%%% Purpose : Main API module for SSL see also tls.erl and dtls.erl
-module(ssl).
--include("ssl_internal.hrl").
+
-include_lib("public_key/include/public_key.hrl").
+-include("ssl_internal.hrl").
+-include("ssl_api.hrl").
+-include("ssl_internal.hrl").
+-include("ssl_record.hrl").
+-include("ssl_cipher.hrl").
+-include("ssl_handshake.hrl").
+-include("ssl_srp.hrl").
+
%% Application handling
-export([start/0, start/1, stop/0, clear_pem_cache/0]).
%% Socket handling
-export([connect/3, connect/2, connect/4,
listen/2, transport_accept/1, transport_accept/2,
- handshake/1, handshake/2, handshake/3,
+ handshake/1, handshake/2, handshake/3, handshake_continue/2,
handshake_continue/3, handshake_cancel/1,
ssl_accept/1, ssl_accept/2, ssl_accept/3,
controlling_process/2, peername/1, peercert/1, sockname/1,
close/1, close/2, shutdown/2, recv/2, recv/3, send/2,
getopts/2, setopts/2, getstat/1, getstat/2
]).
-%% SSL/TLS protocol handling
+%% SSL/TLS protocol handling
-export([cipher_suites/0, cipher_suites/1, cipher_suites/2, filter_cipher_suites/2,
prepend_cipher_suites/2, append_cipher_suites/2,
eccs/0, eccs/1, versions/0,
format_error/1, renegotiate/1, prf/5, negotiated_protocol/1,
connection_information/1, connection_information/2]).
%% Misc
--export([handle_options/2, tls_version/1, new_ssl_options/3]).
-
--include("ssl_api.hrl").
--include("ssl_internal.hrl").
--include("ssl_record.hrl").
--include("ssl_cipher.hrl").
--include("ssl_handshake.hrl").
--include("ssl_srp.hrl").
+-export([handle_options/2, tls_version/1, new_ssl_options/3, suite_to_str/1,
+ set_log_level/1]).
--include_lib("public_key/include/public_key.hrl").
+-deprecated({ssl_accept, 1, eventually}).
+-deprecated({ssl_accept, 2, eventually}).
+-deprecated({ssl_accept, 3, eventually}).
%%--------------------------------------------------------------------
-spec start() -> ok | {error, reason()}.
@@ -84,6 +88,7 @@ stop() ->
application:stop(ssl).
%%--------------------------------------------------------------------
+
-spec connect(host() | port(), [connect_option()]) -> {ok, #sslsocket{}} |
{error, reason()}.
-spec connect(host() | port(), [connect_option()] | inet:port_number(),
@@ -206,6 +211,8 @@ ssl_accept(Socket, SslOptions, Timeout) ->
%% Description: Performs accept on an ssl listen socket. e.i. performs
%% ssl handshake.
%%--------------------------------------------------------------------
+
+%% Performs the SSL/TLS/DTLS server-side handshake.
handshake(ListenSocket) ->
handshake(ListenSocket, infinity).
@@ -213,6 +220,12 @@ handshake(#sslsocket{} = Socket, Timeout) when (is_integer(Timeout) andalso Tim
(Timeout == infinity) ->
ssl_connection:handshake(Socket, Timeout);
+%% If Socket is a ordinary socket(): upgrades a gen_tcp, or equivalent, socket to
+%% an SSL socket, that is, performs the SSL/TLS server-side handshake and returns
+%% the SSL socket.
+%%
+%% If Socket is an sslsocket(): provides extra SSL/TLS/DTLS options to those
+%% specified in ssl:listen/2 and then performs the SSL/TLS/DTLS handshake.
handshake(ListenSocket, SslOptions) when is_port(ListenSocket) ->
handshake(ListenSocket, SslOptions, infinity).
@@ -231,7 +244,7 @@ handshake(#sslsocket{fd = {_, _, _, Tracker}} = Socket, SslOpts, Timeout) when
handshake(#sslsocket{pid = Pid, fd = {_, _, _}} = Socket, SslOpts, Timeout) when
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)->
try
- {ok, EmOpts, _} = dtls_udp_listener:get_all_opts(Pid),
+ {ok, EmOpts, _} = dtls_packet_demux:get_all_opts(Pid),
ssl_connection:handshake(Socket, {SslOpts,
tls_socket:emulated_socket_options(EmOpts, #socket_options{})}, Timeout)
catch
@@ -256,6 +269,16 @@ handshake(Socket, SslOptions, Timeout) when is_port(Socket),
Error = {error, _Reason} -> Error
end.
+
+%%--------------------------------------------------------------------
+-spec handshake_continue(#sslsocket{}, [ssl_option()]) ->
+ {ok, #sslsocket{}} | {error, reason()}.
+%%
+%%
+%% Description: Continues the handshke possible with newly supplied options.
+%%--------------------------------------------------------------------
+handshake_continue(Socket, SSLOptions) ->
+ handshake_continue(Socket, SSLOptions, infinity).
%%--------------------------------------------------------------------
-spec handshake_continue(#sslsocket{}, [ssl_option()], timeout()) ->
{ok, #sslsocket{}} | {error, reason()}.
@@ -280,8 +303,8 @@ handshake_cancel(Socket) ->
%%--------------------------------------------------------------------
close(#sslsocket{pid = Pid}) when is_pid(Pid) ->
ssl_connection:close(Pid, {close, ?DEFAULT_TIMEOUT});
-close(#sslsocket{pid = {udp, #config{udp_handler = {Pid, _}}}}) ->
- dtls_udp_listener:close(Pid);
+close(#sslsocket{pid = {dtls, #config{dtls_handler = {Pid, _}}}}) ->
+ dtls_packet_demux:close(Pid);
close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _}}}}) ->
Transport:close(ListenSocket).
@@ -308,10 +331,10 @@ close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _}
%%--------------------------------------------------------------------
send(#sslsocket{pid = Pid}, Data) when is_pid(Pid) ->
ssl_connection:send(Pid, Data);
-send(#sslsocket{pid = {_, #config{transport_info={gen_udp, _, _, _}}}}, _) ->
+send(#sslsocket{pid = {_, #config{transport_info={_, udp, _, _}}}}, _) ->
{error,enotconn}; %% Emulate connection behaviour
-send(#sslsocket{pid = {udp,_}}, _) ->
- {error,enotconn};
+send(#sslsocket{pid = {dtls,_}}, _) ->
+ {error,enotconn}; %% Emulate connection behaviour
send(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport, _, _, _}}}}, Data) ->
Transport:send(ListenSocket, Data). %% {error,enotconn}
@@ -326,7 +349,7 @@ recv(Socket, Length) ->
recv(#sslsocket{pid = Pid}, Length, Timeout) when is_pid(Pid),
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)->
ssl_connection:recv(Pid, Length, Timeout);
-recv(#sslsocket{pid = {udp,_}}, _, _) ->
+recv(#sslsocket{pid = {dtls,_}}, _, _) ->
{error,enotconn};
recv(#sslsocket{pid = {Listen,
#config{transport_info = {Transport, _, _, _}}}}, _,_) when is_port(Listen)->
@@ -340,7 +363,7 @@ recv(#sslsocket{pid = {Listen,
%%--------------------------------------------------------------------
controlling_process(#sslsocket{pid = Pid}, NewOwner) when is_pid(Pid), is_pid(NewOwner) ->
ssl_connection:new_user(Pid, NewOwner);
-controlling_process(#sslsocket{pid = {udp, _}},
+controlling_process(#sslsocket{pid = {dtls, _}},
NewOwner) when is_pid(NewOwner) ->
ok; %% Meaningless but let it be allowed to conform with TLS
controlling_process(#sslsocket{pid = {Listen,
@@ -365,7 +388,7 @@ connection_information(#sslsocket{pid = Pid}) when is_pid(Pid) ->
end;
connection_information(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
{error, enotconn};
-connection_information(#sslsocket{pid = {udp,_}}) ->
+connection_information(#sslsocket{pid = {dtls,_}}) ->
{error,enotconn}.
%%--------------------------------------------------------------------
@@ -391,13 +414,11 @@ peername(#sslsocket{pid = Pid, fd = {Transport, Socket, _}}) when is_pid(Pid)->
dtls_socket:peername(Transport, Socket);
peername(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}) when is_pid(Pid)->
tls_socket:peername(Transport, Socket);
-peername(#sslsocket{pid = {udp = Transport, #config{udp_handler = {_Pid, _}}}}) ->
- dtls_socket:peername(Transport, undefined);
-peername(#sslsocket{pid = Pid, fd = {gen_udp= Transport, Socket, _, _}}) when is_pid(Pid) ->
- dtls_socket:peername(Transport, Socket);
+peername(#sslsocket{pid = {dtls, #config{dtls_handler = {_Pid, _}}}}) ->
+ dtls_socket:peername(dtls, undefined);
peername(#sslsocket{pid = {ListenSocket, #config{transport_info = {Transport,_,_,_}}}}) ->
tls_socket:peername(Transport, ListenSocket); %% Will return {error, enotconn}
-peername(#sslsocket{pid = {udp,_}}) ->
+peername(#sslsocket{pid = {dtls,_}}) ->
{error,enotconn}.
%%--------------------------------------------------------------------
@@ -412,7 +433,7 @@ peercert(#sslsocket{pid = Pid}) when is_pid(Pid) ->
Result ->
Result
end;
-peercert(#sslsocket{pid = {udp, _}}) ->
+peercert(#sslsocket{pid = {dtls, _}}) ->
{error, enotconn};
peercert(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
{error, enotconn}.
@@ -562,7 +583,7 @@ eccs_filter_supported(Curves) ->
%%--------------------------------------------------------------------
getopts(#sslsocket{pid = Pid}, OptionTags) when is_pid(Pid), is_list(OptionTags) ->
ssl_connection:get_opts(Pid, OptionTags);
-getopts(#sslsocket{pid = {udp, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, OptionTags) when is_list(OptionTags) ->
+getopts(#sslsocket{pid = {dtls, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, OptionTags) when is_list(OptionTags) ->
try dtls_socket:getopts(Transport, ListenSocket, OptionTags) of
{ok, _} = Result ->
Result;
@@ -600,7 +621,7 @@ setopts(#sslsocket{pid = Pid}, Options0) when is_pid(Pid), is_list(Options0) ->
_:_ ->
{error, {options, {not_a_proplist, Options0}}}
end;
-setopts(#sslsocket{pid = {udp, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, Options) when is_list(Options) ->
+setopts(#sslsocket{pid = {dtls, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, Options) when is_list(Options) ->
try dtls_socket:setopts(Transport, ListenSocket, Options) of
ok ->
ok;
@@ -657,7 +678,7 @@ getstat(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}, Options) when is_
shutdown(#sslsocket{pid = {Listen, #config{transport_info = {Transport,_, _, _}}}},
How) when is_port(Listen) ->
Transport:shutdown(Listen, How);
-shutdown(#sslsocket{pid = {udp,_}},_) ->
+shutdown(#sslsocket{pid = {dtls,_}},_) ->
{error, enotconn};
shutdown(#sslsocket{pid = Pid}, How) ->
ssl_connection:shutdown(Pid, How).
@@ -669,8 +690,8 @@ shutdown(#sslsocket{pid = Pid}, How) ->
%%--------------------------------------------------------------------
sockname(#sslsocket{pid = {Listen, #config{transport_info = {Transport, _, _, _}}}}) when is_port(Listen) ->
tls_socket:sockname(Transport, Listen);
-sockname(#sslsocket{pid = {udp, #config{udp_handler = {Pid, _}}}}) ->
- dtls_udp_listener:sockname(Pid);
+sockname(#sslsocket{pid = {dtls, #config{dtls_handler = {Pid, _}}}}) ->
+ dtls_packet_demux:sockname(Pid);
sockname(#sslsocket{pid = Pid, fd = {Transport, Socket, _}}) when is_pid(Pid) ->
dtls_socket:sockname(Transport, Socket);
sockname(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}) when is_pid(Pid) ->
@@ -704,7 +725,7 @@ versions() ->
%%--------------------------------------------------------------------
renegotiate(#sslsocket{pid = Pid}) when is_pid(Pid) ->
ssl_connection:renegotiation(Pid);
-renegotiate(#sslsocket{pid = {udp,_}}) ->
+renegotiate(#sslsocket{pid = {dtls,_}}) ->
{error, enotconn};
renegotiate(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
{error, enotconn}.
@@ -719,7 +740,7 @@ renegotiate(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
prf(#sslsocket{pid = Pid},
Secret, Label, Seed, WantedLength) when is_pid(Pid) ->
ssl_connection:prf(Pid, Secret, Label, Seed, WantedLength);
-prf(#sslsocket{pid = {udp,_}}, _,_,_,_) ->
+prf(#sslsocket{pid = {dtls,_}}, _,_,_,_) ->
{error, enotconn};
prf(#sslsocket{pid = {Listen,_}}, _,_,_,_) when is_port(Listen) ->
{error, enotconn}.
@@ -771,6 +792,42 @@ tls_version({3, _} = Version) ->
tls_version({254, _} = Version) ->
dtls_v1:corresponding_tls_version(Version).
+
+%%--------------------------------------------------------------------
+-spec suite_to_str(ssl_cipher:erl_cipher_suite()) -> string().
+%%
+%% Description: Return the string representation of a cipher suite.
+%%--------------------------------------------------------------------
+suite_to_str(Cipher) ->
+ ssl_cipher:suite_to_str(Cipher).
+
+
+%%--------------------------------------------------------------------
+-spec set_log_level(atom()) -> ok | {error, term()}.
+%%
+%% Description: Set log level for the SSL application
+%%--------------------------------------------------------------------
+set_log_level(Level) ->
+ case application:get_all_key(ssl) of
+ {ok, PropList} ->
+ Modules = proplists:get_value(modules, PropList),
+ set_module_level(Modules, Level);
+ undefined ->
+ {error, ssl_not_started}
+ end.
+
+set_module_level(Modules, Level) ->
+ Fun = fun (Module) ->
+ ok = logger:set_module_level(Module, Level)
+ end,
+ try lists:map(Fun, Modules) of
+ _ ->
+ ok
+ catch
+ error:{badmatch, Error} ->
+ Error
+ end.
+
%%%--------------------------------------------------------------
%%% Internal functions
%%%--------------------------------------------------------------------
@@ -792,8 +849,8 @@ supported_suites(anonymous, Version) ->
do_listen(Port, #config{transport_info = {Transport, _, _, _}} = Config, tls_connection) ->
tls_socket:listen(Transport, Port, Config);
-do_listen(Port, #config{transport_info = {Transport, _, _, _}} = Config, dtls_connection) ->
- dtls_socket:listen(Transport, Port, Config).
+do_listen(Port, Config, dtls_connection) ->
+ dtls_socket:listen(Port, Config).
%% Handle extra ssl options given to ssl_accept
-spec handle_options([any()], #ssl_options{}) -> #ssl_options{}
@@ -830,9 +887,10 @@ handle_options(Opts0, #ssl_options{protocol = Protocol, cacerts = CaCerts0,
[] ->
new_ssl_options(SslOpts1, NewVerifyOpts, RecordCB);
Value ->
- Versions = [RecordCB:protocol_version(Vsn) || Vsn <- Value],
+ Versions0 = [RecordCB:protocol_version(Vsn) || Vsn <- Value],
+ Versions1 = lists:sort(fun RecordCB:is_higher/2, Versions0),
new_ssl_options(proplists:delete(versions, SslOpts1),
- NewVerifyOpts#ssl_options{versions = Versions}, record_cb(Protocol))
+ NewVerifyOpts#ssl_options{versions = Versions1}, record_cb(Protocol))
end;
%% Handle all options in listen and connect
@@ -855,7 +913,8 @@ handle_options(Opts0, Role, Host) ->
[] ->
RecordCb:supported_protocol_versions();
Vsns ->
- [RecordCb:protocol_version(Vsn) || Vsn <- Vsns]
+ Versions0 = [RecordCb:protocol_version(Vsn) || Vsn <- Vsns],
+ lists:sort(fun RecordCb:is_higher/2, Versions0)
end,
Protocol = handle_option(protocol, Opts, tls),
@@ -867,7 +926,7 @@ handle_options(Opts0, Role, Host) ->
ok
end,
- SSLOptions = #ssl_options{
+ SSLOptions0 = #ssl_options{
versions = Versions,
verify = validate_option(verify, Verify),
verify_fun = VerifyFun,
@@ -914,7 +973,6 @@ handle_options(Opts0, Role, Host) ->
next_protocol_selector =
make_next_protocol_selector(
handle_option(client_preferred_next_protocols, Opts, undefined)),
- log_alert = handle_option(log_alert, Opts, true),
server_name_indication = handle_option(server_name_indication, Opts,
default_option_role(client,
server_name_indication_default(Host), Role)),
@@ -937,8 +995,13 @@ handle_options(Opts0, Role, Host) ->
crl_check = handle_option(crl_check, Opts, false),
crl_cache = handle_option(crl_cache, Opts, {ssl_crl_cache, {internal, []}}),
max_handshake_size = handle_option(max_handshake_size, Opts, ?DEFAULT_MAX_HANDSHAKE_SIZE),
- handshake = handle_option(handshake, Opts, full)
+ handshake = handle_option(handshake, Opts, full),
+ customize_hostname_check = handle_option(customize_hostname_check, Opts, [])
},
+ LogLevel = handle_option(log_alert, Opts, true),
+ SSLOptions = SSLOptions0#ssl_options{
+ log_level = handle_option(log_level, Opts, LogLevel)
+ },
CbInfo = proplists:get_value(cb_info, Opts, default_cb_info(Protocol)),
SslOptions = [protocol, versions, verify, verify_fun, partial_chain,
@@ -950,10 +1013,10 @@ handle_options(Opts0, Role, Host) ->
cb_info, renegotiate_at, secure_renegotiate, hibernate_after,
erl_dist, alpn_advertised_protocols, sni_hosts, sni_fun,
alpn_preferred_protocols, next_protocols_advertised,
- client_preferred_next_protocols, log_alert,
+ client_preferred_next_protocols, log_alert, log_level,
server_name_indication, honor_cipher_order, padding_check, crl_check, crl_cache,
fallback, signature_algs, eccs, honor_ecc_order, beast_mitigation,
- max_handshake_size, handshake],
+ max_handshake_size, handshake, customize_hostname_check],
SockOpts = lists:foldl(fun(Key, PropList) ->
proplists:delete(Key, PropList)
end, Opts, SslOptions),
@@ -1129,7 +1192,20 @@ validate_option(client_preferred_next_protocols, {Precedence, PreferredProtocols
Value;
validate_option(client_preferred_next_protocols, undefined) ->
undefined;
-validate_option(log_alert, Value) when is_boolean(Value) ->
+validate_option(log_alert, true) ->
+ notice;
+validate_option(log_alert, false) ->
+ warning;
+validate_option(log_level, Value) when
+ is_atom(Value) andalso
+ (Value =:= emergency orelse
+ Value =:= alert orelse
+ Value =:= critical orelse
+ Value =:= error orelse
+ Value =:= warning orelse
+ Value =:= notice orelse
+ Value =:= info orelse
+ Value =:= debug) ->
Value;
validate_option(next_protocols_advertised, Value) when is_list(Value) ->
validate_binary_list(next_protocols_advertised, Value),
@@ -1196,6 +1272,8 @@ validate_option(handshake, hello = Value) ->
Value;
validate_option(handshake, full = Value) ->
Value;
+validate_option(customize_hostname_check, Value) when is_list(Value) ->
+ Value;
validate_option(Opt, Value) ->
throw({error, {options, {Opt, Value}}}).
@@ -1235,7 +1313,8 @@ validate_binary_list(Opt, List) ->
end, List).
validate_versions([], Versions) ->
Versions;
-validate_versions([Version | Rest], Versions) when Version == 'tlsv1.2';
+validate_versions([Version | Rest], Versions) when Version == 'tlsv1.3';
+ Version == 'tlsv1.2';
Version == 'tlsv1.1';
Version == tlsv1;
Version == sslv3 ->
@@ -1248,10 +1327,11 @@ validate_versions([Ver| _], Versions) ->
tls_validate_versions([], Versions) ->
Versions;
-tls_validate_versions([Version | Rest], Versions) when Version == 'tlsv1.2';
- Version == 'tlsv1.1';
- Version == tlsv1;
- Version == sslv3 ->
+tls_validate_versions([Version | Rest], Versions) when Version == 'tlsv1.3';
+ Version == 'tlsv1.2';
+ Version == 'tlsv1.1';
+ Version == tlsv1;
+ Version == sslv3 ->
tls_validate_versions(Rest, Versions);
tls_validate_versions([Ver| _], Versions) ->
throw({error, {options, {Ver, {versions, Versions}}}}).
@@ -1502,8 +1582,10 @@ new_ssl_options([{next_protocols_advertised, Value} | Rest], #ssl_options{} = Op
new_ssl_options([{client_preferred_next_protocols, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
new_ssl_options(Rest, Opts#ssl_options{next_protocol_selector =
make_next_protocol_selector(validate_option(client_preferred_next_protocols, Value))}, RecordCB);
-new_ssl_options([{log_alert, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
- new_ssl_options(Rest, Opts#ssl_options{log_alert = validate_option(log_alert, Value)}, RecordCB);
+new_ssl_options([{log_alert, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
+ new_ssl_options(Rest, Opts#ssl_options{log_level = validate_option(log_alert, Value)}, RecordCB);
+new_ssl_options([{log_level, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
+ new_ssl_options(Rest, Opts#ssl_options{log_level = validate_option(log_level, Value)}, RecordCB);
new_ssl_options([{server_name_indication, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
new_ssl_options(Rest, Opts#ssl_options{server_name_indication = validate_option(server_name_indication, Value)}, RecordCB);
new_ssl_options([{honor_cipher_order, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl
index fc7b1e6d1c..34e9797f1f 100644
--- a/lib/ssl/src/ssl_alert.erl
+++ b/lib/ssl/src/ssl_alert.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/src/ssl_alert.hrl b/lib/ssl/src/ssl_alert.hrl
index 35670edea5..b23123905e 100644
--- a/lib/ssl/src/ssl_alert.hrl
+++ b/lib/ssl/src/ssl_alert.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/src/ssl_app.erl b/lib/ssl/src/ssl_app.erl
index 62e8765d4a..2a5047c75c 100644
--- a/lib/ssl/src/ssl_app.erl
+++ b/lib/ssl/src/ssl_app.erl
@@ -29,9 +29,26 @@
-export([start/2, stop/1]).
start(_Type, _StartArgs) ->
+ start_logger(),
ssl_sup:start_link().
stop(_State) ->
+ stop_logger(),
ok.
+%%
+%% Description: Start SSL logger
+start_logger() ->
+ Config = #{level => debug,
+ filter_default => stop,
+ formatter => {ssl_logger, #{}}},
+ Filter = {fun logger_filters:domain/2,{log,sub,[otp,ssl]}},
+ logger:add_handler(ssl_handler, logger_std_h, Config),
+ logger:add_handler_filter(ssl_handler, filter_non_ssl, Filter).
+
+%%
+%% Description: Stop SSL logger
+stop_logger() ->
+ logger:remove_handler(ssl_handler).
+
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index a3333d35e9..017d18ee2c 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017 All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018 All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -69,7 +69,7 @@ trusted_cert_and_path(CertChain, CertDbHandle, CertDbRef, PartialChainHandler) -
case SignedAndIssuerID of
{error, issuer_not_found} ->
- %% The root CA was not sent and can not be found.
+ %% The root CA was not sent and cannot be found.
handle_incomplete_chain(Path, PartialChainHandler);
{self, _} when length(Path) == 1 ->
{selfsigned_peer, Path};
@@ -138,8 +138,8 @@ validate(_, {bad_cert, _} = Reason, _) ->
{fail, Reason};
validate(_, valid, UserState) ->
{valid, UserState};
-validate(Cert, valid_peer, UserState = {client, _,_, Hostname, _, _}) when Hostname =/= disable ->
- verify_hostname(Hostname, Cert, UserState);
+validate(Cert, valid_peer, UserState = {client, _,_, {Hostname, Customize}, _, _}) when Hostname =/= disable ->
+ verify_hostname(Hostname, Customize, Cert, UserState);
validate(_, valid_peer, UserState) ->
{valid, UserState}.
@@ -333,12 +333,12 @@ new_trusteded_chain(DerCert, [_ | Rest]) ->
new_trusteded_chain(_, []) ->
unknown_ca.
-verify_hostname({fallback, Hostname}, Cert, UserState) when is_list(Hostname) ->
- case public_key:pkix_verify_hostname(Cert, [{dns_id, Hostname}]) of
+verify_hostname({fallback, Hostname}, Customize, Cert, UserState) when is_list(Hostname) ->
+ case public_key:pkix_verify_hostname(Cert, [{dns_id, Hostname}], Customize) of
true ->
{valid, UserState};
false ->
- case public_key:pkix_verify_hostname(Cert, [{ip, Hostname}]) of
+ case public_key:pkix_verify_hostname(Cert, [{ip, Hostname}], Customize) of
true ->
{valid, UserState};
false ->
@@ -346,16 +346,16 @@ verify_hostname({fallback, Hostname}, Cert, UserState) when is_list(Hostname) ->
end
end;
-verify_hostname({fallback, Hostname}, Cert, UserState) ->
- case public_key:pkix_verify_hostname(Cert, [{ip, Hostname}]) of
+verify_hostname({fallback, Hostname}, Customize, Cert, UserState) ->
+ case public_key:pkix_verify_hostname(Cert, [{ip, Hostname}], Customize) of
true ->
{valid, UserState};
false ->
{fail, {bad_cert, hostname_check_failed}}
end;
-verify_hostname(Hostname, Cert, UserState) ->
- case public_key:pkix_verify_hostname(Cert, [{dns_id, Hostname}]) of
+verify_hostname(Hostname, Customize, Cert, UserState) ->
+ case public_key:pkix_verify_hostname(Cert, [{dns_id, Hostname}], Customize) of
true ->
{valid, UserState};
false ->
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 0956d3501d..07ec823829 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -1,7 +1,7 @@
%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -43,7 +43,7 @@
filter/3, filter_suites/1, filter_suites/2,
hash_algorithm/1, sign_algorithm/1, is_acceptable_hash/2, is_fallback/1,
random_bytes/1, calc_mac_hash/4,
- is_stream_ciphersuite/1]).
+ is_stream_ciphersuite/1, suite_to_str/1]).
-export_type([cipher_suite/0,
erl_cipher_suite/0, old_erl_cipher_suite/0, openssl_cipher_suite/0,
@@ -187,7 +187,7 @@ block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0,
block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0,
Mac, Fragment, {3, N})
- when N == 2; N == 3 ->
+ when N == 2; N == 3; N == 4 ->
NextIV = random_iv(IV),
L0 = build_cipher_block(BlockSz, Mac, Fragment),
L = [NextIV|L0],
@@ -320,6 +320,8 @@ suites({3, Minor}) ->
suites({_, Minor}) ->
dtls_v1:suites(Minor).
+all_suites({3, 4}) ->
+ all_suites({3, 3});
all_suites({3, _} = Version) ->
suites(Version)
++ chacha_suites(Version)
@@ -478,11 +480,12 @@ rc4_suites({3, Minor}) ->
rc4_suites(0) ->
[?TLS_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_RC4_128_MD5];
-rc4_suites(N) when N =< 3 ->
+rc4_suites(N) when N =< 4 ->
[?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
?TLS_ECDHE_RSA_WITH_RC4_128_SHA,
?TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
?TLS_ECDH_RSA_WITH_RC4_128_SHA].
+
%%--------------------------------------------------------------------
-spec des_suites(Version::ssl_record:ssl_version()) -> [cipher_suite()].
%%
@@ -517,13 +520,14 @@ rsa_suites(0) ->
?TLS_RSA_WITH_AES_128_CBC_SHA,
?TLS_RSA_WITH_3DES_EDE_CBC_SHA
];
-rsa_suites(N) when N =< 3 ->
+rsa_suites(N) when N =< 4 ->
[
?TLS_RSA_WITH_AES_256_GCM_SHA384,
?TLS_RSA_WITH_AES_256_CBC_SHA256,
?TLS_RSA_WITH_AES_128_GCM_SHA256,
?TLS_RSA_WITH_AES_128_CBC_SHA256
].
+
%%--------------------------------------------------------------------
-spec suite_definition(cipher_suite()) -> erl_cipher_suite().
%%
@@ -1877,6 +1881,32 @@ suite(#{key_exchange := dhe_rsa,
prf := sha256}) ->
?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256.
+
+%%--------------------------------------------------------------------
+-spec suite_to_str(erl_cipher_suite()) -> string().
+%%
+%% Description: Return the string representation of a cipher suite.
+%%--------------------------------------------------------------------
+suite_to_str(#{key_exchange := null,
+ cipher := null,
+ mac := null,
+ prf := null}) ->
+ "TLS_EMPTY_RENEGOTIATION_INFO_SCSV";
+suite_to_str(#{key_exchange := Kex,
+ cipher := Cipher,
+ mac := aead,
+ prf := PRF}) ->
+ "TLS_" ++ string:to_upper(atom_to_list(Kex)) ++
+ "_WITH_" ++ string:to_upper(atom_to_list(Cipher)) ++
+ "_" ++ string:to_upper(atom_to_list(PRF));
+suite_to_str(#{key_exchange := Kex,
+ cipher := Cipher,
+ mac := Mac}) ->
+ "TLS_" ++ string:to_upper(atom_to_list(Kex)) ++
+ "_WITH_" ++ string:to_upper(atom_to_list(Cipher)) ++
+ "_" ++ string:to_upper(atom_to_list(Mac)).
+
+
%%--------------------------------------------------------------------
-spec openssl_suite(openssl_cipher_suite()) -> cipher_suite().
%%
@@ -2230,7 +2260,7 @@ filter(DerCert, Ciphers0, Version) ->
Ciphers0, Version, OtpCert),
{_, Sign} = public_key:pkix_sign_types(SigAlg#'SignatureAlgorithm'.algorithm),
filter_suites_signature(Sign, Ciphers, Version).
-
+
%%--------------------------------------------------------------------
-spec filter_suites([erl_cipher_suite()] | [cipher_suite()], map()) ->
[erl_cipher_suite()] | [cipher_suite()].
@@ -2404,7 +2434,7 @@ mac_hash({_,_}, ?NULL, _MacSecret, _SeqNo, _Type,
mac_hash({3, 0}, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) ->
ssl_v3:mac_hash(MacAlg, MacSecret, SeqNo, Type, Length, Fragment);
mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment)
- when N =:= 1; N =:= 2; N =:= 3 ->
+ when N =:= 1; N =:= 2; N =:= 3; N =:= 4 ->
tls_v1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version,
Length, Fragment).
@@ -2609,7 +2639,7 @@ generic_block_cipher_from_bin({3, N}, T, IV, HashSize)
next_iv = IV};
generic_block_cipher_from_bin({3, N}, T, IV, HashSize)
- when N == 2; N == 3 ->
+ when N == 2; N == 3; N == 4 ->
Sz1 = byte_size(T) - 1,
<<_:Sz1/binary, ?BYTE(PadLength)>> = T,
IVLength = byte_size(IV),
@@ -2662,29 +2692,35 @@ next_iv(Bin, IV) ->
<<_:FirstPart/binary, NextIV:IVSz/binary>> = Bin,
NextIV.
-
-filter_suites_pubkey(rsa, CiphersSuites0, Version, OtpCert) ->
+filter_suites_pubkey(rsa, CiphersSuites0, _Version, OtpCert) ->
KeyUses = key_uses(OtpCert),
+ NotECDSAKeyed = (CiphersSuites0 -- ec_keyed_suites(CiphersSuites0))
+ -- dss_keyed_suites(CiphersSuites0),
CiphersSuites = filter_keyuse_suites(keyEncipherment, KeyUses,
- (CiphersSuites0 -- ec_keyed_suites(CiphersSuites0))
- -- dss_keyed_suites(CiphersSuites0),
+ NotECDSAKeyed,
rsa_suites_encipher(CiphersSuites0)),
filter_keyuse_suites(digitalSignature, KeyUses, CiphersSuites,
- rsa_signed_suites(CiphersSuites, Version));
-filter_suites_pubkey(dsa, Ciphers, _, _OtpCert) ->
- (Ciphers -- rsa_keyed_suites(Ciphers)) -- ec_keyed_suites(Ciphers);
+ rsa_ecdhe_dhe_suites(CiphersSuites));
+filter_suites_pubkey(dsa, Ciphers, _, OtpCert) ->
+ KeyUses = key_uses(OtpCert),
+ NotECRSAKeyed = (Ciphers -- rsa_keyed_suites(Ciphers)) -- ec_keyed_suites(Ciphers),
+ filter_keyuse_suites(digitalSignature, KeyUses, NotECRSAKeyed,
+ dss_dhe_suites(Ciphers));
filter_suites_pubkey(ec, Ciphers, _, OtpCert) ->
- Uses = key_uses(OtpCert),
- filter_keyuse_suites(digitalSignature, Uses,
- (Ciphers -- rsa_keyed_suites(Ciphers)) -- dss_keyed_suites(Ciphers),
- ecdsa_sign_suites(Ciphers)).
-
+ Uses = key_uses(OtpCert),
+ NotRSADSAKeyed = (Ciphers -- rsa_keyed_suites(Ciphers)) -- dss_keyed_suites(Ciphers),
+ CiphersSuites = filter_keyuse_suites(digitalSignature, Uses, NotRSADSAKeyed,
+ ec_ecdhe_suites(Ciphers)),
+ filter_keyuse_suites(keyAgreement, Uses, CiphersSuites, ec_ecdh_suites(Ciphers)).
+
+filter_suites_signature(rsa, Ciphers, {3, N}) when N >= 3 ->
+ Ciphers;
filter_suites_signature(rsa, Ciphers, Version) ->
- Ciphers -- ecdsa_signed_suites(Ciphers, Version) -- dsa_signed_suites(Ciphers, Version);
+ (Ciphers -- ecdsa_signed_suites(Ciphers, Version)) -- dsa_signed_suites(Ciphers, Version);
filter_suites_signature(dsa, Ciphers, Version) ->
- Ciphers -- ecdsa_signed_suites(Ciphers, Version) -- rsa_signed_suites(Ciphers, Version);
+ (Ciphers -- ecdsa_signed_suites(Ciphers, Version)) -- rsa_signed_suites(Ciphers, Version);
filter_suites_signature(ecdsa, Ciphers, Version) ->
- Ciphers -- rsa_signed_suites(Ciphers, Version) -- dsa_signed_suites(Ciphers, Version).
+ (Ciphers -- rsa_signed_suites(Ciphers, Version)) -- dsa_signed_suites(Ciphers, Version).
%% From RFC 5246 - Section 7.4.2. Server Certificate
@@ -2745,14 +2781,14 @@ ecdsa_signed_suites(Ciphers, Version) ->
rsa_keyed(dhe_rsa) ->
true;
+rsa_keyed(ecdhe_rsa) ->
+ true;
rsa_keyed(rsa) ->
true;
rsa_keyed(rsa_psk) ->
true;
rsa_keyed(srp_rsa) ->
true;
-rsa_keyed(ecdhe_rsa) ->
- true;
rsa_keyed(_) ->
false.
@@ -2793,24 +2829,24 @@ dsa_signed_suites(Ciphers, Version) ->
cipher_filters => [],
mac_filters => [],
prf_filters => []}).
-
-dsa_signed({3,N}) when N >= 3 ->
- fun(dhe_dss) -> true;
- (ecdhe_dss) -> true;
- (_) -> false
- end;
dsa_signed(_) ->
fun(dhe_dss) -> true;
- (ecdh_dss) -> true;
- (ecdhe_dss) -> true;
(_) -> false
end.
+dss_dhe_suites(Ciphers) ->
+ filter_suites(Ciphers, #{key_exchange_filters => [fun(dhe_dss) -> true;
+ (_) -> false
+ end],
+ cipher_filters => [],
+ mac_filters => [],
+ prf_filters => []}).
+
ec_keyed(ecdh_ecdsa) ->
true;
-ec_keyed(ecdhe_ecdsa) ->
+ec_keyed(ecdh_rsa) ->
true;
-ec_keyed(ecdh_rsa) ->
+ec_keyed(ecdhe_ecdsa) ->
true;
ec_keyed(_) ->
false.
@@ -2822,9 +2858,28 @@ ec_keyed_suites(Ciphers) ->
mac_filters => [],
prf_filters => []}).
-%% EC Certs key can be used for signing
-ecdsa_sign_suites(Ciphers)->
+%% EC Certs key usage keyAgreement
+ec_ecdh_suites(Ciphers)->
+ filter_suites(Ciphers, #{key_exchange_filters => [fun(ecdh_ecdsa) -> true;
+ (_) -> false
+ end],
+ cipher_filters => [],
+ mac_filters => [],
+ prf_filters => []}).
+
+%% EC Certs key usage digitalSignature
+ec_ecdhe_suites(Ciphers) ->
filter_suites(Ciphers, #{key_exchange_filters => [fun(ecdhe_ecdsa) -> true;
+ (ecdhe_rsa) -> true;
+ (_) -> false
+ end],
+ cipher_filters => [],
+ mac_filters => [],
+ prf_filters => []}).
+%% RSA Certs key usage digitalSignature
+rsa_ecdhe_dhe_suites(Ciphers) ->
+ filter_suites(Ciphers, #{key_exchange_filters => [fun(dhe_rsa) -> true;
+ (ecdhe_rsa) -> true;
(_) -> false
end],
cipher_filters => [],
@@ -2837,11 +2892,14 @@ key_uses(OtpCert) ->
Extensions = ssl_certificate:extensions_list(TBSExtensions),
case ssl_certificate:select_extension(?'id-ce-keyUsage', Extensions) of
undefined ->
- undefined;
+ [];
#'Extension'{extnValue = KeyUses} ->
KeyUses
end.
+%% If no key-usage extension is defined all key-usages are allowed
+filter_keyuse_suites(_, [], CiphersSuites, _) ->
+ CiphersSuites;
filter_keyuse_suites(Use, KeyUse, CipherSuits, Suites) ->
case ssl_certificate:is_valid_key_usage(KeyUse, Use) of
true ->
diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl
index e5462d8402..ba6a98b92a 100644
--- a/lib/ssl/src/ssl_cipher.hrl
+++ b/lib/ssl/src/ssl_cipher.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/src/ssl_config.erl b/lib/ssl/src/ssl_config.erl
index 452a98e683..1e6dab9276 100644
--- a/lib/ssl/src/ssl_config.erl
+++ b/lib/ssl/src/ssl_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -91,9 +91,9 @@ init_certificates(undefined, #{pem_cache := PemCache} = Config, CertFile, server
end;
init_certificates(Cert, Config, _, _) ->
{ok, Config#{own_certificate => Cert}}.
-init_private_key(_, #{algorithm := Alg} = Key, <<>>, _Password, _Client) when Alg == ecdsa;
- Alg == rsa;
- Alg == dss ->
+init_private_key(_, #{algorithm := Alg} = Key, _, _Password, _Client) when Alg == ecdsa;
+ Alg == rsa;
+ Alg == dss ->
case maps:is_key(engine, Key) andalso maps:is_key(key_id, Key) of
true ->
Key;
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index ec034af44c..6e98baf984 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,6 +35,7 @@
-include("ssl_internal.hrl").
-include("ssl_srp.hrl").
-include_lib("public_key/include/public_key.hrl").
+-include_lib("kernel/include/logger.hrl").
%% Setup
@@ -334,14 +335,20 @@ handle_own_alert(Alert, Version, StateName,
connection_states = ConnectionStates,
ssl_options = SslOpts} = State) ->
try %% Try to tell the other side
- {BinMsg, _} =
- Connection:encode_alert(Alert, Version, ConnectionStates),
- Connection:send(Transport, Socket, BinMsg)
+ {BinMsg, _} =
+ Connection:encode_alert(Alert, Version, ConnectionStates),
+ Connection:send(Transport, Socket, BinMsg),
+ Report = #{direction => outbound,
+ protocol => 'tls_record',
+ message => BinMsg},
+ ssl_logger:debug(SslOpts#ssl_options.log_level, Report, #{domain => [otp,ssl,tls_record]})
catch _:_ -> %% Can crash if we are in a uninitialized state
ignore
end,
try %% Try to tell the local user
- log_alert(SslOpts#ssl_options.log_alert, Role, Connection:protocol_name(), StateName, Alert#alert{role = Role}),
+ log_alert(SslOpts#ssl_options.log_level, Role,
+ Connection:protocol_name(), StateName,
+ Alert#alert{role = Role}),
handle_normal_shutdown(Alert,StateName, State)
catch _:_ ->
ok
@@ -372,8 +379,9 @@ handle_alert(#alert{level = ?FATAL} = Alert, StateName,
port = Port, session = Session, user_application = {_Mon, Pid},
role = Role, socket_options = Opts, tracker = Tracker} = State) ->
invalidate_session(Role, Host, Port, Session),
- log_alert(SslOpts#ssl_options.log_alert, Role, Connection:protocol_name(),
- StateName, Alert#alert{role = opposite_role(Role)}),
+ log_alert(SslOpts#ssl_options.log_level, Role,
+ Connection:protocol_name(), StateName,
+ Alert#alert{role = opposite_role(Role)}),
alert_user(Transport, Tracker, Socket, StateName, Opts, Pid, From, Alert, Role, Connection),
stop(normal, State);
@@ -384,8 +392,9 @@ handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert,
handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName,
#state{role = Role, ssl_options = SslOpts, protocol_cb = Connection, renegotiation = {true, internal}} = State) ->
- log_alert(SslOpts#ssl_options.log_alert, Role,
- Connection:protocol_name(), StateName, Alert#alert{role = opposite_role(Role)}),
+ log_alert(SslOpts#ssl_options.log_level, Role,
+ Connection:protocol_name(), StateName,
+ Alert#alert{role = opposite_role(Role)}),
handle_normal_shutdown(Alert, StateName, State),
stop({shutdown, peer_close}, State);
@@ -393,8 +402,9 @@ handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert,
#state{role = Role,
ssl_options = SslOpts, renegotiation = {true, From},
protocol_cb = Connection} = State0) ->
- log_alert(SslOpts#ssl_options.log_alert, Role,
- Connection:protocol_name(), StateName, Alert#alert{role = opposite_role(Role)}),
+ log_alert(SslOpts#ssl_options.log_level, Role,
+ Connection:protocol_name(), StateName,
+ Alert#alert{role = opposite_role(Role)}),
gen_statem:reply(From, {error, renegotiation_rejected}),
{Record, State1} = Connection:next_record(State0),
%% Go back to connection!
@@ -404,8 +414,9 @@ handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert,
%% Gracefully log and ignore all other warning alerts
handle_alert(#alert{level = ?WARNING} = Alert, StateName,
#state{ssl_options = SslOpts, protocol_cb = Connection, role = Role} = State0) ->
- log_alert(SslOpts#ssl_options.log_alert, Role,
- Connection:protocol_name(), StateName, Alert#alert{role = opposite_role(Role)}),
+ log_alert(SslOpts#ssl_options.log_level, Role,
+ Connection:protocol_name(), StateName,
+ Alert#alert{role = opposite_role(Role)}),
{Record, State} = Connection:next_record(State0),
Connection:next_event(StateName, Record, State).
@@ -419,7 +430,7 @@ write_application_data(Data0, {FromPid, _} = From,
transport_cb = Transport,
connection_states = ConnectionStates0,
socket_options = SockOpts,
- ssl_options = #ssl_options{renegotiate_at = RenegotiateAt}} = State) ->
+ ssl_options = #ssl_options{renegotiate_at = RenegotiateAt} = SslOpts} = State) ->
Data = encode_packet(Data0, SockOpts),
case time_to_renegotiate(Data, ConnectionStates0, RenegotiateAt) of
@@ -430,16 +441,21 @@ write_application_data(Data0, {FromPid, _} = From,
{Msgs, ConnectionStates} =
Connection:encode_data(Data, Version, ConnectionStates0),
NewState = State#state{connection_states = ConnectionStates},
- case Connection:send(Transport, Socket, Msgs) of
- ok when FromPid =:= self() ->
- hibernate_after(connection, NewState, []);
- Error when FromPid =:= self() ->
- stop({shutdown, Error}, NewState);
- ok ->
- hibernate_after(connection, NewState, [{reply, From, ok}]);
- Result ->
- hibernate_after(connection, NewState, [{reply, From, Result}])
- end
+ RetVal = case Connection:send(Transport, Socket, Msgs) of
+ ok when FromPid =:= self() ->
+ hibernate_after(connection, NewState, []);
+ Error when FromPid =:= self() ->
+ stop({shutdown, Error}, NewState);
+ ok ->
+ hibernate_after(connection, NewState, [{reply, From, ok}]);
+ Result ->
+ hibernate_after(connection, NewState, [{reply, From, Result}])
+ end,
+ Report = #{direction => outbound,
+ protocol => 'tls_record',
+ message => Msgs},
+ ssl_logger:debug(SslOpts#ssl_options.log_level, Report, #{domain => [otp,ssl,tls_record]}),
+ RetVal
end.
read_application_data(Data, #state{user_application = {_Mon, Pid},
@@ -634,8 +650,10 @@ init(_Type, _Event, _State, _Connection) ->
tls_connection | dtls_connection) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
-error({call, From}, Msg, State, Connection) ->
- handle_call(Msg, From, ?FUNCTION_NAME, State, Connection).
+error({call, From}, {close, _}, State, _Connection) ->
+ stop_and_reply(normal, {reply, From, ok}, State);
+error({call, From}, _Msg, State, _Connection) ->
+ {next_state, ?FUNCTION_NAME, State, [{reply, From, {error, closed}}]}.
%%--------------------------------------------------------------------
-spec hello(gen_statem:event_type(),
@@ -791,6 +809,7 @@ certify(internal, #server_key_exchange{exchange_keys = Keys},
#state{role = client, negotiated_version = Version,
key_algorithm = Alg,
public_key_info = PubKeyInfo,
+ session = Session,
connection_states = ConnectionStates} = State, Connection)
when Alg == dhe_dss; Alg == dhe_rsa;
Alg == ecdhe_rsa; Alg == ecdhe_ecdsa;
@@ -812,7 +831,8 @@ certify(internal, #server_key_exchange{exchange_keys = Keys},
ConnectionStates, ssl:tls_version(Version), PubKeyInfo) of
true ->
calculate_secret(Params#server_key_params.params,
- State#state{hashsign_algorithm = HashSign},
+ State#state{hashsign_algorithm = HashSign,
+ session = session_handle_params(Params#server_key_params.params, Session)},
Connection);
false ->
handle_own_alert(?ALERT_REC(?FATAL, ?DECRYPT_ERROR),
@@ -1339,7 +1359,7 @@ handle_info({ErrorTag, Socket, econnaborted}, StateName,
handle_info({ErrorTag, Socket, Reason}, StateName, #state{socket = Socket,
error_tag = ErrorTag} = State) ->
Report = io_lib:format("SSL: Socket error: ~p ~n", [Reason]),
- error_logger:error_report(Report),
+ ?LOG_ERROR(Report),
handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
stop(normal, State);
@@ -1388,7 +1408,7 @@ handle_info({cancel_start_or_recv, _RecvFrom}, StateName, State) ->
handle_info(Msg, StateName, #state{socket = Socket, error_tag = Tag} = State) ->
Report = io_lib:format("SSL: Got unexpected info: ~p ~n", [{Msg, Tag, Socket}]),
- error_logger:info_report(Report),
+ ?LOG_NOTICE(Report),
{next_state, StateName, State}.
%%====================================================================
@@ -1472,7 +1492,7 @@ connection_info(#state{sni_hostname = SNIHostname,
RecordCB = record_cb(Connection),
CipherSuiteDef = #{key_exchange := KexAlg} = ssl_cipher:suite_definition(CipherSuite),
IsNamedCurveSuite = lists:member(KexAlg,
- [ecdh_ecdsa, ecdhe_ecdsa, ecdh_rsa, ecdh_anon]),
+ [ecdh_ecdsa, ecdhe_ecdsa, ecdh_rsa, ecdhe_rsa, ecdh_anon]),
CurveInfo = case ECCCurve of
{namedCurve, Curve} when IsNamedCurveSuite ->
[{ecc, {named_curve, pubkey_cert_records:namedCurves(Curve)}}];
@@ -1482,6 +1502,7 @@ connection_info(#state{sni_hostname = SNIHostname,
[{protocol, RecordCB:protocol_version(Version)},
{session_id, SessionId},
{cipher_suite, ssl_cipher:erl_suite_definition(CipherSuiteDef)},
+ {selected_cipher_suite, CipherSuiteDef},
{sni_hostname, SNIHostname} | CurveInfo] ++ ssl_options_list(Opts).
security_info(#state{connection_states = ConnectionStates}) ->
@@ -1496,13 +1517,18 @@ do_server_hello(Type, #hello_extensions{next_protocol_negotiation = NextProtocol
ServerHelloExt,
#state{negotiated_version = Version,
session = #session{session_id = SessId},
- connection_states = ConnectionStates0}
+ connection_states = ConnectionStates0,
+ ssl_options = #ssl_options{versions = [HighestVersion|_]}}
= State0, Connection) when is_atom(Type) ->
-
+ %% TLS 1.3 - Section 4.1.3
+ %% Override server random values for TLS 1.3 downgrade protection mechanism.
+ ConnectionStates1 = update_server_random(ConnectionStates0, Version, HighestVersion),
+ State1 = State0#state{connection_states = ConnectionStates1},
ServerHello =
- ssl_handshake:server_hello(SessId, ssl:tls_version(Version), ConnectionStates0, ServerHelloExt),
+ ssl_handshake:server_hello(SessId, ssl:tls_version(Version),
+ ConnectionStates1, ServerHelloExt),
State = server_hello(ServerHello,
- State0#state{expecting_next_protocol_negotiation =
+ State1#state{expecting_next_protocol_negotiation =
NextProtocols =/= undefined}, Connection),
case Type of
new ->
@@ -1511,6 +1537,60 @@ do_server_hello(Type, #hello_extensions{next_protocol_negotiation = NextProtocol
resumed_server_hello(State, Connection)
end.
+update_server_random(#{pending_read := #{security_parameters := ReadSecParams0} =
+ ReadState0,
+ pending_write := #{security_parameters := WriteSecParams0} =
+ WriteState0} = ConnectionStates,
+ Version, HighestVersion) ->
+ ReadRandom = override_server_random(
+ ReadSecParams0#security_parameters.server_random,
+ Version,
+ HighestVersion),
+ WriteRandom = override_server_random(
+ WriteSecParams0#security_parameters.server_random,
+ Version,
+ HighestVersion),
+ ReadSecParams = ReadSecParams0#security_parameters{server_random = ReadRandom},
+ WriteSecParams = WriteSecParams0#security_parameters{server_random = WriteRandom},
+ ReadState = ReadState0#{security_parameters => ReadSecParams},
+ WriteState = WriteState0#{security_parameters => WriteSecParams},
+
+ ConnectionStates#{pending_read => ReadState, pending_write => WriteState}.
+
+%% TLS 1.3 - Section 4.1.3
+%%
+%% If negotiating TLS 1.2, TLS 1.3 servers MUST set the last eight bytes
+%% of their Random value to the bytes:
+%%
+%% 44 4F 57 4E 47 52 44 01
+%%
+%% If negotiating TLS 1.1 or below, TLS 1.3 servers MUST and TLS 1.2
+%% servers SHOULD set the last eight bytes of their Random value to the
+%% bytes:
+%%
+%% 44 4F 57 4E 47 52 44 00
+override_server_random(<<Random0:24/binary,_:8/binary>> = Random, {M,N}, {Major,Minor})
+ when Major > 3 orelse Major =:= 3 andalso Minor >= 4 -> %% TLS 1.3 or above
+ if M =:= 3 andalso N =:= 3 -> %% Negotating TLS 1.2
+ Down = ?RANDOM_OVERRIDE_TLS12,
+ <<Random0/binary,Down/binary>>;
+ M =:= 3 andalso N < 3 -> %% Negotating TLS 1.1 or prior
+ Down = ?RANDOM_OVERRIDE_TLS11,
+ <<Random0/binary,Down/binary>>;
+ true ->
+ Random
+ end;
+override_server_random(<<Random0:24/binary,_:8/binary>> = Random, {M,N}, {Major,Minor})
+ when Major =:= 3 andalso Minor =:= 3 -> %% TLS 1.2
+ if M =:= 3 andalso N < 3 -> %% Negotating TLS 1.1 or prior
+ Down = ?RANDOM_OVERRIDE_TLS11,
+ <<Random0/binary,Down/binary>>;
+ true ->
+ Random
+ end;
+override_server_random(Random, _, _) ->
+ Random.
+
new_server_hello(#server_hello{cipher_suite = CipherSuite,
compression_method = Compression,
session_id = SessionId},
@@ -1575,11 +1655,9 @@ handle_peer_cert_key(client, _,
KeyAlg, #state{session = Session} = State) when KeyAlg == ecdh_rsa;
KeyAlg == ecdh_ecdsa ->
ECDHKey = public_key:generate_key(PublicKeyParams),
- {namedCurve, Oid} = PublicKeyParams,
- Curve = pubkey_cert_records:namedCurves(Oid), %% Need API function
PremasterSecret = ssl_handshake:premaster_secret(PublicKey, ECDHKey),
master_secret(PremasterSecret, State#state{diffie_hellman_keys = ECDHKey,
- session = Session#session{ecc = {named_curve, Curve}}});
+ session = Session#session{ecc = PublicKeyParams}});
%% We do currently not support cipher suites that use fixed DH.
%% If we want to implement that the following clause can be used
%% to extract DH parameters form cert.
@@ -1756,9 +1834,11 @@ key_exchange(#state{role = server, key_algorithm = Algo,
PrivateKey}),
State = Connection:queue_handshake(Msg, State0),
State#state{diffie_hellman_keys = DHKeys};
-key_exchange(#state{role = server, private_key = Key, key_algorithm = Algo} = State, _)
+key_exchange(#state{role = server, private_key = #'ECPrivateKey'{parameters = ECCurve} = Key, key_algorithm = Algo,
+ session = Session} = State, _)
when Algo == ecdh_ecdsa; Algo == ecdh_rsa ->
- State#state{diffie_hellman_keys = Key};
+ State#state{diffie_hellman_keys = Key,
+ session = Session#session{ecc = ECCurve}};
key_exchange(#state{role = server, key_algorithm = Algo,
hashsign_algorithm = HashSignAlgo,
private_key = PrivateKey,
@@ -1914,12 +1994,13 @@ key_exchange(#state{role = client,
key_exchange(#state{role = client,
key_algorithm = Algorithm,
negotiated_version = Version,
- diffie_hellman_keys = Keys} = State0, Connection)
+ session = Session,
+ diffie_hellman_keys = #'ECPrivateKey'{parameters = ECCurve} = Key} = State0, Connection)
when Algorithm == ecdhe_ecdsa; Algorithm == ecdhe_rsa;
Algorithm == ecdh_ecdsa; Algorithm == ecdh_rsa;
Algorithm == ecdh_anon ->
- Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {ecdh, Keys}),
- Connection:queue_handshake(Msg, State0);
+ Msg = ssl_handshake:key_exchange(client, ssl:tls_version(Version), {ecdh, Key}),
+ Connection:queue_handshake(Msg, State0#state{session = Session#session{ecc = ECCurve}});
key_exchange(#state{role = client,
ssl_options = SslOpts,
key_algorithm = psk,
@@ -2391,7 +2472,7 @@ handle_trusted_certs_db(#state{ssl_options =
handle_trusted_certs_db(#state{cert_db_ref = Ref,
cert_db = CertDb,
ssl_options = #ssl_options{cacertfile = <<>>}}) when CertDb =/= undefined ->
- %% Certs provided as DER directly can not be shared
+ %% Certs provided as DER directly cannot be shared
%% with other connections and it is safe to delete them when the connection ends.
ssl_pkix_db:remove_trusted_certs(Ref, CertDb);
handle_trusted_certs_db(#state{file_ref_db = undefined}) ->
@@ -2442,6 +2523,11 @@ cancel_timer(Timer) ->
erlang:cancel_timer(Timer),
ok.
+session_handle_params(#server_ecdh_params{curve = ECCurve}, Session) ->
+ Session#session{ecc = ECCurve};
+session_handle_params(_, Session) ->
+ Session.
+
register_session(client, Host, Port, #session{is_resumable = new} = Session0) ->
Session = Session0#session{is_resumable = true},
ssl_manager:register_session(Host, Port, Session),
@@ -2522,7 +2608,7 @@ ssl_options_list([ciphers = Key | Keys], [Value | Values], Acc) ->
ssl_options_list(Keys, Values,
[{Key, lists:map(
fun(Suite) ->
- ssl_cipher:erl_suite_definition(Suite)
+ ssl_cipher:suite_definition(Suite)
end, Value)}
| Acc]);
ssl_options_list([Key | Keys], [Value | Values], Acc) ->
@@ -2739,14 +2825,14 @@ alert_user(Transport, Tracker, Socket, Active, Pid, From, Alert, Role, Connectio
Transport, Socket, Connection, Tracker), ReasonCode})
end.
-log_alert(true, Role, ProtocolName, StateName, #alert{role = Role} = Alert) ->
+log_alert(Level, Role, ProtocolName, StateName, #alert{role = Role} = Alert) ->
Txt = ssl_alert:own_alert_txt(Alert),
- error_logger:info_report(io_lib:format("~s ~p: In state ~p ~s\n", [ProtocolName, Role, StateName, Txt]));
-log_alert(true, Role, ProtocolName, StateName, Alert) ->
+ Report = io_lib:format("~s ~p: In state ~p ~s\n", [ProtocolName, Role, StateName, Txt]),
+ ssl_logger:notice(Level, Report);
+log_alert(Level, Role, ProtocolName, StateName, Alert) ->
Txt = ssl_alert:alert_txt(Alert),
- error_logger:info_report(io_lib:format("~s ~p: In state ~p ~s\n", [ProtocolName, Role, StateName, Txt]));
-log_alert(false, _, _, _, _) ->
- ok.
+ Report = io_lib:format("~s ~p: In state ~p ~s\n", [ProtocolName, Role, StateName, Txt]),
+ ssl_logger:notice(Level, Report).
invalidate_session(client, Host, Port, Session) ->
ssl_manager:invalidate_session(Host, Port, Session);
@@ -2836,7 +2922,7 @@ erl_dist_stop_reason(
Reason, #state{ssl_options = #ssl_options{erl_dist = true}}) ->
case Reason of
normal ->
- %% We can not exit with normal since that will not bring
+ %% We cannot exit with normal since that will not bring
%% down the rest of the distribution processes
{shutdown, normal};
_ -> Reason
diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl
index a61ff747ae..811aa779d5 100644
--- a/lib/ssl/src/ssl_connection.hrl
+++ b/lib/ssl/src/ssl_connection.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/src/ssl_connection_sup.erl b/lib/ssl/src/ssl_connection_sup.erl
index 1a1f43e683..934dd39df5 100644
--- a/lib/ssl/src/ssl_connection_sup.erl
+++ b/lib/ssl/src/ssl_connection_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -51,12 +51,12 @@ init([]) ->
ListenOptionsTracker = listen_options_tracker_child_spec(),
DTLSConnetionManager = dtls_connection_manager_child_spec(),
- DTLSUdpListeners = dtls_udp_listeners_spec(),
+ DTLSListeners = dtls_listeners_spec(),
{ok, {{one_for_one, 10, 3600}, [TLSConnetionManager,
ListenOptionsTracker,
DTLSConnetionManager,
- DTLSUdpListeners
+ DTLSListeners
]}}.
@@ -91,9 +91,9 @@ listen_options_tracker_child_spec() ->
Type = supervisor,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
-dtls_udp_listeners_spec() ->
- Name = dtls_udp_listener,
- StartFunc = {dtls_udp_sup, start_link, []},
+dtls_listeners_spec() ->
+ Name = dtls_listener,
+ StartFunc = {dtls_listener_sup, start_link, []},
Restart = permanent,
Shutdown = 4000,
Modules = [],
diff --git a/lib/ssl/src/ssl_crl_cache.erl b/lib/ssl/src/ssl_crl_cache.erl
index 66f46da75f..9c1af86eeb 100644
--- a/lib/ssl/src/ssl_crl_cache.erl
+++ b/lib/ssl/src/ssl_crl_cache.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/src/ssl_crl_hash_dir.erl b/lib/ssl/src/ssl_crl_hash_dir.erl
index bb62737232..9478ff9b78 100644
--- a/lib/ssl/src/ssl_crl_hash_dir.erl
+++ b/lib/ssl/src/ssl_crl_hash_dir.erl
@@ -20,6 +20,7 @@
-module(ssl_crl_hash_dir).
-include_lib("public_key/include/public_key.hrl").
+-include_lib("kernel/include/logger.hrl").
-behaviour(ssl_crl_cache_api).
@@ -55,7 +56,7 @@ select(Issuer, {_DbHandle, [{dir, Dir}]}) ->
%% is happy with that, but if it's true, this is an error.
[];
{error, Error} ->
- error_logger:error_report(
+ ?LOG_ERROR(
[{cannot_find_crl, Error},
{dir, Dir},
{module, ?MODULE},
@@ -86,7 +87,7 @@ find_crls(Issuer, Hash, Dir, N, Acc) ->
error:Error ->
%% Something is wrong with the file. Report
%% it, and try the next one.
- error_logger:error_report(
+ ?LOG_ERROR(
[{crl_parse_error, Error},
{filename, Filename},
{module, ?MODULE},
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 090e7b69b7..73757e6b65 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -53,7 +53,7 @@
-export([certify/7, certificate_verify/6, verify_signature/5,
master_secret/4, server_key_exchange_hash/2, verify_connection/6,
init_handshake_history/0, update_handshake_history/2, verify_server_key/5,
- select_version/3, extension_value/1
+ select_version/3, select_supported_version/2, extension_value/1
]).
%% Encode
@@ -345,6 +345,7 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef,
Opts#ssl_options.partial_chain),
ValidationFunAndState = validation_fun_and_state(Opts#ssl_options.verify_fun, Role,
CertDbHandle, CertDbRef, ServerName,
+ Opts#ssl_options.customize_hostname_check,
Opts#ssl_options.crl_check, CRLDbHandle, CertPath),
case public_key:pkix_path_validation(TrustedCert,
CertPath,
@@ -504,6 +505,21 @@ verify_server_key(#server_key_params{params_bin = EncParams,
select_version(RecordCB, ClientVersion, Versions) ->
do_select_version(RecordCB, ClientVersion, Versions).
+
+%% Called by TLS 1.2/1.3 Server when "supported_versions" is present
+%% in ClientHello.
+%% Input lists are ordered (highest first)
+select_supported_version([], _ServerVersions) ->
+ undefined;
+select_supported_version([ClientVersion|T], ServerVersions) ->
+ case lists:member(ClientVersion, ServerVersions) of
+ true ->
+ ClientVersion;
+ false ->
+ select_supported_version(T, ServerVersions)
+ end.
+
+
%%====================================================================
%% Encode handshake
%%====================================================================
@@ -631,7 +647,20 @@ encode_hello_extensions([#sni{hostname = Hostname} | Rest], Acc) ->
?UINT16(ServerNameLength),
?BYTE(?SNI_NAMETYPE_HOST_NAME),
?UINT16(HostLen), HostnameBin/binary,
- Acc/binary>>).
+ Acc/binary>>);
+encode_hello_extensions([#client_hello_versions{versions = Versions0} | Rest], Acc) ->
+ Versions = encode_versions(Versions0),
+ VerLen = byte_size(Versions),
+ Len = VerLen + 2,
+ encode_hello_extensions(Rest, <<?UINT16(?SUPPORTED_VERSIONS_EXT),
+ ?UINT16(Len), ?UINT16(VerLen), Versions/binary, Acc/binary>>);
+encode_hello_extensions([#server_hello_selected_version{selected_version = Version0} | Rest], Acc) ->
+ Version = encode_versions(Version0),
+ Len = byte_size(Version), %% 2
+ encode_hello_extensions(Rest, <<?UINT16(?SUPPORTED_VERSIONS_EXT),
+ ?UINT16(Len), Version/binary, Acc/binary>>).
+
+
encode_client_protocol_negotiation(undefined, _) ->
undefined;
@@ -929,7 +958,8 @@ premaster_secret(EncSecret, #'RSAPrivateKey'{} = RSAPrivateKey) ->
%%====================================================================
client_hello_extensions(Version, CipherSuites,
#ssl_options{signature_algs = SupportedHashSigns,
- eccs = SupportedECCs} = SslOpts, ConnectionStates, Renegotiation) ->
+ eccs = SupportedECCs,
+ versions = Versions} = SslOpts, ConnectionStates, Renegotiation) ->
{EcPointFormats, EllipticCurves} =
case advertises_ec_ciphers(lists:map(fun ssl_cipher:suite_definition/1, CipherSuites)) of
true ->
@@ -939,18 +969,29 @@ client_hello_extensions(Version, CipherSuites,
end,
SRP = srp_user(SslOpts),
- #hello_extensions{
- renegotiation_info = renegotiation_info(tls_record, client,
- ConnectionStates, Renegotiation),
- srp = SRP,
- signature_algs = available_signature_algs(SupportedHashSigns, Version),
- ec_point_formats = EcPointFormats,
- elliptic_curves = EllipticCurves,
- alpn = encode_alpn(SslOpts#ssl_options.alpn_advertised_protocols, Renegotiation),
- next_protocol_negotiation =
- encode_client_protocol_negotiation(SslOpts#ssl_options.next_protocol_selector,
- Renegotiation),
- sni = sni(SslOpts#ssl_options.server_name_indication)}.
+ HelloExtensions =
+ #hello_extensions{
+ renegotiation_info = renegotiation_info(tls_record, client,
+ ConnectionStates, Renegotiation),
+ srp = SRP,
+ signature_algs = available_signature_algs(SupportedHashSigns, Version),
+ ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves,
+ alpn = encode_alpn(SslOpts#ssl_options.alpn_advertised_protocols, Renegotiation),
+ next_protocol_negotiation =
+ encode_client_protocol_negotiation(SslOpts#ssl_options.next_protocol_selector,
+ Renegotiation),
+ sni = sni(SslOpts#ssl_options.server_name_indication)},
+
+ %% Add "supported_versions" extension if TLS 1.3
+ case Version of
+ {3,4} ->
+ HelloExtensions#hello_extensions{
+ client_hello_versions = #client_hello_versions{
+ versions = Versions}};
+ _Else ->
+ HelloExtensions
+ end.
handle_client_hello_extensions(RecordCB, Random, ClientCipherSuites,
#hello_extensions{renegotiation_info = Info,
@@ -1054,7 +1095,8 @@ select_curve(undefined, _, _) ->
%%--------------------------------------------------------------------
select_hashsign(_, _, KeyExAlgo, _, _Version) when KeyExAlgo == dh_anon;
KeyExAlgo == ecdh_anon;
- KeyExAlgo == srp_anon ->
+ KeyExAlgo == srp_anon;
+ KeyExAlgo == psk ->
{null, anon};
%% The signature_algorithms extension was introduced with TLS 1.2. Ignore it if we have
%% negotiated a lower version.
@@ -1063,17 +1105,14 @@ select_hashsign(HashSigns, Cert, KeyExAlgo,
select_hashsign(HashSigns, Cert, KeyExAlgo, tls_v1:default_signature_algs(Version), Version);
select_hashsign(#hash_sign_algos{hash_sign_algos = HashSigns}, Cert, KeyExAlgo, SupportedHashSigns,
{Major, Minor}) when Major >= 3 andalso Minor >= 3 ->
- #'OTPCertificate'{tbsCertificate = TBSCert,
- signatureAlgorithm = {_,SignAlgo, _}} = public_key:pkix_decode_cert(Cert, otp),
+ #'OTPCertificate'{tbsCertificate = TBSCert} = public_key:pkix_decode_cert(Cert, otp),
#'OTPSubjectPublicKeyInfo'{algorithm = {_, SubjAlgo, _}} =
TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
- Sign = sign_algo(SignAlgo),
SubSign = sign_algo(SubjAlgo),
case lists:filter(fun({_, S} = Algos) when S == SubSign ->
- is_acceptable_hash_sign(Algos, Sign,
- SubSign, KeyExAlgo, SupportedHashSigns);
+ is_acceptable_hash_sign(Algos, KeyExAlgo, SupportedHashSigns);
(_) ->
false
end, HashSigns) of
@@ -1243,7 +1282,7 @@ certificate_authorities_from_db(_CertDbHandle, {extracted, CertDbData}) ->
%%-------------Handle handshake messages --------------------------------
validation_fun_and_state({Fun, UserState0}, Role, CertDbHandle, CertDbRef,
- ServerNameIndication, CRLCheck, CRLDbHandle, CertPath) ->
+ ServerNameIndication, CustomizeHostCheck, CRLCheck, CRLDbHandle, CertPath) ->
{fun(OtpCert, {extension, _} = Extension, {SslState, UserState}) ->
case ssl_certificate:validate(OtpCert,
Extension,
@@ -1260,9 +1299,9 @@ validation_fun_and_state({Fun, UserState0}, Role, CertDbHandle, CertDbRef,
(OtpCert, VerifyResult, {SslState, UserState}) ->
apply_user_fun(Fun, OtpCert, VerifyResult, UserState,
SslState, CertPath)
- end, {{Role, CertDbHandle, CertDbRef, ServerNameIndication, CRLCheck, CRLDbHandle}, UserState0}};
+ end, {{Role, CertDbHandle, CertDbRef, {ServerNameIndication, CustomizeHostCheck}, CRLCheck, CRLDbHandle}, UserState0}};
validation_fun_and_state(undefined, Role, CertDbHandle, CertDbRef,
- ServerNameIndication, CRLCheck, CRLDbHandle, CertPath) ->
+ ServerNameIndication, CustomizeHostCheck, CRLCheck, CRLDbHandle, CertPath) ->
{fun(OtpCert, {extension, _} = Extension, SslState) ->
ssl_certificate:validate(OtpCert,
Extension,
@@ -1282,7 +1321,7 @@ validation_fun_and_state(undefined, Role, CertDbHandle, CertDbRef,
ssl_certificate:validate(OtpCert,
VerifyResult,
SslState)
- end, {Role, CertDbHandle, CertDbRef, ServerNameIndication, CRLCheck, CRLDbHandle}}.
+ end, {Role, CertDbHandle, CertDbRef, {ServerNameIndication, CustomizeHostCheck}, CRLCheck, CRLDbHandle}}.
apply_user_fun(Fun, OtpCert, VerifyResult, UserState0,
{_, CertDbHandle, CertDbRef, _, CRLCheck, CRLDbHandle} = SslState, CertPath) when
@@ -1723,6 +1762,16 @@ encode_alpn(undefined, _) ->
encode_alpn(Protocols, _) ->
#alpn{extension_data = lists:foldl(fun encode_protocol/2, <<>>, Protocols)}.
+
+encode_versions(Versions) ->
+ encode_versions(lists:reverse(Versions), <<>>).
+%%
+encode_versions([], Acc) ->
+ Acc;
+encode_versions([{M,N}|T], Acc) ->
+ encode_versions(T, <<?BYTE(M),?BYTE(N),Acc/binary>>).
+
+
hello_extensions_list(#hello_extensions{renegotiation_info = RenegotiationInfo,
srp = SRP,
signature_algs = HashSigns,
@@ -1730,9 +1779,13 @@ hello_extensions_list(#hello_extensions{renegotiation_info = RenegotiationInfo,
elliptic_curves = EllipticCurves,
alpn = ALPN,
next_protocol_negotiation = NextProtocolNegotiation,
- sni = Sni}) ->
+ sni = Sni,
+ client_hello_versions = Versions,
+ server_hello_selected_version = Version}) ->
[Ext || Ext <- [RenegotiationInfo, SRP, HashSigns,
- EcPointFormats, EllipticCurves, ALPN, NextProtocolNegotiation, Sni], Ext =/= undefined].
+ EcPointFormats, EllipticCurves, ALPN,
+ NextProtocolNegotiation, Sni,
+ Versions, Version], Ext =/= undefined].
%%-------------Decode handshakes---------------------------------
dec_server_key(<<?UINT16(PLen), P:PLen/binary,
@@ -1932,15 +1985,28 @@ dec_hello_extensions(<<?UINT16(?EC_POINT_FORMATS_EXT), ?UINT16(Len),
ECPointFormats}});
dec_hello_extensions(<<?UINT16(?SNI_EXT), ?UINT16(Len), Rest/binary>>, Acc) when Len == 0 ->
- dec_hello_extensions(Rest, Acc#hello_extensions{sni = ""}); %% Server may send an empy SNI
+ dec_hello_extensions(Rest, Acc#hello_extensions{sni = #sni{hostname = ""}}); %% Server may send an empy SNI
dec_hello_extensions(<<?UINT16(?SNI_EXT), ?UINT16(Len),
ExtData:Len/binary, Rest/binary>>, Acc) ->
<<?UINT16(_), NameList/binary>> = ExtData,
dec_hello_extensions(Rest, Acc#hello_extensions{sni = dec_sni(NameList)});
+
+dec_hello_extensions(<<?UINT16(?SUPPORTED_VERSIONS_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Acc) when Len > 2 ->
+ <<?UINT16(_),Versions/binary>> = ExtData,
+ dec_hello_extensions(Rest, Acc#hello_extensions{
+ client_hello_versions =
+ #client_hello_versions{versions = decode_versions(Versions)}});
+
+dec_hello_extensions(<<?UINT16(?SUPPORTED_VERSIONS_EXT), ?UINT16(Len),
+ ?UINT16(Version), Rest/binary>>, Acc) when Len =:= 2, Version =:= 16#0304 ->
+ dec_hello_extensions(Rest, Acc#hello_extensions{
+ server_hello_selected_version =
+ #server_hello_selected_version{selected_version = [{3,4}]}});
+
%% Ignore data following the ClientHello (i.e.,
%% extensions) if not understood.
-
dec_hello_extensions(<<?UINT16(_), ?UINT16(Len), _Unknown:Len/binary, Rest/binary>>, Acc) ->
dec_hello_extensions(Rest, Acc);
%% This theoretically should not happen if the protocol is followed, but if it does it is ignored.
@@ -1962,6 +2028,15 @@ decode_alpn(undefined) ->
decode_alpn(#alpn{extension_data=Data}) ->
decode_protocols(Data, []).
+decode_versions(Versions) ->
+ decode_versions(Versions, []).
+%%
+decode_versions(<<>>, Acc) ->
+ lists:reverse(Acc);
+decode_versions(<<?BYTE(M),?BYTE(N),Rest/binary>>, Acc) ->
+ decode_versions(Rest, [{M,N}|Acc]).
+
+
decode_next_protocols({next_protocol_negotiation, Protocols}) ->
decode_protocols(Protocols, []).
@@ -2230,38 +2305,7 @@ sign_algo(Alg) ->
{_, Sign} =public_key:pkix_sign_types(Alg),
Sign.
-is_acceptable_hash_sign(Algos, _, _, KeyExAlgo, SupportedHashSigns) when
- KeyExAlgo == dh_dss;
- KeyExAlgo == dh_rsa;
- KeyExAlgo == ecdh_ecdsa;
- KeyExAlgo == ecdh_rsa;
- KeyExAlgo == ecdh_ecdsa
- ->
- %% *dh_* could be called only *dh in TLS-1.2
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign(Algos, rsa, ecdsa, ecdh_rsa, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign({_, rsa} = Algos, rsa, _, dhe_rsa, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign({_, rsa} = Algos, rsa, rsa, ecdhe_rsa, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign({_, rsa} = Algos, rsa, rsa, rsa, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign({_, rsa} = Algos, rsa, _, srp_rsa, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign({_, rsa} = Algos, rsa, _, rsa_psk, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign({_, dsa} = Algos, dsa, _, dhe_dss, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign({_, dsa} = Algos, dsa, _, srp_dss, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign({_, ecdsa} = Algos, ecdsa, _, dhe_ecdsa, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign({_, ecdsa} = Algos, ecdsa, ecdsa, ecdh_ecdsa, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign({_, ecdsa} = Algos, ecdsa, ecdsa, ecdhe_ecdsa, SupportedHashSigns) ->
- is_acceptable_hash_sign(Algos, SupportedHashSigns);
-is_acceptable_hash_sign(_, _, _, KeyExAlgo, _) when
+is_acceptable_hash_sign( _, KeyExAlgo, _) when
KeyExAlgo == psk;
KeyExAlgo == dhe_psk;
KeyExAlgo == ecdhe_psk;
@@ -2270,8 +2314,9 @@ is_acceptable_hash_sign(_, _, _, KeyExAlgo, _) when
KeyExAlgo == ecdhe_anon
->
true;
-is_acceptable_hash_sign(_,_, _,_,_) ->
- false.
+is_acceptable_hash_sign(Algos,_, SupportedHashSigns) ->
+ is_acceptable_hash_sign(Algos, SupportedHashSigns).
+
is_acceptable_hash_sign(Algos, SupportedHashSigns) ->
lists:member(Algos, SupportedHashSigns).
@@ -2464,13 +2509,7 @@ cert_curve(Cert, ECCCurve0, CipherSuite) ->
#'OTPSubjectPublicKeyInfo'{algorithm = AlgInfo}
= TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
{namedCurve, Oid} = AlgInfo#'PublicKeyAlgorithm'.parameters,
- try pubkey_cert_records:namedCurves(Oid) of
- Curve ->
- {{named_curve, Curve}, CipherSuite}
- catch
- _:_ ->
- {no_curve, no_suite}
- end;
+ {{namedCurve, Oid}, CipherSuite};
_ ->
{ECCCurve0, CipherSuite}
end.
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index a191fcf766..9cc6f570fc 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -105,7 +105,9 @@
srp,
ec_point_formats,
elliptic_curves,
- sni
+ sni,
+ client_hello_versions,
+ server_hello_selected_version
}).
-record(server_hello, {
@@ -377,4 +379,13 @@
hostname = undefined
}).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Supported Versions TLS 1.3 section 4.2.1
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(SUPPORTED_VERSIONS_EXT, 43).
+
+-record(client_hello_versions, {versions}).
+-record(server_hello_selected_version, {selected_version}).
+
-endif. % -ifdef(ssl_handshake).
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index 5df00de0e5..0d3093c1ae 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include_lib("public_key/include/public_key.hrl").
+-define(VSN, "8.2.6").
-define(SECRET_PRINTOUT, "***").
-type reason() :: term().
@@ -71,14 +72,39 @@
-define(FALSE, 1).
%% sslv3 is considered insecure due to lack of padding check (Poodle attack)
-%% Keep as interop with legacy software but do not support as default
--define(ALL_AVAILABLE_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1, sslv3]).
+%% Keep as interop with legacy software but do not support as default
+%% tlsv1.3 is under development (experimental).
+-define(ALL_AVAILABLE_VERSIONS, ['tlsv1.3', 'tlsv1.2', 'tlsv1.1', tlsv1, sslv3]).
-define(ALL_AVAILABLE_DATAGRAM_VERSIONS, ['dtlsv1.2', dtlsv1]).
+%% Defines the default versions when not specified by an ssl option.
-define(ALL_SUPPORTED_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1]).
-define(MIN_SUPPORTED_VERSIONS, ['tlsv1.1', tlsv1]).
+
+%% Versions allowed in TLSCiphertext.version (TLS 1.2 and prior) and
+%% TLSCiphertext.legacy_record_version (TLS 1.3).
+%% TLS 1.3 sets TLSCiphertext.legacy_record_version to 0x0303 for all records
+%% generated other than an than an initial ClientHello, where it MAY also be 0x0301.
+%% Thus, the allowed range is limited to 0x0300 - 0x0303.
+-define(ALL_TLS_RECORD_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1, sslv3]).
+
-define(ALL_DATAGRAM_SUPPORTED_VERSIONS, ['dtlsv1.2', dtlsv1]).
-define(MIN_DATAGRAM_SUPPORTED_VERSIONS, [dtlsv1]).
+%% TLS 1.3 - Section 4.1.3
+%%
+%% If negotiating TLS 1.2, TLS 1.3 servers MUST set the last eight bytes
+%% of their Random value to the bytes:
+%%
+%% 44 4F 57 4E 47 52 44 01
+%%
+%% If negotiating TLS 1.1 or below, TLS 1.3 servers MUST and TLS 1.2
+%% servers SHOULD set the last eight bytes of their Random value to the
+%% bytes:
+%%
+%% 44 4F 57 4E 47 52 44 00
+-define(RANDOM_OVERRIDE_TLS12, <<16#44,16#4F,16#57,16#4E,16#47,16#52,16#44,16#01>>).
+-define(RANDOM_OVERRIDE_TLS11, <<16#44,16#4F,16#57,16#4E,16#47,16#52,16#44,16#00>>).
+
-define('24H_in_msec', 86400000).
-define('24H_in_sec', 86400).
@@ -127,7 +153,7 @@
alpn_preferred_protocols = undefined :: [binary()] | undefined,
next_protocols_advertised = undefined :: [binary()] | undefined,
next_protocol_selector = undefined, %% fun([binary()]) -> binary())
- log_alert :: boolean(),
+ log_level = notice :: atom(),
server_name_indication = undefined,
sni_hosts :: [{inet:hostname(), [tuple()]}],
sni_fun :: function() | undefined,
@@ -145,7 +171,8 @@
eccs,
honor_ecc_order :: boolean(),
max_handshake_size :: integer(),
- handshake
+ handshake,
+ customize_hostname_check
}).
-record(socket_options,
@@ -160,7 +187,7 @@
-record(config, {ssl, %% SSL parameters
inet_user, %% User set inet options
emulated, %% Emulated option list or "inherit_tracker" pid
- udp_handler,
+ dtls_handler,
inet_ssl, %% inet options for internal ssl socket
transport_info, %% Callback info
connection_cb
@@ -179,6 +206,8 @@
-type gen_fsm_state_return() :: {next_state, state_name(), term()} |
{next_state, state_name(), term(), timeout()} |
{stop, term(), term()}.
+-type ssl_options() :: #ssl_options{}.
+
-endif. % -ifdef(ssl_internal).
diff --git a/lib/ssl/src/ssl_logger.erl b/lib/ssl/src/ssl_logger.erl
new file mode 100644
index 0000000000..35c8dcfd48
--- /dev/null
+++ b/lib/ssl/src/ssl_logger.erl
@@ -0,0 +1,349 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% 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(ssl_logger).
+
+-export([debug/3,
+ format/2,
+ notice/2]).
+
+-define(DEC2HEX(X),
+ if ((X) >= 0) andalso ((X) =< 9) -> (X) + $0;
+ ((X) >= 10) andalso ((X) =< 15) -> (X) + $a - 10
+ end).
+
+-define(rec_info(T,R),lists:zip(record_info(fields,T),tl(tuple_to_list(R)))).
+
+-include("tls_record.hrl").
+-include("ssl_internal.hrl").
+-include("tls_handshake.hrl").
+-include_lib("kernel/include/logger.hrl").
+
+%%-------------------------------------------------------------------------
+%% External API
+%%-------------------------------------------------------------------------
+
+%% SSL log formatter
+format(#{level:= _Level, msg:= {report, Msg}, meta:= _Meta}, _Config0) ->
+ #{direction := Direction,
+ protocol := Protocol,
+ message := BinMsg0} = Msg,
+ case Protocol of
+ 'tls_record' ->
+ BinMsg = lists:flatten(BinMsg0),
+ format_tls_record(Direction, BinMsg);
+ 'handshake' ->
+ format_handshake(Direction, BinMsg0);
+ _Other ->
+ []
+ end.
+
+%% Stateful logging
+debug(Level, Report, Meta) ->
+ case logger:compare_levels(Level, debug) of
+ lt ->
+ ?LOG_DEBUG(Report, Meta);
+ eq ->
+ ?LOG_DEBUG(Report, Meta);
+ _ ->
+ ok
+ end.
+
+%% Stateful logging
+notice(Level, Report) ->
+ case logger:compare_levels(Level, notice) of
+ lt ->
+ ?LOG_NOTICE(Report);
+ eq ->
+ ?LOG_NOTICE(Report);
+ _ ->
+ ok
+ end.
+
+
+%%-------------------------------------------------------------------------
+%% Handshake Protocol
+%%-------------------------------------------------------------------------
+format_handshake(Direction, BinMsg) ->
+ {Header, Message} = parse_handshake(Direction, BinMsg),
+ io_lib:format("~s~n~s~n", [Header, Message]).
+
+
+parse_handshake(Direction, #client_hello{
+ client_version = Version
+ } = ClientHello) ->
+ Header = io_lib:format("~s ~s Handshake, ClientHello",
+ [header_prefix(Direction),
+ version(Version)]),
+ Message = io_lib:format("~p", [?rec_info(client_hello, ClientHello)]),
+ {Header, Message};
+parse_handshake(Direction, #server_hello{
+ server_version = Version
+ } = ServerHello) ->
+ Header = io_lib:format("~s ~s Handshake, ServerHello",
+ [header_prefix(Direction),
+ version(Version)]),
+ Message = io_lib:format("~p", [?rec_info(server_hello, ServerHello)]),
+ {Header, Message};
+parse_handshake(Direction, #certificate{} = Certificate) ->
+ Header = io_lib:format("~s Handshake, Certificate",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(certificate, Certificate)]),
+ {Header, Message};
+parse_handshake(Direction, #server_key_exchange{} = ServerKeyExchange) ->
+ Header = io_lib:format("~s Handshake, ServerKeyExchange",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(server_key_exchange, ServerKeyExchange)]),
+ {Header, Message};
+parse_handshake(Direction, #server_key_params{} = ServerKeyExchange) ->
+ Header = io_lib:format("~s Handshake, ServerKeyExchange",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(server_key_params, ServerKeyExchange)]),
+ {Header, Message};
+parse_handshake(Direction, #certificate_request{} = CertificateRequest) ->
+ Header = io_lib:format("~s Handshake, CertificateRequest",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(certificate_request, CertificateRequest)]),
+ {Header, Message};
+parse_handshake(Direction, #server_hello_done{} = ServerHelloDone) ->
+ Header = io_lib:format("~s Handshake, ServerHelloDone",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(server_hello_done, ServerHelloDone)]),
+ {Header, Message};
+parse_handshake(Direction, #client_key_exchange{} = ClientKeyExchange) ->
+ Header = io_lib:format("~s Handshake, ClientKeyExchange",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(client_key_exchange, ClientKeyExchange)]),
+ {Header, Message};
+parse_handshake(Direction, #certificate_verify{} = CertificateVerify) ->
+ Header = io_lib:format("~s Handshake, CertificateVerify",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(certificate_verify, CertificateVerify)]),
+ {Header, Message};
+parse_handshake(Direction, #finished{} = Finished) ->
+ Header = io_lib:format("~s Handshake, Finished",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(finished, Finished)]),
+ {Header, Message};
+parse_handshake(Direction, #hello_request{} = HelloRequest) ->
+ Header = io_lib:format("~s Handshake, HelloRequest",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(hello_request, HelloRequest)]),
+ {Header, Message}.
+
+
+version({3,3}) ->
+ "TLS 1.2";
+version({3,2}) ->
+ "TLS 1.1";
+version({3,1}) ->
+ "TLS 1.0";
+version({3,0}) ->
+ "SSL 3.0";
+version({M,N}) ->
+ io_lib:format("TLS [0x0~B0~B]", [M,N]).
+
+
+header_prefix(inbound) ->
+ "<<<";
+header_prefix(outbound) ->
+ ">>>".
+
+
+%%-------------------------------------------------------------------------
+%% TLS Record Protocol
+%%-------------------------------------------------------------------------
+format_tls_record(Direction, BinMsg) ->
+ {Message, Size} = convert_to_hex('tls_record', BinMsg),
+ Header = io_lib:format("~s (~B bytes) ~s~n",
+ [header_prefix_tls_record(Direction),
+ Size,
+ tls_record_version(BinMsg)]),
+ Header ++ Message.
+
+
+header_prefix_tls_record(inbound) ->
+ "reading";
+header_prefix_tls_record(outbound) ->
+ "writing".
+
+
+tls_record_version([<<?BYTE(B),?BYTE(3),?BYTE(3),_/binary>>|_]) ->
+ io_lib:format("TLS 1.2 Record Protocol, ~s", [msg_type(B)]);
+tls_record_version([<<?BYTE(B),?BYTE(3),?BYTE(2),_/binary>>|_]) ->
+ io_lib:format("TLS 1.1 Record Protocol, ~s", [msg_type(B)]);
+tls_record_version([<<?BYTE(B),?BYTE(3),?BYTE(1),_/binary>>|_]) ->
+ io_lib:format("TLS 1.0 Record Protocol, ~s", [msg_type(B)]);
+tls_record_version([<<?BYTE(B),?BYTE(3),?BYTE(0),_/binary>>|_]) ->
+ io_lib:format("SSL 3.0 Record Protocol, ~s", [msg_type(B)]);
+tls_record_version([<<?BYTE(B),?BYTE(M),?BYTE(N),_/binary>>|_]) ->
+ io_lib:format("TLS [0x0~B0~B] Record Protocol, ~s", [M, N, msg_type(B)]).
+
+
+msg_type(20) -> "change_cipher_spec";
+msg_type(21) -> "alert";
+msg_type(22) -> "handshake";
+msg_type(23) -> "application_data";
+msg_type(_) -> unknown.
+
+
+%%-------------------------------------------------------------------------
+%% Hex encoding functions
+%%-------------------------------------------------------------------------
+convert_to_hex(Protocol, BinMsg) ->
+ convert_to_hex(Protocol, BinMsg, [], [], 0).
+%%
+convert_to_hex(P, [], Row0, Acc, C) when C rem 16 =:= 0 ->
+ Row = lists:reverse(end_row(P, Row0)),
+ {lists:reverse(Acc) ++ Row ++ io_lib:nl(), C};
+convert_to_hex(P, [], Row0, Acc, C) ->
+ Row = lists:reverse(end_row(P, Row0)),
+ Padding = calculate_padding(Row0, Acc),
+ PaddedRow = string:pad(Row, Padding, leading, $ ),
+ {lists:reverse(Acc) ++ PaddedRow ++ io_lib:nl(), C};
+convert_to_hex(P, [H|T], Row, Acc, C) when is_list(H) ->
+ convert_to_hex(P, H ++ T, Row, Acc, C);
+convert_to_hex(P, [<<>>|T], Row, Acc, C) ->
+ convert_to_hex(P, T, Row, Acc, C);
+
+%% First line
+convert_to_hex(P, [<<A:4,B:4,R/binary>>|T], Row, Acc, C) when C =:= 0 ->
+ convert_to_hex(P, [<<R/binary>>|T],
+ update_row(<<A:4,B:4>>, Row),
+ prepend_first_row(P, A, B, Acc, C),
+ C + 1);
+%% New line
+convert_to_hex(P, [<<A:4,B:4,R/binary>>|T], Row, Acc, C) when C rem 16 =:= 0 ->
+ convert_to_hex(P, [<<R/binary>>|T],
+ update_row(<<A:4,B:4>>, []),
+ prepend_row(P, A, B, Row, Acc, C),
+ C + 1);
+%% Add 8th hex with extra whitespace
+%% 0000 - 16 03 02 00 bd 01 00 00 b9 ...
+%% ^^^^
+convert_to_hex(P, [<<A:4,B:4,R/binary>>|T], Row, Acc, C) when C rem 8 =:= 7 ->
+ convert_to_hex(P, [<<R/binary>>|T],
+ update_row(<<A:4,B:4>>, Row),
+ prepend_eighths_hex(A, B, Acc),
+ C + 1);
+convert_to_hex(P, [<<A:4,B:4,R/binary>>|T], Row, Acc, C) ->
+ convert_to_hex(P, [<<R/binary>>|T],
+ update_row(<<A:4,B:4>>, Row),
+ prepend_hex(A, B, Acc),
+ C + 1);
+%% First line
+convert_to_hex(P, [H|T], Row, Acc, C) when is_integer(H), C =:= 0 ->
+ convert_to_hex(P, T,
+ update_row(H, Row),
+ prepend_first_row(P, H, Acc, C),
+ C + 1);
+%% New line
+convert_to_hex(P, [H|T], Row, Acc, C) when is_integer(H), C rem 16 =:= 0 ->
+ convert_to_hex(P, T,
+ update_row(H, []),
+ prepend_row(P, H, Row, Acc, C),
+ C + 1);
+%% Add 8th hex with extra whitespace
+%% 0000 - 16 03 02 00 bd 01 00 00 b9 ...
+%% ^^^^
+convert_to_hex(P, [H|T], Row, Acc, C) when is_integer(H), C rem 8 =:= 7 ->
+ convert_to_hex(P, T,
+ update_row(H, Row),
+ prepend_eighths_hex(H, Acc),
+ C + 1);
+convert_to_hex(P, [H|T], Row, Acc, C) when is_integer(H) ->
+ convert_to_hex(P, T,
+ update_row(H, Row),
+ prepend_hex(H, Acc),
+ C + 1).
+
+
+row_prefix(tls_record, N) ->
+ S = string:pad(string:to_lower(erlang:integer_to_list(N, 16)),4,leading,$0),
+ lists:reverse(lists:flatten(S ++ " - ")).
+
+
+end_row(tls_record, Row) ->
+ Row ++ " ".
+
+
+%% Calculate padding of the "printable character" lines in order to be
+%% visually aligned.
+calculate_padding(Row, Acc) ->
+ %% Number of new line characters
+ NNL = (length(Acc) div 75) * length(io_lib:nl()),
+ %% Length of the last printed line
+ Length = (length(Acc) - NNL) rem 75,
+ %% Adjusted length of the last printed line
+ PaddedLength = 75 - (16 - length(Row)), %% Length
+ %% Padding
+ PaddedLength - Length.
+
+
+%%-------------------------------------------------------------------------
+%% Functions operating on reversed lists
+%%-------------------------------------------------------------------------
+update_row(B, Row) when is_binary(B) ->
+ case binary_to_list(B) of
+ [C] when 32 =< C, C =< 126 ->
+ [C|Row];
+ _Else ->
+ [$.|Row]
+ end;
+update_row(C, Row) when 32 =< C, C =< 126 ->
+ [C|Row];
+update_row(_, Row) ->
+ [$.|Row].
+
+
+prepend_first_row(P, A, B, Acc, C) ->
+ prepend_hex(A, B,row_prefix(P, C) ++ Acc).
+%%
+prepend_first_row(P, N, Acc, C) ->
+ prepend_hex(N,row_prefix(P, C) ++ Acc).
+
+prepend_row(P, A, B, Row, Acc, C) ->
+ prepend_hex(A, B,row_prefix(P, C) ++ io_lib:nl() ++ end_row(P, Row) ++ Acc).
+%%
+prepend_row(P, N, Row, Acc, C) ->
+ prepend_hex(N,row_prefix(P, C) ++ io_lib:nl() ++ end_row(P, Row) ++ Acc).
+
+
+
+prepend_hex(A, B, Acc) ->
+ [$ ,?DEC2HEX(B),?DEC2HEX(A)|Acc].
+%%
+prepend_hex(N, Acc) ->
+ " " ++ number_to_hex(N) ++ Acc.
+
+
+prepend_eighths_hex(A, B, Acc) ->
+ [$ ,$ ,?DEC2HEX(B),?DEC2HEX(A)|Acc].
+%%
+prepend_eighths_hex(N, Acc) ->
+ " " ++ number_to_hex(N) ++ Acc.
+
+number_to_hex(N) ->
+ case string:to_lower(erlang:integer_to_list(N, 16)) of
+ H when length(H) < 2 ->
+ lists:append(H, "0");
+ H ->
+ lists:reverse(H)
+ end.
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index f44fe6a2bf..b3a425b2fe 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -127,7 +127,13 @@ cache_pem_file(File, DbHandle) ->
[Content] ->
{ok, Content};
undefined ->
- ssl_pem_cache:insert(File)
+ case ssl_pkix_db:decode_pem_file(File) of
+ {ok, Content} ->
+ ssl_pem_cache:insert(File, Content),
+ {ok, Content};
+ Error ->
+ Error
+ end
end.
%%--------------------------------------------------------------------
@@ -499,10 +505,10 @@ last_delay_timer({{_,_},_}, TRef, {LastServer, _}) ->
last_delay_timer({_,_}, TRef, {_, LastClient}) ->
{TRef, LastClient}.
-%% If we can not generate a not allready in use session ID in
+%% If we cannot generate a not allready in use session ID in
%% ?GEN_UNIQUE_ID_MAX_TRIES we make the new session uncacheable The
%% value of ?GEN_UNIQUE_ID_MAX_TRIES is stolen from open SSL which
-%% states : "If we can not find a session id in
+%% states : "If we cannot find a session id in
%% ?GEN_UNIQUE_ID_MAX_TRIES either the RAND code is broken or someone
%% is trying to open roughly very close to 2^128 (or 2^256) SSL
%% sessions to our server"
@@ -513,7 +519,7 @@ new_id(Port, Tries, Cache, CacheCb) ->
case CacheCb:lookup(Cache, {Port, Id}) of
undefined ->
Now = erlang:monotonic_time(),
- %% New sessions can not be set to resumable
+ %% New sessions cannot be set to resumable
%% until handshake is compleate and the
%% other session values are set.
CacheCb:update(Cache, {Port, Id}, #session{session_id = Id,
diff --git a/lib/ssl/src/ssl_pem_cache.erl b/lib/ssl/src/ssl_pem_cache.erl
index 115ab4451d..a952e20133 100644
--- a/lib/ssl/src/ssl_pem_cache.erl
+++ b/lib/ssl/src/ssl_pem_cache.erl
@@ -29,7 +29,7 @@
-export([start_link/1,
start_link_dist/1,
name/1,
- insert/1,
+ insert/2,
clear/0]).
% Spawn export
@@ -90,19 +90,17 @@ start_link_dist(_) ->
%%--------------------------------------------------------------------
--spec insert(binary()) -> {ok, term()} | {error, reason()}.
+-spec insert(binary(), term()) -> ok | {error, reason()}.
%%
%% Description: Cache a pem file and return its content.
%%--------------------------------------------------------------------
-insert(File) ->
- {ok, PemBin} = file:read_file(File),
- Content = public_key:pem_decode(PemBin),
+insert(File, Content) ->
case bypass_cache() of
true ->
- {ok, Content};
+ ok;
false ->
cast({cache_pem, File, Content}),
- {ok, Content}
+ ok
end.
%%--------------------------------------------------------------------
diff --git a/lib/ssl/src/ssl_pkix_db.erl b/lib/ssl/src/ssl_pkix_db.erl
index 8828c3a0d8..e7e4af942a 100644
--- a/lib/ssl/src/ssl_pkix_db.erl
+++ b/lib/ssl/src/ssl_pkix_db.erl
@@ -27,6 +27,7 @@
-include("ssl_internal.hrl").
-include_lib("public_key/include/public_key.hrl").
-include_lib("kernel/include/file.hrl").
+-include_lib("kernel/include/logger.hrl").
-export([create/1, create_pem_cache/1,
add_crls/3, remove_crls/2, remove/1, add_trusted_certs/3,
@@ -157,7 +158,7 @@ extract_trusted_certs(File) ->
{error, {badmatch, Error}}
end.
--spec decode_pem_file(binary()) -> {ok, term()}.
+-spec decode_pem_file(binary()) -> {ok, term()} | {error, term()}.
decode_pem_file(File) ->
case file:read_file(File) of
{ok, PemBin} ->
@@ -311,16 +312,21 @@ decode_certs(Ref, Cert) ->
error:_ ->
Report = io_lib:format("SSL WARNING: Ignoring a CA cert as "
"it could not be correctly decoded.~n", []),
- error_logger:info_report(Report),
+ ?LOG_NOTICE(Report),
undefined
end.
new_trusted_cert_entry(File, [CertsDb, RefsDb, _ | _]) ->
- Ref = make_ref(),
- init_ref_db(Ref, File, RefsDb),
- {ok, Content} = ssl_pem_cache:insert(File),
- add_certs_from_pem(Content, Ref, CertsDb),
- {ok, Ref}.
+ case decode_pem_file(File) of
+ {ok, Content} ->
+ Ref = make_ref(),
+ init_ref_db(Ref, File, RefsDb),
+ ok = ssl_pem_cache:insert(File, Content),
+ add_certs_from_pem(Content, Ref, CertsDb),
+ {ok, Ref};
+ Error ->
+ Error
+ end.
add_crls([_,_,_, {_, Mapping} | _], ?NO_DIST_POINT, CRLs) ->
[add_crls(CRL, Mapping) || CRL <- CRLs];
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index c0eee466ae..659e1485ac 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl
index ed007f58d7..e8ce50040f 100644
--- a/lib/ssl/src/ssl_record.hrl
+++ b/lib/ssl/src/ssl_record.hrl
@@ -74,7 +74,7 @@
-define(INITIAL_BYTES, 5).
-define(MAX_SEQENCE_NUMBER, 18446744073709551615). %% (1 bsl 64) - 1 = 18446744073709551615
-%% Sequence numbers can not wrap so when max is about to be reached we should renegotiate.
+%% Sequence numbers cannot wrap so when max is about to be reached we should renegotiate.
%% We will renegotiate a little before so that there will be sequence numbers left
%% for the rehandshake and a little data. Currently we decided to renegotiate a little more
%% often as we can have a cheaper test to check if it is time to renegotiate. It will still
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index ef84c5320e..8320d3f7f3 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -38,7 +38,8 @@
-include("ssl_api.hrl").
-include("ssl_internal.hrl").
-include("ssl_srp.hrl").
--include_lib("public_key/include/public_key.hrl").
+-include_lib("public_key/include/public_key.hrl").
+-include_lib("kernel/include/logger.hrl").
%% Internal application API
@@ -111,12 +112,13 @@ start_link(Role, Host, Port, Socket, Options, User, CbInfo) ->
init([Role, Host, Port, Socket, Options, User, CbInfo]) ->
process_flag(trap_exit, true),
- State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo),
+ State0 = #state{protocol_specific = Map} = initial_state(Role, Host, Port, Socket, Options, User, CbInfo),
try
State = ssl_connection:ssl_config(State0#state.ssl_options, Role, State0),
gen_statem:enter_loop(?MODULE, [], init, State)
catch throw:Error ->
- gen_statem:enter_loop(?MODULE, [], error, {Error, State0})
+ EState = State0#state{protocol_specific = Map#{error => Error}},
+ gen_statem:enter_loop(?MODULE, [], error, EState)
end.
%%====================================================================
%% State transition handling
@@ -129,6 +131,7 @@ next_record(#state{protocol_buffers =
= Buffers,
connection_states = ConnStates0,
ssl_options = #ssl_options{padding_check = Check}} = State) ->
+
case tls_record:decode_cipher_text(CT, ConnStates0, Check) of
{Plain, ConnStates} ->
{Plain, State#state{protocol_buffers =
@@ -264,9 +267,19 @@ send_handshake(Handshake, State) ->
queue_handshake(Handshake, #state{negotiated_version = Version,
tls_handshake_history = Hist0,
flight_buffer = Flight0,
- connection_states = ConnectionStates0} = State0) ->
+ connection_states = ConnectionStates0,
+ ssl_options = SslOpts} = State0) ->
{BinHandshake, ConnectionStates, Hist} =
encode_handshake(Handshake, Version, ConnectionStates0, Hist0),
+ Report = #{direction => outbound,
+ protocol => 'tls_record',
+ message => BinHandshake},
+ HandshakeMsg = #{direction => outbound,
+ protocol => 'handshake',
+ message => Handshake},
+ ssl_logger:debug(SslOpts#ssl_options.log_level, HandshakeMsg, #{domain => [otp,ssl,handshake]}),
+ ssl_logger:debug(SslOpts#ssl_options.log_level, Report, #{domain => [otp,ssl,tls_record]}),
+
State0#state{connection_states = ConnectionStates,
tls_handshake_history = Hist,
flight_buffer = Flight0 ++ [BinHandshake]}.
@@ -278,10 +291,15 @@ send_handshake_flight(#state{socket = Socket,
{State0#state{flight_buffer = []}, []}.
queue_change_cipher(Msg, #state{negotiated_version = Version,
- flight_buffer = Flight0,
- connection_states = ConnectionStates0} = State0) ->
+ flight_buffer = Flight0,
+ connection_states = ConnectionStates0,
+ ssl_options = SslOpts} = State0) ->
{BinChangeCipher, ConnectionStates} =
encode_change_cipher(Msg, Version, ConnectionStates0),
+ Report = #{direction => outbound,
+ protocol => 'tls_record',
+ message => BinChangeCipher},
+ ssl_logger:debug(SslOpts#ssl_options.log_level, Report, #{domain => [otp,ssl,tls_record]}),
State0#state{connection_states = ConnectionStates,
flight_buffer = Flight0 ++ [BinChangeCipher]}.
@@ -309,10 +327,16 @@ empty_connection_state(ConnectionEnd, BeastMitigation) ->
send_alert(Alert, #state{negotiated_version = Version,
socket = Socket,
transport_cb = Transport,
- connection_states = ConnectionStates0} = State0) ->
+ connection_states = ConnectionStates0,
+ ssl_options = SslOpts} = State0) ->
{BinMsg, ConnectionStates} =
encode_alert(Alert, Version, ConnectionStates0),
+
send(Transport, Socket, BinMsg),
+ Report = #{direction => outbound,
+ protocol => 'tls_record',
+ message => BinMsg},
+ ssl_logger:debug(SslOpts#ssl_options.log_level, Report, #{domain => [otp,ssl,tls_record]}),
State0#state{connection_states = ConnectionStates}.
%%--------------------------------------------------------------------
@@ -415,6 +439,14 @@ init({call, From}, {start, Timeout},
{BinMsg, ConnectionStates, Handshake} =
encode_handshake(Hello, HelloVersion, ConnectionStates0, Handshake0),
send(Transport, Socket, BinMsg),
+ Report = #{direction => outbound,
+ protocol => 'tls_record',
+ message => BinMsg},
+ HelloMsg = #{direction => outbound,
+ protocol => 'handshake',
+ message => Hello},
+ ssl_logger:debug(SslOpts#ssl_options.log_level, HelloMsg, #{domain => [otp,ssl,handshake]}),
+ ssl_logger:debug(SslOpts#ssl_options.log_level, Report, #{domain => [otp,ssl,tls_record]}),
State1 = State0#state{connection_states = ConnectionStates,
negotiated_version = Version, %% Requested version
session =
@@ -432,17 +464,12 @@ init(Type, Event, State) ->
{start, timeout()} | term(), #state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
-
-error({call, From}, {start, _Timeout}, {Error, State}) ->
- ssl_connection:stop_and_reply(
- normal, {reply, From, {error, Error}}, State);
error({call, From}, {start, _Timeout},
#state{protocol_specific = #{error := Error}} = State) ->
ssl_connection:stop_and_reply(
normal, {reply, From, {error, Error}}, State);
-error({call, _} = Call, Msg, {Error, #state{protocol_specific = Map} = State}) ->
- gen_handshake(?FUNCTION_NAME, Call, Msg,
- State#state{protocol_specific = Map#{error => Error}});
+error({call, _} = Call, Msg, State) ->
+ gen_handshake(?FUNCTION_NAME, Call, Msg, State);
error(_, _, _) ->
{keep_state_and_data, [postpone]}.
@@ -651,11 +678,11 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, Tracker}, Us
next_tls_record(Data, StateName, #state{protocol_buffers =
#protocol_buffers{tls_record_buffer = Buf0,
- tls_cipher_texts = CT0} = Buffers}
- = State0) ->
- case tls_record:get_tls_records(Data,
+ tls_cipher_texts = CT0} = Buffers,
+ ssl_options = SslOpts} = State0) ->
+ case tls_record:get_tls_records(Data,
acceptable_record_versions(StateName, State0),
- Buf0) of
+ Buf0, SslOpts) of
{Records, Buf1} ->
CT1 = CT0 ++ Records,
next_record(State0#state{protocol_buffers =
@@ -666,10 +693,18 @@ next_tls_record(Data, StateName, #state{protocol_buffers =
end.
+%% TLS 1.3 Client/Server
+%% - Ignore TLSPlaintext.legacy_record_version
+%% - Verify that TLSCiphertext.legacy_record_version is set to 0x0303 for all records
+%% other than an initial ClientHello, where it MAY also be 0x0301.
acceptable_record_versions(hello, _) ->
- [tls_record:protocol_version(Vsn) || Vsn <- ?ALL_AVAILABLE_VERSIONS];
+ [tls_record:protocol_version(Vsn) || Vsn <- ?ALL_TLS_RECORD_VERSIONS];
+acceptable_record_versions(_, #state{negotiated_version = {Major, Minor}})
+ when Major > 3; Major =:= 3, Minor >= 4 ->
+ [{3, 3}];
acceptable_record_versions(_, #state{negotiated_version = Version}) ->
[Version].
+
handle_record_alert(Alert, _) ->
Alert.
diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl
index 0058b9c8ae..2ad1386900 100644
--- a/lib/ssl/src/tls_handshake.erl
+++ b/lib/ssl/src/tls_handshake.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
-include("ssl_internal.hrl").
-include("ssl_cipher.hrl").
-include_lib("public_key/include/public_key.hrl").
+-include_lib("kernel/include/logger.hrl").
%% Handshake handling
-export([client_hello/8, hello/4]).
@@ -60,6 +61,18 @@ client_hello(Host, Port, ConnectionStates,
} = SslOpts,
Cache, CacheCb, Renegotiation, OwnCert) ->
Version = tls_record:highest_protocol_version(Versions),
+
+ %% In TLS 1.3, the client indicates its version preferences in the
+ %% "supported_versions" extension (Section 4.2.1) and the
+ %% legacy_version field MUST be set to 0x0303, which is the version
+ %% number for TLS 1.2.
+ LegacyVersion =
+ case tls_record:is_higher(Version, {3,2}) of
+ true ->
+ {3,3};
+ false ->
+ Version
+ end,
#{security_parameters := SecParams} =
ssl_record:pending_connection_state(ConnectionStates, read),
AvailableCipherSuites = ssl_handshake:available_suites(UserSuites, Version),
@@ -70,7 +83,7 @@ client_hello(Host, Port, ConnectionStates,
CipherSuites = ssl_handshake:cipher_suites(AvailableCipherSuites, Renegotiation, Fallback),
Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
#client_hello{session_id = Id,
- client_version = Version,
+ client_version = LegacyVersion,
cipher_suites = CipherSuites,
compression_methods = ssl_record:compressions(),
random = SecParams#security_parameters.client_random,
@@ -92,6 +105,65 @@ client_hello(Host, Port, ConnectionStates,
%%
%% Description: Handles a received hello message
%%--------------------------------------------------------------------
+
+
+%% TLS 1.3 - Section 4.1.3
+%% TLS 1.3 clients receiving a ServerHello indicating TLS 1.2 or below
+%% MUST check that the last eight bytes are not equal to either of these
+%% values.
+hello(#server_hello{server_version = {Major, Minor},
+ random = <<_:24/binary,Down:8/binary>>},
+ #ssl_options{versions = [{M,N}|_]}, _, _)
+ when (M > 3 orelse M =:= 3 andalso N >= 4) andalso %% TLS 1.3 client
+ (Major =:= 3 andalso Minor =:= 3 andalso %% Negotiating TLS 1.2
+ Down =:= ?RANDOM_OVERRIDE_TLS12) orelse
+
+ (M > 3 orelse M =:= 3 andalso N >= 4) andalso %% TLS 1.3 client
+ (Major =:= 3 andalso Minor < 3 andalso %% Negotiating TLS 1.1 or prior
+ Down =:= ?RANDOM_OVERRIDE_TLS11) ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+
+%% TLS 1.2 clients SHOULD also check that the last eight bytes are not
+%% equal to the second value if the ServerHello indicates TLS 1.1 or below.
+hello(#server_hello{server_version = {Major, Minor},
+ random = <<_:24/binary,Down:8/binary>>},
+ #ssl_options{versions = [{M,N}|_]}, _, _)
+ when (M =:= 3 andalso N =:= 3) andalso %% TLS 1.2 client
+ (Major =:= 3 andalso Minor < 3 andalso %% Negotiating TLS 1.1 or prior
+ Down =:= ?RANDOM_OVERRIDE_TLS11) ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+
+
+%% TLS 1.3 - 4.2.1. Supported Versions
+%% If the "supported_versions" extension in the ServerHello contains a
+%% version not offered by the client or contains a version prior to TLS
+%% 1.3, the client MUST abort the handshake with an "illegal_parameter"
+%% alert.
+%%--------------------------------------------------------------------
+%% TLS 1.2 Client
+%%
+%% - If "supported_version" is present (ServerHello):
+%% - Abort handshake with an "illegal_parameter" alert
+hello(#server_hello{server_version = Version,
+ extensions = #hello_extensions{
+ server_hello_selected_version =
+ #server_hello_selected_version{selected_version = Version}
+ }},
+ #ssl_options{versions = SupportedVersions},
+ _ConnectionStates0, _Renegotiation) ->
+ case tls_record:is_higher({3,4}, Version) of
+ true ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+ false ->
+ case tls_record:is_acceptable_version(Version, SupportedVersions) of
+ true ->
+ %% Implement TLS 1.3 statem ???
+ ?ALERT_REC(?FATAL, ?PROTOCOL_VERSION);
+ false ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end
+ end;
+
hello(#server_hello{server_version = Version, random = Random,
cipher_suite = CipherSuite,
compression_method = Compression,
@@ -106,6 +178,37 @@ hello(#server_hello{server_version = Version, random = Random,
false ->
?ALERT_REC(?FATAL, ?PROTOCOL_VERSION)
end;
+
+
+%% TLS 1.2 Server
+%% - If "supported_versions" is present (ClientHello):
+%% - Select version from "supported_versions" (ignore ClientHello.legacy_version)
+%% - If server only supports versions greater than "supported_versions":
+%% - Abort handshake with a "protocol_version" alert (*)
+%% - If "supported_versions" is absent (ClientHello):
+%% - Negotiate the minimum of ClientHello.legacy_version and TLS 1.2 (**)
+%% - If server only supports versions greater than ClientHello.legacy_version:
+%% - Abort handshake with a "protocol_version" alert
+%%
+%% (*) Sends alert even if there is a gap in supported versions
+%% e.g. Server 1.0,1.2 Client 1.1,1.3
+%% (**) Current implementation can negotiate a version not supported by the client
+%% e.g. Server 1.0,1.2 Client 1.1 -> ServerHello 1.0
+hello(#client_hello{client_version = _ClientVersion,
+ cipher_suites = CipherSuites,
+ extensions = #hello_extensions{
+ client_hello_versions =
+ #client_hello_versions{versions = ClientVersions}
+ }} = Hello,
+ #ssl_options{versions = Versions} = SslOpts,
+ Info, Renegotiation) ->
+ try
+ Version = ssl_handshake:select_supported_version(ClientVersions, Versions),
+ do_hello(Version, Versions, CipherSuites, Hello, SslOpts, Info, Renegotiation)
+ catch
+ _:_ ->
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, malformed_handshake_data)
+ end;
hello(#client_hello{client_version = ClientVersion,
cipher_suites = CipherSuites} = Hello,
@@ -113,19 +216,11 @@ hello(#client_hello{client_version = ClientVersion,
Info, Renegotiation) ->
try
Version = ssl_handshake:select_version(tls_record, ClientVersion, Versions),
- case ssl_cipher:is_fallback(CipherSuites) of
- true ->
- Highest = tls_record:highest_protocol_version(Versions),
- case tls_record:is_higher(Highest, Version) of
- true ->
- ?ALERT_REC(?FATAL, ?INAPPROPRIATE_FALLBACK);
- false ->
- handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation)
- end;
- false ->
- handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation)
- end
+ do_hello(Version, Versions, CipherSuites, Hello, SslOpts, Info, Renegotiation)
catch
+ error:{case_clause,{asn1, Asn1Reason}} ->
+ %% ASN-1 decode of certificate somehow failed
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {failed_to_decode_own_certificate, Asn1Reason});
_:_ ->
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, malformed_handshake_data)
end.
@@ -241,6 +336,31 @@ handle_server_hello_extensions(Version, SessionId, Random, CipherSuite,
{ConnectionStates, ProtoExt, Protocol} ->
{Version, SessionId, ConnectionStates, ProtoExt, Protocol}
end.
+
+
+do_hello(undefined, _Versions, _CipherSuites, _Hello, _SslOpts, _Info, _Renegotiation) ->
+ ?ALERT_REC(?FATAL, ?PROTOCOL_VERSION);
+do_hello(Version, Versions, CipherSuites, Hello, SslOpts, Info, Renegotiation) ->
+ case tls_record:is_higher({3,4}, Version) of
+ true -> %% TLS 1.2 and older
+ case ssl_cipher:is_fallback(CipherSuites) of
+ true ->
+ Highest = tls_record:highest_protocol_version(Versions),
+ case tls_record:is_higher(Highest, Version) of
+ true ->
+ ?ALERT_REC(?FATAL, ?INAPPROPRIATE_FALLBACK);
+ false ->
+ handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation)
+ end;
+ false ->
+ handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation)
+ end;
+ false ->
+ %% Implement TLS 1.3 statem ???
+ ?ALERT_REC(?FATAL, ?PROTOCOL_VERSION)
+ end.
+
+
%%--------------------------------------------------------------------
enc_handshake(#hello_request{}, _Version) ->
{?HELLO_REQUEST, <<>>};
@@ -272,6 +392,10 @@ get_tls_handshake_aux(Version, <<?BYTE(Type), ?UINT24(Length),
Raw = <<?BYTE(Type), ?UINT24(Length), Body/binary>>,
try decode_handshake(Version, Type, Body) of
Handshake ->
+ Report = #{direction => inbound,
+ protocol => 'handshake',
+ message => Handshake},
+ ssl_logger:debug(Opts#ssl_options.log_level, Report, #{domain => [otp,ssl,handshake]}),
get_tls_handshake_aux(Version, Rest, Opts, [{Handshake,Raw} | Acc])
catch
_:_ ->
diff --git a/lib/ssl/src/tls_record.erl b/lib/ssl/src/tls_record.erl
index aa70508f1e..444759aafa 100644
--- a/lib/ssl/src/tls_record.erl
+++ b/lib/ssl/src/tls_record.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,9 +30,10 @@
-include("ssl_alert.hrl").
-include("tls_handshake.hrl").
-include("ssl_cipher.hrl").
+-include_lib("kernel/include/logger.hrl").
%% Handling of incoming data
--export([get_tls_records/3, init_connection_states/2]).
+-export([get_tls_records/4, init_connection_states/2]).
%% Encoding TLS records
-export([encode_handshake/3, encode_alert_record/3,
@@ -75,24 +76,24 @@ init_connection_states(Role, BeastMitigation) ->
pending_write => Pending}.
%%--------------------------------------------------------------------
--spec get_tls_records(binary(), [tls_version()], binary()) -> {[binary()], binary()} | #alert{}.
+-spec get_tls_records(binary(), [tls_version()], binary(), ssl_options()) -> {[binary()], binary()} | #alert{}.
%%
%% and returns it as a list of tls_compressed binaries also returns leftover
%% Description: Given old buffer and new data from TCP, packs up a records
%% data
%%--------------------------------------------------------------------
-get_tls_records(Data, Versions, Buffer) ->
+get_tls_records(Data, Versions, Buffer, SslOpts) ->
BinData = list_to_binary([Buffer, Data]),
case erlang:byte_size(BinData) of
N when N >= 3 ->
case assert_version(BinData, Versions) of
true ->
- get_tls_records_aux(BinData, []);
+ get_tls_records_aux(BinData, [], SslOpts);
false ->
?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
end;
_ ->
- get_tls_records_aux(BinData, [])
+ get_tls_records_aux(BinData, [], SslOpts)
end.
%%====================================================================
@@ -229,6 +230,8 @@ decode_cipher_text(#ssl_tls{type = Type, version = Version,
%% Description: Creates a protocol version record from a version atom
%% or vice versa.
%%--------------------------------------------------------------------
+protocol_version('tlsv1.3') ->
+ {3, 4};
protocol_version('tlsv1.2') ->
{3, 3};
protocol_version('tlsv1.1') ->
@@ -239,6 +242,8 @@ protocol_version(sslv3) ->
{3, 0};
protocol_version(sslv2) -> %% Backwards compatibility
{2, 0};
+protocol_version({3, 4}) ->
+ 'tlsv1.3';
protocol_version({3, 3}) ->
'tlsv1.2';
protocol_version({3, 2}) ->
@@ -399,33 +404,61 @@ assert_version(<<?BYTE(_), ?BYTE(MajVer), ?BYTE(MinVer), _/binary>>, Versions) -
get_tls_records_aux(<<?BYTE(?APPLICATION_DATA),?BYTE(MajVer),?BYTE(MinVer),
?UINT16(Length), Data:Length/binary, Rest/binary>>,
- Acc) ->
+ Acc, SslOpts) ->
+ RawTLSRecord = <<?BYTE(?APPLICATION_DATA),?BYTE(MajVer),?BYTE(MinVer),
+ ?UINT16(Length), Data:Length/binary>>,
+ Report = #{direction => inbound,
+ protocol => 'tls_record',
+ message => [RawTLSRecord]},
+ ssl_logger:debug(SslOpts#ssl_options.log_level, Report, #{domain => [otp,ssl,tls_record]}),
get_tls_records_aux(Rest, [#ssl_tls{type = ?APPLICATION_DATA,
version = {MajVer, MinVer},
- fragment = Data} | Acc]);
+ fragment = Data} | Acc],
+ SslOpts);
get_tls_records_aux(<<?BYTE(?HANDSHAKE),?BYTE(MajVer),?BYTE(MinVer),
- ?UINT16(Length),
- Data:Length/binary, Rest/binary>>, Acc) ->
+ ?UINT16(Length),
+ Data:Length/binary, Rest/binary>>, Acc, SslOpts) ->
+ RawTLSRecord = <<?BYTE(?HANDSHAKE),?BYTE(MajVer),?BYTE(MinVer),
+ ?UINT16(Length), Data:Length/binary>>,
+ Report = #{direction => inbound,
+ protocol => 'tls_record',
+ message => [RawTLSRecord]},
+ ssl_logger:debug(SslOpts#ssl_options.log_level, Report, #{domain => [otp,ssl,tls_record]}),
get_tls_records_aux(Rest, [#ssl_tls{type = ?HANDSHAKE,
version = {MajVer, MinVer},
- fragment = Data} | Acc]);
+ fragment = Data} | Acc],
+ SslOpts);
get_tls_records_aux(<<?BYTE(?ALERT),?BYTE(MajVer),?BYTE(MinVer),
?UINT16(Length), Data:Length/binary,
- Rest/binary>>, Acc) ->
+ Rest/binary>>, Acc, SslOpts) ->
+ RawTLSRecord = <<?BYTE(?ALERT),?BYTE(MajVer),?BYTE(MinVer),
+ ?UINT16(Length), Data:Length/binary>>,
+ Report = #{direction => inbound,
+ protocol => 'tls_record',
+ message => [RawTLSRecord]},
+ ssl_logger:debug(SslOpts#ssl_options.log_level, Report, #{domain => [otp,ssl,tls_record]}),
get_tls_records_aux(Rest, [#ssl_tls{type = ?ALERT,
version = {MajVer, MinVer},
- fragment = Data} | Acc]);
+ fragment = Data} | Acc],
+ SslOpts);
get_tls_records_aux(<<?BYTE(?CHANGE_CIPHER_SPEC),?BYTE(MajVer),?BYTE(MinVer),
?UINT16(Length), Data:Length/binary, Rest/binary>>,
- Acc) ->
+ Acc, SslOpts) ->
+ RawTLSRecord = <<?BYTE(?CHANGE_CIPHER_SPEC),?BYTE(MajVer),?BYTE(MinVer),
+ ?UINT16(Length), Data:Length/binary>>,
+ Report = #{direction => inbound,
+ protocol => 'tls_record',
+ message => [RawTLSRecord]},
+ ssl_logger:debug(SslOpts#ssl_options.log_level, Report, #{domain => [otp,ssl,tls_record]}),
get_tls_records_aux(Rest, [#ssl_tls{type = ?CHANGE_CIPHER_SPEC,
version = {MajVer, MinVer},
- fragment = Data} | Acc]);
+ fragment = Data} | Acc],
+ SslOpts);
get_tls_records_aux(<<0:1, _CT:7, ?BYTE(_MajVer), ?BYTE(_MinVer),
?UINT16(Length), _/binary>>,
- _Acc) when Length > ?MAX_CIPHER_TEXT_LENGTH ->
+ _Acc, _SslOpts) when Length > ?MAX_CIPHER_TEXT_LENGTH ->
?ALERT_REC(?FATAL, ?RECORD_OVERFLOW);
-get_tls_records_aux(Data, Acc) ->
+get_tls_records_aux(Data, Acc, _SslOpts) ->
case size(Data) =< ?MAX_CIPHER_TEXT_LENGTH + ?INITIAL_BYTES of
true ->
{lists:reverse(Acc), Data};
diff --git a/lib/ssl/src/tls_socket.erl b/lib/ssl/src/tls_socket.erl
index 453a908401..154281f1c2 100644
--- a/lib/ssl/src/tls_socket.erl
+++ b/lib/ssl/src/tls_socket.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/src/tls_v1.erl b/lib/ssl/src/tls_v1.erl
index a31ab8d044..6ef6040761 100644
--- a/lib/ssl/src/tls_v1.erl
+++ b/lib/ssl/src/tls_v1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -74,7 +74,7 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
prf(?MD5SHA, MasterSecret, finished_label(Role), [MD5, SHA], 12);
finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
- when Version == 3 ->
+ when Version == 3; Version == 4 ->
%% RFC 5246 - 7.4.9. Finished
%% struct {
%% opaque verify_data[12];
@@ -85,6 +85,7 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
Hash = crypto:hash(mac_algo(PrfAlgo), Handshake),
prf(PrfAlgo, MasterSecret, finished_label(Role), Hash, 12).
+
-spec certificate_verify(md5sha | sha, integer(), [binary()]) -> binary().
certificate_verify(md5sha, _Version, Handshake) ->
@@ -154,7 +155,7 @@ setup_keys(Version, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize
%% TLS v1.2
setup_keys(Version, PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize,
KeyMatLen, IVSize)
- when Version == 3 ->
+ when Version == 3; Version == 4 ->
%% RFC 5246 - 6.3. Key calculation
%% key_block = PRF(SecurityParameters.master_secret,
%% "key expansion",
@@ -192,7 +193,7 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
Fragment]),
Mac.
--spec suites(1|2|3) -> [ssl_cipher:cipher_suite()].
+-spec suites(1|2|3|4) -> [ssl_cipher:cipher_suite()].
suites(Minor) when Minor == 1; Minor == 2 ->
[
@@ -244,8 +245,15 @@ suites(3) ->
%% ?TLS_DH_DSS_WITH_AES_256_GCM_SHA384,
%% ?TLS_DH_RSA_WITH_AES_128_GCM_SHA256,
%% ?TLS_DH_DSS_WITH_AES_128_GCM_SHA256
- ] ++ suites(2).
+ ] ++ suites(2);
+
+
+suites(4) ->
+ suites(3).
+
+signature_algs({3, 4}, HashSigns) ->
+ signature_algs({3, 3}, HashSigns);
signature_algs({3, 3}, HashSigns) ->
CryptoSupports = crypto:supports(),
Hashes = proplists:get_value(hashs, CryptoSupports),
@@ -273,6 +281,8 @@ signature_algs({3, 3}, HashSigns) ->
end, [], HashSigns),
lists:reverse(Supported).
+default_signature_algs({3, 4}) ->
+ default_signature_algs({3, 3});
default_signature_algs({3, 3} = Version) ->
Default = [%% SHA2
{sha512, ecdsa},
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile
index 845f5bee2e..9dfb2eba53 100644
--- a/lib/ssl/test/Makefile
+++ b/lib/ssl/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2017. All Rights Reserved.
+# Copyright Ericsson AB 1999-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/ssl/test/ssl_ECC.erl b/lib/ssl/test/ssl_ECC.erl
index 2096cf8166..36d949f74b 100644
--- a/lib/ssl/test/ssl_ECC.erl
+++ b/lib/ssl/test/ssl_ECC.erl
@@ -34,53 +34,65 @@
%% ECDH_RSA
client_ecdh_rsa_server_ecdh_rsa(Config) when is_list(Config) ->
+ Ext = x509_test:extensions([{key_usage, [keyAgreement]}]),
Suites = all_rsa_suites(Config),
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
{client_chain, Default}],
ecdh_rsa, ecdh_rsa, Config),
ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
ssl_test_lib:ssl_options(SOpts, Config),
[{check_keyex, ecdh_rsa}, {ciphers, Suites} | proplists:delete(check_keyex, Config)]).
client_ecdhe_rsa_server_ecdh_rsa(Config) when is_list(Config) ->
+ Ext = x509_test:extensions([{key_usage, [keyAgreement]}]),
Suites = all_rsa_suites(Config),
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
{client_chain, Default}],
ecdhe_rsa, ecdh_rsa, Config),
ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
ssl_test_lib:ssl_options(SOpts, Config),
[{check_keyex, ecdh_rsa}, {ciphers, Suites} | proplists:delete(check_keyex, Config)]).
client_ecdhe_ecdsa_server_ecdh_rsa(Config) when is_list(Config) ->
+ Ext = x509_test:extensions([{key_usage, [keyAgreement]}]),
Suites = all_rsa_suites(Config),
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
{client_chain, Default}],
ecdhe_ecdsa, ecdh_rsa, Config),
ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
- ssl_test_lib:ssl_options(SOpts, Config),
- [{check_keyex, ecdh_rsa}, {ciphers, Suites} | proplists:delete(check_keyex, Config)]).
+ ssl_test_lib:ssl_options(SOpts, Config),
+ [{check_keyex, ecdh_rsa}, {ciphers, Suites} | proplists:delete(check_keyex, Config)]).
%% ECDHE_RSA
client_ecdh_rsa_server_ecdhe_rsa(Config) when is_list(Config) ->
+ Ext = x509_test:extensions([{key_usage, [digitalSignature]}]),
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
{client_chain, Default}],
ecdh_rsa, ecdhe_rsa, Config),
ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
ssl_test_lib:ssl_options(SOpts, Config),
[{check_keyex, ecdhe_rsa} | proplists:delete(check_keyex, Config)]).
client_ecdhe_rsa_server_ecdhe_rsa(Config) when is_list(Config) ->
+ Ext = x509_test:extensions([{key_usage, [digitalSignature]}]),
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
{client_chain, Default}],
ecdhe_rsa, ecdhe_rsa, Config),
ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
- ssl_test_lib:ssl_options(SOpts, Config),
+ ssl_test_lib:ssl_options(SOpts, Config),
[{check_keyex, ecdhe_rsa} | proplists:delete(check_keyex, Config)]).
client_ecdhe_ecdsa_server_ecdhe_rsa(Config) when is_list(Config) ->
+ Ext = x509_test:extensions([{key_usage, [digitalSignature]}]),
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
{client_chain, Default}],
ecdh_ecdsa, ecdhe_rsa, Config),
ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
@@ -122,24 +134,30 @@ client_ecdhe_ecdsa_server_ecdh_ecdsa(Config) when is_list(Config) ->
%% ECDHE_ECDSA
client_ecdh_rsa_server_ecdhe_ecdsa(Config) when is_list(Config) ->
- Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ Ext = x509_test:extensions([{key_usage, [digitalSignature]}]),
+ Default = ssl_test_lib:default_cert_chain_conf(),
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
{client_chain, Default}],
ecdh_rsa, ecdhe_ecdsa, Config),
ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
ssl_test_lib:ssl_options(SOpts, Config),
[{check_keyex, ecdhe_ecdsa} | proplists:delete(check_keyex, Config)]).
client_ecdh_ecdsa_server_ecdhe_ecdsa(Config) when is_list(Config) ->
+ Ext = x509_test:extensions([{key_usage, [digitalSignature]}]),
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
{client_chain, Default}],
ecdh_ecdsa, ecdhe_ecdsa, Config),
ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
ssl_test_lib:ssl_options(SOpts, Config),
[{check_keyex, ecdhe_ecdsa} | proplists:delete(check_keyex, Config)]).
client_ecdhe_ecdsa_server_ecdhe_ecdsa(Config) when is_list(Config) ->
+ Ext = x509_test:extensions([{key_usage, [digitalSignature]}]),
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ {COpts, SOpts} = ssl_test_lib:make_ec_cert_chains([{server_chain,
+ [[], [], [{extensions, Ext}]]},
{client_chain, Default}],
ecdhe_ecdsa, ecdhe_ecdsa, Config),
ssl_test_lib:basic_test(ssl_test_lib:ssl_options(COpts, Config),
diff --git a/lib/ssl/test/ssl_ECC_SUITE.erl b/lib/ssl/test/ssl_ECC_SUITE.erl
index 6e2d86571a..c93f066825 100644
--- a/lib/ssl/test/ssl_ECC_SUITE.erl
+++ b/lib/ssl/test/ssl_ECC_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -43,10 +43,10 @@ all() ->
groups() ->
[
- {'tlsv1.2', [], test_cases()},
+ {'tlsv1.2', [], [mix_sign | test_cases()]},
{'tlsv1.1', [], test_cases()},
{'tlsv1', [], test_cases()},
- {'dtlsv1.2', [], test_cases()},
+ {'dtlsv1.2', [], [mix_sign | test_cases()]},
{'dtlsv1', [], test_cases()}
].
@@ -288,22 +288,22 @@ client_ecdh_rsa_server_ecdhe_ecdsa_server_custom(Config) ->
client_ecdh_rsa_server_ecdhe_rsa_server_custom(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
{COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdh_rsa, ecdhe_rsa, Config),
+ {client_chain, Default}],
+ ecdh_rsa, ecdhe_rsa, Config),
COpts = ssl_test_lib:ssl_options(COpts0, Config),
SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
case ssl_test_lib:supported_eccs(ECCOpts) of
- true -> ssl_test_lib:ecc_test(undefined, COpts, SOpts, [], ECCOpts, Config);
+ true -> ssl_test_lib:ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config);
false -> {skip, "unsupported named curves"}
end.
client_ecdhe_rsa_server_ecdhe_ecdsa_server_custom(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
- {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdhe_rsa, ecdhe_ecdsa, Config),
+ {COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
+ {client_chain, Default}],
+ ecdhe_rsa, ecdhe_ecdsa, Config),
COpts = ssl_test_lib:ssl_options(COpts0, Config),
SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
@@ -315,29 +315,30 @@ client_ecdhe_rsa_server_ecdhe_ecdsa_server_custom(Config) ->
client_ecdhe_rsa_server_ecdhe_rsa_server_custom(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
{COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdhe_rsa, ecdhe_rsa, Config),
+ {client_chain, Default}],
+ ecdhe_rsa, ecdhe_rsa, Config),
COpts = ssl_test_lib:ssl_options(COpts0, Config),
SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
case ssl_test_lib:supported_eccs(ECCOpts) of
- true -> ssl_test_lib:ecc_test(undefined, COpts, SOpts, [], ECCOpts, Config);
+ true -> ssl_test_lib:ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config);
false -> {skip, "unsupported named curves"}
end.
client_ecdhe_rsa_server_ecdh_rsa_server_custom(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
Ext = x509_test:extensions([{key_usage, [keyEncipherment]}]),
{COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, [[], [], [{extensions, Ext}]]},
- {client_chain, Default}],
- ecdhe_rsa, ecdh_rsa, Config),
+ {client_chain, Default}],
+ ecdhe_rsa, ecdh_rsa, Config),
COpts = ssl_test_lib:ssl_options(COpts0, Config),
SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
-
+ Expected = pubkey_cert_records:namedCurves(hd(tls_v1:ecc_curves(0))), %% The certificate curve
+
case ssl_test_lib:supported_eccs(ECCOpts) of
- true -> ssl_test_lib:ecc_test(undefined, COpts, SOpts, [], ECCOpts, Config);
+ true -> ssl_test_lib:ecc_test(Expected, COpts, SOpts, [], ECCOpts, Config);
false -> {skip, "unsupported named curves"}
end.
@@ -345,7 +346,7 @@ client_ecdhe_ecdsa_server_ecdhe_ecdsa_server_custom(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
{COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
{client_chain, Default}],
- ecdhe_ecdsa, ecdhe_ecdsa, Config),
+ ecdhe_ecdsa, ecdhe_ecdsa, Config),
COpts = ssl_test_lib:ssl_options(COpts0, Config),
SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
@@ -357,13 +358,13 @@ client_ecdhe_ecdsa_server_ecdhe_ecdsa_server_custom(Config) ->
client_ecdhe_ecdsa_server_ecdhe_rsa_server_custom(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
{COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdhe_ecdsa, ecdhe_rsa, Config),
+ {client_chain, Default}],
+ ecdhe_ecdsa, ecdhe_rsa, Config),
COpts = ssl_test_lib:ssl_options(COpts0, Config),
SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
ECCOpts = [{honor_ecc_order, true}, {eccs, [secp256r1, sect571r1]}],
case ssl_test_lib:supported_eccs(ECCOpts) of
- true -> ssl_test_lib:ecc_test(undefined, COpts, SOpts, [], ECCOpts, Config);
+ true -> ssl_test_lib:ecc_test(secp256r1, COpts, SOpts, [], ECCOpts, Config);
false -> {skip, "unsupported named curves"}
end.
@@ -371,7 +372,7 @@ client_ecdhe_ecdsa_server_ecdhe_ecdsa_client_custom(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
{COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
{client_chain, Default}],
- ecdhe_ecdsa, ecdhe_ecdsa, Config),
+ ecdhe_ecdsa, ecdhe_ecdsa, Config),
COpts = ssl_test_lib:ssl_options(COpts0, Config),
SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
ECCOpts = [{eccs, [secp256r1, sect571r1]}],
@@ -383,8 +384,8 @@ client_ecdhe_ecdsa_server_ecdhe_ecdsa_client_custom(Config) ->
client_ecdhe_rsa_server_ecdhe_ecdsa_client_custom(Config) ->
Default = ssl_test_lib:default_cert_chain_conf(),
{COpts0, SOpts0} = ssl_test_lib:make_ec_cert_chains([{server_chain, Default},
- {client_chain, Default}],
- ecdhe_rsa, ecdhe_ecdsa, Config),
+ {client_chain, Default}],
+ ecdhe_rsa, ecdhe_ecdsa, Config),
COpts = ssl_test_lib:ssl_options(COpts0, Config),
SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
ECCOpts = [{eccs, [secp256r1, sect571r1]}],
@@ -392,3 +393,12 @@ client_ecdhe_rsa_server_ecdhe_ecdsa_client_custom(Config) ->
true -> ssl_test_lib:ecc_test(secp256r1, COpts, SOpts, ECCOpts, [], Config);
false -> {skip, "unsupported named curves"}
end.
+
+mix_sign(Config) ->
+ {COpts0, SOpts0} = ssl_test_lib:make_mix_cert(Config),
+ COpts = ssl_test_lib:ssl_options(COpts0, Config),
+ SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
+ ECDHE_ECDSA =
+ ssl:filter_cipher_suites(ssl:cipher_suites(default, 'tlsv1.2'),
+ [{key_exchange, fun(ecdhe_ecdsa) -> true; (_) -> false end}]),
+ ssl_test_lib:basic_test(COpts, [{ciphers, ECDHE_ECDSA} | SOpts], Config).
diff --git a/lib/ssl/test/ssl_ECC_openssl_SUITE.erl b/lib/ssl/test/ssl_ECC_openssl_SUITE.erl
index 280fa94ecb..81a7dfd2da 100644
--- a/lib/ssl/test/ssl_ECC_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_ECC_openssl_SUITE.erl
@@ -57,13 +57,13 @@ all_groups() ->
groups() ->
case ssl_test_lib:openssl_sane_dtls() of
true ->
- [{'tlsv1.2', [], test_cases()},
+ [{'tlsv1.2', [], [mix_sign | test_cases()]},
{'tlsv1.1', [], test_cases()},
{'tlsv1', [], test_cases()},
- {'dtlsv1.2', [], test_cases()},
+ {'dtlsv1.2', [], [mix_sign | test_cases()]},
{'dtlsv1', [], test_cases()}];
false ->
- [{'tlsv1.2', [], test_cases()},
+ [{'tlsv1.2', [], [mix_sign | test_cases()]},
{'tlsv1.1', [], test_cases()},
{'tlsv1', [], test_cases()}]
end.
@@ -157,7 +157,7 @@ init_per_testcase(TestCase, Config) ->
ct:log("Ciphers: ~p~n ", [ssl:cipher_suites(default, Version)]),
end_per_testcase(TestCase, Config),
ssl:start(),
- ct:timetrap({seconds, 15}),
+ ct:timetrap({seconds, 30}),
Config.
end_per_testcase(_TestCase, Config) ->
@@ -202,6 +202,17 @@ client_ecdh_ecdsa_server_ecdhe_ecdsa(Config) when is_list(Config) ->
ssl_ECC:client_ecdh_ecdsa_server_ecdhe_ecdsa(Config).
client_ecdhe_ecdsa_server_ecdhe_ecdsa(Config) when is_list(Config) ->
ssl_ECC:client_ecdhe_ecdsa_server_ecdhe_ecdsa(Config).
+
+mix_sign(Config) ->
+ {COpts0, SOpts0} = ssl_test_lib:make_mix_cert(Config),
+ COpts = ssl_test_lib:ssl_options(COpts0, Config),
+ SOpts = ssl_test_lib:ssl_options(SOpts0, Config),
+ ECDHE_ECDSA =
+ ssl:filter_cipher_suites(ssl:cipher_suites(default, 'tlsv1.2'),
+ [{key_exchange, fun(ecdhe_ecdsa) -> true; (_) -> false end}]),
+ ssl_test_lib:basic_test(COpts, [{ciphers, ECDHE_ECDSA} | SOpts], [{client_type, erlang},
+ {server_type, openssl} | Config]).
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
diff --git a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl b/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
index 055f05a900..27062d4801 100644
--- a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index d3b13050e3..480988b6e4 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -108,7 +108,8 @@ basic_tests() ->
clear_pem_cache,
defaults,
fallback,
- cipher_format
+ cipher_format,
+ suite_to_str
].
basic_tests_tls() ->
@@ -146,8 +147,7 @@ options_tests_tls() ->
tls_tcp_reuseaddr].
api_tests() ->
- [connection_info,
- secret_connection_info,
+ [secret_connection_info,
connection_information,
peercert,
peercert_with_client_cert,
@@ -242,7 +242,9 @@ error_handling_tests()->
[close_transport_accept,
recv_active,
recv_active_once,
- recv_error_handling
+ recv_error_handling,
+ call_in_error_state,
+ close_in_error_state
].
error_handling_tests_tls()->
@@ -475,6 +477,8 @@ init_per_testcase(TestCase, Config) when TestCase == tls_ssl_accept_timeout;
TestCase == tls_client_closes_socket;
TestCase == tls_closed_in_active_once;
TestCase == tls_downgrade ->
+ ssl:stop(),
+ ssl:start(),
ssl_test_lib:ct_log_supported_protocol_versions(Config),
ct:timetrap({seconds, 15}),
Config;
@@ -609,7 +613,16 @@ new_options_in_accept(Config) when is_list(Config) ->
[_ , _ | ServerSslOpts] = ssl_test_lib:ssl_options(server_opts, Config), %% Remove non ssl opts
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Version = ssl_test_lib:protocol_options(Config, [{tls, sslv3}, {dtls, dtlsv1}]),
- Cipher = ssl_test_lib:protocol_options(Config, [{tls, {rsa,rc4_128,sha}}, {dtls, {rsa,aes_128_cbc,sha}}]),
+ Cipher = ssl_test_lib:protocol_options(Config, [{tls, #{key_exchange =>rsa,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf
+ }},
+ {dtls, #{key_exchange =>rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf
+ }}]),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
{ssl_extra_opts, [{versions, [Version]},
@@ -686,11 +699,16 @@ hello_client_cancel(Config) when is_list(Config) ->
{host, Hostname},
{from, self()},
{options, ssl_test_lib:ssl_options([{handshake, hello}], Config)},
- {continue_options, cancel}]),
-
- ssl_test_lib:check_result(Server, {error, {tls_alert, "user canceled"}}).
-%%--------------------------------------------------------------------
+ {continue_options, cancel}]),
+ receive
+ {Server, {error, {tls_alert, "user canceled"}}} ->
+ ok;
+ {Server, {error, closed}} ->
+ ct:pal("Did not receive the ALERT"),
+ ok
+ end.
+%%--------------------------------------------------------------------
hello_server_cancel() ->
[{doc, "Test API function ssl:handshake_cancel/1 on the server side"}].
hello_server_cancel(Config) when is_list(Config) ->
@@ -733,41 +751,6 @@ prf(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
-connection_info() ->
- [{doc,"Test the API function ssl:connection_information/2"}].
-connection_info(Config) when is_list(Config) ->
- ClientOpts = ssl_test_lib:ssl_options(client_verification_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_verification_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, connection_info_result, []}},
- {options, ServerOpts}]),
-
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, connection_info_result, []}},
- {options,
- [{ciphers,[{dhe_rsa, aes_128_cbc, sha}]} |
- ClientOpts]}]),
-
- ct:log("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- Version = ssl_test_lib:protocol_version(Config),
-
- ServerMsg = ClientMsg = {ok, {Version, {dhe_rsa, aes_128_cbc, sha}}},
-
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-%%--------------------------------------------------------------------
-
secret_connection_info() ->
[{doc,"Test the API function ssl:connection_information/2"}].
secret_connection_info(Config) when is_list(Config) ->
@@ -1222,7 +1205,27 @@ cipher_format(Config) when is_list(Config) ->
ssl:close(Socket1),
{ok, Socket2} = ssl:listen(0, [{ciphers, ssl:cipher_suites(openssl)}]),
ssl:close(Socket2).
-
+
+%%--------------------------------------------------------------------
+suite_to_str() ->
+ [{doc, "Test that the suite_to_str API works"}].
+suite_to_str(Config) when is_list(Config) ->
+ "TLS_EMPTY_RENEGOTIATION_INFO_SCSV" =
+ ssl:suite_to_str(#{key_exchange => null,
+ cipher => null,
+ mac => null,
+ prf => null}),
+ "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" =
+ ssl:suite_to_str(#{key_exchange => ecdhe_ecdsa,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256}),
+ "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256" =
+ ssl:suite_to_str(#{key_exchange => ecdh_rsa,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => sha256}).
+
%%--------------------------------------------------------------------
peername() ->
@@ -2539,7 +2542,7 @@ anonymous_cipher_suites()->
[{doc,"Test the anonymous ciphersuites"}].
anonymous_cipher_suites(Config) when is_list(Config) ->
NVersion = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:anonymous_suites(NVersion),
+ Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(NVersion),
run_suites(Ciphers, Config, anonymous).
%%-------------------------------------------------------------------
psk_cipher_suites() ->
@@ -2635,7 +2638,7 @@ default_reject_anonymous(Config) when is_list(Config) ->
Version = ssl_test_lib:protocol_version(Config),
TLSVersion = ssl_test_lib:tls_version(Version),
- [CipherSuite | _] = ssl_test_lib:anonymous_suites(TLSVersion),
+ [CipherSuite | _] = ssl_test_lib:ecdh_dh_anonymous_suites(TLSVersion),
Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
{from, self()},
@@ -3449,16 +3452,50 @@ tls_tcp_reuseaddr(Config) when is_list(Config) ->
honor_server_cipher_order() ->
[{doc,"Test API honor server cipher order."}].
honor_server_cipher_order(Config) when is_list(Config) ->
- ClientCiphers = [{dhe_rsa, aes_128_cbc, sha}, {dhe_rsa, aes_256_cbc, sha}],
- ServerCiphers = [{dhe_rsa, aes_256_cbc, sha}, {dhe_rsa, aes_128_cbc, sha}],
-honor_cipher_order(Config, true, ServerCiphers, ClientCiphers, {dhe_rsa, aes_256_cbc, sha}).
+ ClientCiphers = [#{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf},
+ #{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf}],
+ ServerCiphers = [#{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac =>sha,
+ prf => default_prf},
+ #{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf}],
+ honor_cipher_order(Config, true, ServerCiphers, ClientCiphers, #{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf}).
honor_client_cipher_order() ->
[{doc,"Test API honor server cipher order."}].
honor_client_cipher_order(Config) when is_list(Config) ->
- ClientCiphers = [{dhe_rsa, aes_128_cbc, sha}, {dhe_rsa, aes_256_cbc, sha}],
- ServerCiphers = [{dhe_rsa, aes_256_cbc, sha}, {dhe_rsa, aes_128_cbc, sha}],
-honor_cipher_order(Config, false, ServerCiphers, ClientCiphers, {dhe_rsa, aes_128_cbc, sha}).
+ ClientCiphers = [#{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf},
+ #{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf}],
+ ServerCiphers = [#{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac =>sha,
+ prf => default_prf},
+ #{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf}],
+honor_cipher_order(Config, false, ServerCiphers, ClientCiphers, #{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf}).
honor_cipher_order(Config, Honor, ServerCiphers, ClientCiphers, Expected) ->
ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
@@ -3490,7 +3527,7 @@ honor_cipher_order(Config, Honor, ServerCiphers, ClientCiphers, Expected) ->
%%--------------------------------------------------------------------
tls_ciphersuite_vs_version() ->
- [{doc,"Test a SSLv3 client can not negotiate a TLSv* cipher suite."}].
+ [{doc,"Test a SSLv3 client cannot negotiate a TLSv* cipher suite."}].
tls_ciphersuite_vs_version(Config) when is_list(Config) ->
{_ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -3967,6 +4004,64 @@ recv_error_handling(Config) when is_list(Config) ->
ssl:close(SslSocket),
ssl_test_lib:check_result(Server, ok).
+
+
+%%--------------------------------------------------------------------
+call_in_error_state() ->
+ [{doc,"Special case of call error handling"}].
+call_in_error_state(Config) when is_list(Config) ->
+ ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config),
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = [{cacertfile, "foo.pem"} | proplists:delete(cacertfile, ServerOpts0)],
+ Pid = spawn_link(?MODULE, run_error_server, [[self() | ServerOpts]]),
+ receive
+ {Pid, Port} ->
+ spawn_link(?MODULE, run_client_error, [[Port, ClientOpts]])
+ end,
+ receive
+ {error, closed} ->
+ ok;
+ Other ->
+ ct:fail(Other)
+ end.
+
+run_client_error([Port, Opts]) ->
+ ssl:connect("localhost", Port, Opts).
+
+run_error_server([ Pid | Opts]) ->
+ {ok, Listen} = ssl:listen(0, Opts),
+ {ok,{_, Port}} = ssl:sockname(Listen),
+ Pid ! {self(), Port},
+ {ok, Socket} = ssl:transport_accept(Listen),
+ Pid ! ssl:controlling_process(Socket, self()).
+
+%%--------------------------------------------------------------------
+
+close_in_error_state() ->
+ [{doc,"Special case of closing socket in error state"}].
+close_in_error_state(Config) when is_list(Config) ->
+ ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config),
+ ServerOpts = [{cacertfile, "foo.pem"} | proplists:delete(cacertfile, ServerOpts0)],
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ _ = spawn_link(?MODULE, run_error_server_close, [[self() | ServerOpts]]),
+ receive
+ {_Pid, Port} ->
+ spawn_link(?MODULE, run_client_error, [[Port, ClientOpts]])
+ end,
+ receive
+ ok ->
+ ok;
+ Other ->
+ ct:fail(Other)
+ end.
+
+run_error_server_close([Pid | Opts]) ->
+ {ok, Listen} = ssl:listen(0, Opts),
+ {ok,{_, Port}} = ssl:sockname(Listen),
+ Pid ! {self(), Port},
+ {ok, Socket} = ssl:transport_accept(Listen),
+ Pid ! ssl:close(Socket).
+
%%--------------------------------------------------------------------
rizzo() ->
@@ -4186,17 +4281,17 @@ unordered_protocol_versions_server(Config) when is_list(Config) ->
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE, connection_info_result, []}},
+ {mfa, {?MODULE, protocol_info_result, []}},
{options, [{versions, ['tlsv1.1', 'tlsv1.2']} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
- {mfa, {?MODULE, connection_info_result, []}},
+ {mfa, {?MODULE, protocol_info_result, []}},
{options, ClientOpts}]),
- CipherSuite = first_rsa_suite(ssl:cipher_suites()),
- ServerMsg = ClientMsg = {ok, {'tlsv1.2', CipherSuite}},
+
+ ServerMsg = ClientMsg = {ok,'tlsv1.2'},
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg).
%%--------------------------------------------------------------------
@@ -4211,18 +4306,17 @@ unordered_protocol_versions_client(Config) when is_list(Config) ->
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
- {mfa, {?MODULE, connection_info_result, []}},
+ {mfa, {?MODULE, protocol_info_result, []}},
{options, ServerOpts }]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
- {mfa, {?MODULE, connection_info_result, []}},
+ {mfa, {?MODULE, protocol_info_result, []}},
{options, [{versions, ['tlsv1.1', 'tlsv1.2']} | ClientOpts]}]),
-
- CipherSuite = first_rsa_suite(ssl:cipher_suites()),
- ServerMsg = ClientMsg = {ok, {'tlsv1.2', CipherSuite}},
+
+ ServerMsg = ClientMsg = {ok, 'tlsv1.2'},
ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg).
%%--------------------------------------------------------------------
@@ -4938,6 +5032,7 @@ run_suites(Ciphers, Config, Type) ->
[{ciphers, Ciphers} |
ssl_test_lib:ssl_options(server_ecdsa_opts, Config)]}
end,
+ ct:pal("ssl_test_lib:filter_suites(~p ~p) -> ~p ", [Ciphers, Version, ssl_test_lib:filter_suites(Ciphers, Version)]),
Result = lists:map(fun(Cipher) ->
cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end,
ssl_test_lib:filter_suites(Ciphers, Version)),
@@ -4950,7 +5045,7 @@ run_suites(Ciphers, Config, Type) ->
end.
erlang_cipher_suite(Suite) when is_list(Suite)->
- ssl_cipher:erl_suite_definition(ssl_cipher:openssl_suite(Suite));
+ ssl_cipher:suite_definition(ssl_cipher:openssl_suite(Suite));
erlang_cipher_suite(Suite) ->
Suite.
@@ -5002,8 +5097,13 @@ connection_information_result(Socket) ->
end.
connection_info_result(Socket) ->
- {ok, Info} = ssl:connection_information(Socket, [protocol, cipher_suite]),
- {ok, {proplists:get_value(protocol, Info), proplists:get_value(cipher_suite, Info)}}.
+ {ok, Info} = ssl:connection_information(Socket, [protocol, selected_cipher_suite]),
+ {ok, {proplists:get_value(protocol, Info), proplists:get_value(selected_cipher_suite, Info)}}.
+
+protocol_info_result(Socket) ->
+ {ok, [{protocol, PVersion}]} = ssl:connection_information(Socket, [protocol]),
+ {ok, PVersion}.
+
version_info_result(Socket) ->
{ok, [{version, Version}]} = ssl:connection_information(Socket, [version]),
{ok, Version}.
@@ -5046,8 +5146,14 @@ tls_downgrade_result(Socket) ->
tls_close(Socket) ->
ok = ssl_test_lib:send_recv_result(Socket),
- ok = ssl:close(Socket, 5000).
-
+ case ssl:close(Socket, 5000) of
+ ok ->
+ ok;
+ {error, closed} ->
+ ok;
+ Other ->
+ ct:fail(Other)
+ end.
%% First two clauses handles 1/n-1 splitting countermeasure Rizzo/Duong-Beast
treashold(N, {3,0}) ->
@@ -5126,20 +5232,6 @@ try_recv_active_once(Socket) ->
{error, einval} = ssl:recv(Socket, 11),
ok.
-first_rsa_suite([{ecdhe_rsa, _, _} = Suite | _]) ->
- Suite;
-first_rsa_suite([{dhe_rsa, _, _} = Suite| _]) ->
- Suite;
-first_rsa_suite([{rsa, _, _} = Suite| _]) ->
- Suite;
-first_rsa_suite([{ecdhe_rsa, _, _, _} = Suite | _]) ->
- Suite;
-first_rsa_suite([{dhe_rsa, _, _, _} = Suite| _]) ->
- Suite;
-first_rsa_suite([{rsa, _, _, _} = Suite| _]) ->
- Suite;
-first_rsa_suite([_ | Rest]) ->
- first_rsa_suite(Rest).
wait_for_send(Socket) ->
%% Make sure TLS process processed send message event
diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
index 1de4c89d7f..c0981a9eaf 100644
--- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl
+++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -87,7 +87,9 @@ tests() ->
extended_key_usage_verify_server,
critical_extension_verify_client,
critical_extension_verify_server,
- critical_extension_verify_none].
+ critical_extension_verify_none,
+ customize_hostname_check
+ ].
error_handling_tests()->
[client_with_cert_cipher_suites_handshake,
@@ -511,7 +513,7 @@ verify_fun_always_run_client(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(Server),
%% If user verify fun is called correctly we fail the connection.
- %% otherwise we can not tell this case apart form where we miss
+ %% otherwise we cannot tell this case apart form where we miss
%% to call users verify fun
FunAndState = {fun(_,{extension, _}, UserState) ->
{unknown, UserState};
@@ -550,7 +552,7 @@ verify_fun_always_run_server(Config) when is_list(Config) ->
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
%% If user verify fun is called correctly we fail the connection.
- %% otherwise we can not tell this case apart form where we miss
+ %% otherwise we cannot tell this case apart form where we miss
%% to call users verify fun
FunAndState = {fun(_,{extension, _}, UserState) ->
{unknown, UserState};
@@ -1145,6 +1147,58 @@ unknown_server_ca_accept_backwardscompatibility(Config) when is_list(Config) ->
ssl_test_lib:close(Client).
%%--------------------------------------------------------------------
+
+customize_hostname_check() ->
+ [{doc,"Test option customize_hostname_check."}].
+customize_hostname_check(Config) when is_list(Config) ->
+ Ext = [#'Extension'{extnID = ?'id-ce-subjectAltName',
+ extnValue = [{dNSName, "*.example.org"}],
+ critical = false}
+ ],
+ {ClientOpts0, ServerOpts0} = ssl_test_lib:make_rsa_cert_chains([{server_chain,
+ [[],
+ [],
+ [{extensions, Ext}]
+ ]}],
+ Config, "https_hostname_convention"),
+ ClientOpts = ssl_test_lib:ssl_options(ClientOpts0, Config),
+ ServerOpts = ssl_test_lib:ssl_options(ServerOpts0, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ CustomFun = public_key:pkix_verify_hostname_match_fun(https),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options,
+ [{server_name_indication, "other.example.org"},
+ {customize_hostname_check,
+ [{match_fun, CustomFun}]} | ClientOpts]
+ }]),
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ Server ! {listen, {mfa, {ssl_test_lib, no_result, []}}},
+
+ Client1 = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}
+ ]),
+ ssl_test_lib:check_result(Client1, {error, {tls_alert, "handshake failure"}},
+ Server, {error, {tls_alert, "handshake failure"}}),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
diff --git a/lib/ssl/test/ssl_crl_SUITE.erl b/lib/ssl/test/ssl_crl_SUITE.erl
index 668c76e38d..23c5eaf84d 100644
--- a/lib/ssl/test/ssl_crl_SUITE.erl
+++ b/lib/ssl/test/ssl_crl_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/test/ssl_dist_bench_SUITE.erl b/lib/ssl/test/ssl_dist_bench_SUITE.erl
index f827ea12bb..3c7904cf24 100644
--- a/lib/ssl/test/ssl_dist_bench_SUITE.erl
+++ b/lib/ssl/test/ssl_dist_bench_SUITE.erl
@@ -117,19 +117,14 @@ init_per_suite(Config) ->
?MODULE_STRING ++ " ROOT CA", CertOptions),
SSLConf =
[{verify, verify_peer},
- {fail_if_no_peer_cert, true},
{versions, [TLSVersion]},
{ciphers, [TLSCipher]}],
ServerConf =
- [{verify_fun,
- {fun inet_tls_dist:verify_client/3,
- fun inet_tls_dist:cert_nodes/1}}
- | SSLConf],
- ClientConf =
- [{verify_fun,
- {fun inet_tls_dist:verify_server/3,
- fun inet_tls_dist:cert_nodes/1}}
+ [{fail_if_no_peer_cert, true},
+ {verify_fun,
+ {fun inet_tls_dist:verify_client/3,[]}}
| SSLConf],
+ ClientConf = SSLConf,
%%
write_node_conf(
NodeAConfFile, NodeA, ServerConf, ClientConf,
@@ -291,6 +286,8 @@ roundtrip(A, B, Prefix, HA, HB) ->
Rounds = 40000,
[] = ssl_apply(HA, erlang, nodes, []),
[] = ssl_apply(HB, erlang, nodes, []),
+ ok = ssl_apply(HA, net_kernel, allow, [[B]]),
+ ok = ssl_apply(HB, net_kernel, allow, [[A]]),
Time = ssl_apply(HA, fun () -> roundtrip_runner(A, B, Rounds) end),
[B] = ssl_apply(HA, erlang, nodes, []),
[A] = ssl_apply(HB, erlang, nodes, []),
diff --git a/lib/ssl/test/ssl_engine_SUITE.erl b/lib/ssl/test/ssl_engine_SUITE.erl
index 71891356e8..1423c99dc2 100644
--- a/lib/ssl/test/ssl_engine_SUITE.erl
+++ b/lib/ssl/test/ssl_engine_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -117,8 +117,23 @@ private_key(Config) when is_list(Config) ->
EngineServerConf = [{key, #{algorithm => rsa,
engine => Engine,
key_id => ServerKey}} | proplists:delete(key, ServerConf)],
+
+ EngineFileClientConf = [{key, #{algorithm => rsa,
+ engine => Engine,
+ key_id => ClientKey}} |
+ proplists:delete(keyfile, FileClientConf)],
+
+ EngineFileServerConf = [{key, #{algorithm => rsa,
+ engine => Engine,
+ key_id => ServerKey}} |
+ proplists:delete(keyfile, FileServerConf)],
+
%% Test with engine
test_tls_connection(EngineServerConf, EngineClientConf, Config),
+
+ %% Test with engine and present file arugments
+ test_tls_connection(EngineFileServerConf, EngineFileClientConf, Config),
+
%% Test that sofware fallback is available
test_tls_connection(ServerConf, [{reuse_sessions, false} |ClientConf], Config).
diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl
index cd3d972c07..9ae04184e2 100644
--- a/lib/ssl/test/ssl_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_handshake_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -149,7 +149,7 @@ decode_single_hello_sni_extension_correctly(_Config) ->
Exts = Decoded.
decode_empty_server_sni_correctly(_Config) ->
- Exts = #hello_extensions{sni = ""},
+ Exts = #hello_extensions{sni = #sni{hostname = ""}},
SNI = <<?UINT16(?SNI_EXT),?UINT16(0)>>,
Decoded = ssl_handshake:decode_hello_extensions(SNI),
Exts = Decoded.
diff --git a/lib/ssl/test/ssl_npn_handshake_SUITE.erl b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
index 6bf2aa2786..1c7d6b5f9f 100644
--- a/lib/ssl/test/ssl_npn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl
index ef05241759..5939800001 100644
--- a/lib/ssl/test/ssl_payload_SUITE.erl
+++ b/lib/ssl/test/ssl_payload_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/test/ssl_pem_cache_SUITE.erl b/lib/ssl/test/ssl_pem_cache_SUITE.erl
index 96b15d9b51..3b79780974 100644
--- a/lib/ssl/test/ssl_pem_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_pem_cache_SUITE.erl
@@ -34,7 +34,7 @@
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
all() ->
- [pem_cleanup].
+ [pem_cleanup, invalid_insert].
groups() ->
[].
@@ -68,6 +68,10 @@ init_per_testcase(pem_cleanup = Case, Config) ->
application:set_env(ssl, ssl_pem_cache_clean, ?CLEANUP_INTERVAL),
ssl:start(),
ct:timetrap({minutes, 1}),
+ Config;
+init_per_testcase(_, Config) ->
+ ssl:start(),
+ ct:timetrap({seconds, 5}),
Config.
end_per_testcase(_TestCase, Config) ->
@@ -108,7 +112,34 @@ pem_cleanup(Config)when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client),
false = Size == Size1.
-
+
+invalid_insert() ->
+ [{doc, "Test that insert of invalid pem does not cause empty cache entry"}].
+invalid_insert(Config)when is_list(Config) ->
+ process_flag(trap_exit, true),
+
+ ClientOpts = proplists:get_value(client_verification_opts, Config),
+ ServerOpts = proplists:get_value(server_verification_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ BadClientOpts = [{cacertfile, "tmp/does_not_exist.pem"} | proplists:delete(cacertfile, ClientOpts)],
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ ssl_test_lib:start_client_error([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {from, self()}, {options, BadClientOpts}]),
+ ssl_test_lib:close(Server),
+ 1 = ssl_pkix_db:db_size(get_fileref_db()).
+
+
+
+%%--------------------------------------------------------------------
+%% Internal funcations
+%%--------------------------------------------------------------------
+
get_pem_cache() ->
{status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
[_, _,_, _, Prop] = StatusInfo,
@@ -120,6 +151,16 @@ get_pem_cache() ->
undefined
end.
+get_fileref_db() ->
+ {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
+ [_, _,_, _, Prop] = StatusInfo,
+ State = ssl_test_lib:state(Prop),
+ case element(6, State) of
+ [_CertDb, {FileRefDb,_} | _] ->
+ FileRefDb;
+ _ ->
+ undefined
+ end.
later()->
DateTime = calendar:now_to_local_time(os:timestamp()),
Gregorian = calendar:datetime_to_gregorian_seconds(DateTime),
diff --git a/lib/ssl/test/ssl_sni_SUITE.erl b/lib/ssl/test/ssl_sni_SUITE.erl
index 7e78c41444..251b6a2639 100644
--- a/lib/ssl/test/ssl_sni_SUITE.erl
+++ b/lib/ssl/test/ssl_sni_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 8c27571d64..7202e3662c 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -309,7 +309,7 @@ client_cont_loop(Node, Host, Port, Pid, Transport, Options, ContOpts, Opts) ->
case rpc:call(Node, Transport, connect, [Host, Port, Options]) of
{ok, Socket0, _} ->
ct:log("~p:~p~nClient: handshake_continue(~p, ~p, infinity) ~n", [?MODULE, ?LINE, Socket0, ContOpts]),
- case rpc:call(Node, Transport, handshake_continue, [Socket0, ContOpts, infinity]) of
+ case rpc:call(Node, Transport, handshake_continue, [Socket0, ContOpts]) of
{ok, Socket} ->
Pid ! {connected, Socket},
{Module, Function, Args} = proplists:get_value(mfa, Opts),
@@ -585,6 +585,17 @@ default_cert_chain_conf() ->
%% Use only default options
[[],[],[]].
+gen_conf(mix, mix, UserClient, UserServer) ->
+ ClientTag = conf_tag("client"),
+ ServerTag = conf_tag("server"),
+
+ DefaultClient = default_cert_chain_conf(),
+ DefaultServer = default_cert_chain_conf(),
+
+ ClientConf = merge_chain_spec(UserClient, DefaultClient, []),
+ ServerConf = merge_chain_spec(UserServer, DefaultServer, []),
+
+ new_format([{ClientTag, ClientConf}, {ServerTag, ServerConf}]);
gen_conf(ClientChainType, ServerChainType, UserClient, UserServer) ->
ClientTag = conf_tag("client"),
ServerTag = conf_tag("server"),
@@ -678,6 +689,32 @@ merge_spec(User, Default, [Conf | Rest], Acc) ->
merge_spec(User, Default, Rest, [{Conf, Value} | Acc])
end.
+make_mix_cert(Config) ->
+ Ext = x509_test:extensions([{key_usage, [digitalSignature]}]),
+ Digest = {digest, appropriate_sha(crypto:supports())},
+ CurveOid = hd(tls_v1:ecc_curves(0)),
+ ClientFileBase = filename:join([proplists:get_value(priv_dir, Config), "mix"]),
+ ServerFileBase = filename:join([proplists:get_value(priv_dir, Config), "mix"]),
+ ClientChain = [[Digest, {key, {namedCurve, CurveOid}}],
+ [Digest, {key, hardcode_rsa_key(1)}],
+ [Digest, {key, {namedCurve, CurveOid}}, {extensions, Ext}]
+ ],
+ ServerChain = [[Digest, {key, {namedCurve, CurveOid}}],
+ [Digest, {key, hardcode_rsa_key(2)}],
+ [Digest, {key, {namedCurve, CurveOid}},{extensions, Ext}]
+ ],
+ ClientChainType =ServerChainType = mix,
+ CertChainConf = gen_conf(ClientChainType, ServerChainType, ClientChain, ServerChain),
+ ClientFileBase = filename:join([proplists:get_value(priv_dir, Config), atom_to_list(ClientChainType)]),
+ ServerFileBase = filename:join([proplists:get_value(priv_dir, Config), atom_to_list(ServerChainType)]),
+ GenCertData = public_key:pkix_test_data(CertChainConf),
+ [{server_config, ServerConf},
+ {client_config, ClientConf}] =
+ x509_test:gen_pem_config_files(GenCertData, ClientFileBase, ServerFileBase),
+ {[{verify, verify_peer} | ClientConf],
+ [{reuseaddr, true}, {verify, verify_peer} | ServerConf]
+ }.
+
make_ecdsa_cert(Config) ->
CryptoSupport = crypto:supports(),
case proplists:get_bool(ecdsa, proplists:get_value(public_keys, CryptoSupport)) of
@@ -1097,8 +1134,6 @@ check_ecc(SSL, Role, Expect) ->
{ok, Data} = ssl:connection_information(SSL),
case lists:keyfind(ecc, 1, Data) of
{ecc, {named_curve, Expect}} -> ok;
- false when Expect == undefined -> ok;
- false when Expect == secp256r1 andalso Role == client_no_ecc -> ok;
Other -> {error, Role, Expect, Other}
end.
@@ -1170,13 +1205,13 @@ rsa_suites(CounterPart) ->
lists:member(cipher_atom(Cipher), Ciphers);
({ecdhe_rsa, Cipher, _}) when ECC == true ->
lists:member(cipher_atom(Cipher), Ciphers);
+ ({ecdhe_rsa, Cipher, _,_}) when ECC == true ->
+ lists:member(cipher_atom(Cipher), Ciphers);
({rsa, Cipher, _, _}) ->
lists:member(cipher_atom(Cipher), Ciphers);
({dhe_rsa, Cipher, _,_}) ->
lists:member(cipher_atom(Cipher), Ciphers);
- ({ecdhe_rsa, Cipher, _,_}) when ECC == true ->
- lists:member(cipher_atom(Cipher), Ciphers);
- (_) ->
+ (_) ->
false
end,
common_ciphers(CounterPart)).
@@ -1186,13 +1221,13 @@ common_ciphers(crypto) ->
common_ciphers(openssl) ->
OpenSslSuites =
string:tokens(string:strip(os:cmd("openssl ciphers"), right, $\n), ":"),
- [ssl_cipher:erl_suite_definition(S)
+ [ssl_cipher:suite_definition(S)
|| S <- ssl_cipher:suites(tls_record:highest_protocol_version([])),
lists:member(ssl_cipher:openssl_suite_name(S), OpenSslSuites)
].
available_suites(Version) ->
- [ssl_cipher:erl_suite_definition(Suite) ||
+ [ssl_cipher:suite_definition(Suite) ||
Suite <- ssl_cipher:filter_suites(ssl_cipher:suites(Version))].
@@ -1264,12 +1299,28 @@ string_regex_filter(Str, Search) when is_list(Str) ->
string_regex_filter(_Str, _Search) ->
false.
-anonymous_suites(Version) ->
- ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:anonymous_suites(Version)],[]).
+ecdh_dh_anonymous_suites(Version) ->
+ ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:anonymous_suites(Version)],
+ [{key_exchange,
+ fun(dh_anon) ->
+ true;
+ (ecdh_anon) ->
+ true;
+ (_) ->
+ false
+ end}]).
+psk_suites({3,_} = Version) ->
+ ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:psk_suites(Version)], []);
psk_suites(Version) ->
- ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:psk_suites(Version)], []).
+ ssl:filter_cipher_suites(psk_suites(dtls_v1:corresponding_tls_version(Version)),
+ [{cipher,
+ fun(rc4_128) ->
+ false;
+ (_) ->
+ true
+ end}]).
-psk_anon_suites(Version) ->
+psk_anon_suites({3,_} = Version) ->
ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:psk_suites_anon(Version)],
[{key_exchange,
fun(psk) ->
@@ -1278,8 +1329,18 @@ psk_anon_suites(Version) ->
true;
(_) ->
false
+ end}]);
+
+psk_anon_suites(Version) ->
+ ssl:filter_cipher_suites(psk_anon_suites(dtls_v1:corresponding_tls_version(Version)),
+ [{cipher,
+ fun(rc4_128) ->
+ false;
+ (_) ->
+ true
end}]).
+
srp_suites() ->
ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:srp_suites()],
[{key_exchange,
@@ -1300,7 +1361,7 @@ srp_dss_suites() ->
false
end}]).
chacha_suites(Version) ->
- [ssl_cipher:erl_suite_definition(S) || S <- ssl_cipher:filter_suites(ssl_cipher:chacha_suites(Version))].
+ [ssl_cipher:suite_definition(S) || S <- ssl_cipher:filter_suites(ssl_cipher:chacha_suites(Version))].
rc4_suites(Version) ->
@@ -1330,7 +1391,7 @@ der_to_pem(File, Entries) ->
cipher_result(Socket, Result) ->
{ok, Info} = ssl:connection_information(Socket),
- Result = {ok, {proplists:get_value(protocol, Info), proplists:get_value(cipher_suite, Info)}},
+ Result = {ok, {proplists:get_value(protocol, Info), proplists:get_value(selected_cipher_suite, Info)}},
ct:log("~p:~p~nSuccessfull connect: ~p~n", [?MODULE,?LINE, Result]),
%% Importante to send two packets here
%% to properly test "cipher state" handling
@@ -1442,10 +1503,13 @@ check_key_exchange_send_active(Socket, KeyEx) ->
send_recv_result_active(Socket).
check_key_exchange({KeyEx,_, _}, KeyEx, _) ->
+ ct:pal("Kex: ~p", [KeyEx]),
true;
check_key_exchange({KeyEx,_,_,_}, KeyEx, _) ->
+ ct:pal("Kex: ~p", [KeyEx]),
true;
check_key_exchange(KeyEx1, KeyEx2, Version) ->
+ ct:pal("Kex: ~p ~p", [KeyEx1, KeyEx2]),
case Version of
'tlsv1.2' ->
v_1_2_check(element(1, KeyEx1), KeyEx2);
@@ -1522,7 +1586,7 @@ is_sane_ecc(crypto) ->
true
end;
is_sane_ecc(_) ->
- true.
+ sufficient_crypto_support(cipher_ec).
is_fips(openssl) ->
VersionStr = os:cmd("openssl version"),
@@ -1593,11 +1657,7 @@ openssl_sane_dtls() ->
false;
"OpenSSL 1.0.2k-freebsd" ++ _ ->
false;
- "OpenSSL 1.0.2d" ++ _ ->
- false;
- "OpenSSL 1.0.2n" ++ _ ->
- false;
- "OpenSSL 1.0.2m" ++ _ ->
+ "OpenSSL 1.0.2" ++ _ ->
false;
"OpenSSL 1.0.0" ++ _ ->
false;
@@ -1705,7 +1765,7 @@ filter_suites([Cipher | _] = Ciphers, AtomVersion) when is_list(Cipher)->
filter_suites([ssl_cipher:openssl_suite(S) || S <- Ciphers],
AtomVersion);
filter_suites([Cipher | _] = Ciphers, AtomVersion) when is_binary(Cipher)->
- filter_suites([ssl_cipher:erl_suite_definition(S) || S <- Ciphers],
+ filter_suites([ssl_cipher:suite_definition(S) || S <- Ciphers],
AtomVersion);
filter_suites(Ciphers0, AtomVersion) ->
Version = tls_version(AtomVersion),
@@ -1717,7 +1777,7 @@ filter_suites(Ciphers0, AtomVersion) ->
++ ssl_cipher:srp_suites_anon()
++ ssl_cipher:rc4_suites(Version),
Supported1 = ssl_cipher:filter_suites(Supported0),
- Supported2 = [ssl_cipher:erl_suite_definition(S) || S <- Supported1],
+ Supported2 = [ssl_cipher:suite_definition(S) || S <- Supported1],
[Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported2)].
-define(OPENSSL_QUIT, "Q\n").
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index a2e8ef8be0..7fc5e13400 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -412,8 +412,16 @@ basic_erlang_server_openssl_client(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(Server),
Exe = "openssl",
- Args = ["s_client", "-connect", hostname_format(Hostname) ++
- ":" ++ integer_to_list(Port) ++ no_low_flag() | workaround_openssl_s_clinent()],
+ Args = case no_low_flag("-no_ssl2") of
+ [] ->
+ ["s_client", "-connect", hostname_format(Hostname) ++
+ ":" ++ integer_to_list(Port), no_low_flag("-no_ssl3")
+ | workaround_openssl_s_clinent()];
+ Flag ->
+ ["s_client", "-connect", hostname_format(Hostname) ++
+ ":" ++ integer_to_list(Port), no_low_flag("-no_ssl3"), Flag
+ | workaround_openssl_s_clinent()]
+ end,
OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
true = port_command(OpenSslPort, Data),
@@ -588,7 +596,7 @@ erlang_client_openssl_server_anon(Config) when is_list(Config) ->
ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
ClientOpts = ssl_test_lib:ssl_options(client_anon_opts, Config),
VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:anonymous_suites(VersionTuple),
+ Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple),
{ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
@@ -631,7 +639,7 @@ erlang_server_openssl_client_anon(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ssl_test_lib:ssl_options(server_anon_opts, Config),
VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:anonymous_suites(VersionTuple),
+ Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple),
{_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -665,7 +673,7 @@ erlang_server_openssl_client_anon_with_cert(Config) when is_list(Config) ->
process_flag(trap_exit, true),
ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
- Ciphers = ssl_test_lib:anonymous_suites(VersionTuple),
+ Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple),
{_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -1995,10 +2003,12 @@ hostname_format(Hostname) ->
"localhost"
end.
-no_low_flag() ->
+no_low_flag("-no_ssl2" = Flag) ->
case ssl_test_lib:supports_ssl_tls_version(sslv2) of
true ->
- " -no_ssl2 -no_ssl3";
+ Flag;
false ->
- " -no_ssl3"
- end.
+ ""
+ end;
+no_low_flag(Flag) ->
+ Flag.
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index eb85a55717..75d959accf 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1 +1 @@
-SSL_VSN = 8.2.6
+SSL_VSN = 9.1
diff --git a/lib/stdlib/doc/src/Makefile b/lib/stdlib/doc/src/Makefile
index 508a4fa2de..4541b4a463 100644
--- a/lib/stdlib/doc/src/Makefile
+++ b/lib/stdlib/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2017. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -71,7 +71,6 @@ XML_REF3_FILES = \
gen_statem.xml \
io.xml \
io_lib.xml \
- lib.xml \
lists.xml \
log_mf_h.xml \
maps.xml \
@@ -156,6 +155,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(MAN6DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
diff --git a/lib/stdlib/doc/src/assert_hrl.xml b/lib/stdlib/doc/src/assert_hrl.xml
index 33f29f38da..4dc7299609 100644
--- a/lib/stdlib/doc/src/assert_hrl.xml
+++ b/lib/stdlib/doc/src/assert_hrl.xml
@@ -4,7 +4,7 @@
<fileref>
<header>
<copyright>
- <year>2012</year><year>2017</year>
+ <year>2012</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/c.xml b/lib/stdlib/doc/src/c.xml
index 697e1715e7..b6cb6f5aae 100644
--- a/lib/stdlib/doc/src/c.xml
+++ b/lib/stdlib/doc/src/c.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/calendar.xml b/lib/stdlib/doc/src/calendar.xml
index 8f2b6b747a..6b4fa7f98a 100644
--- a/lib/stdlib/doc/src/calendar.xml
+++ b/lib/stdlib/doc/src/calendar.xml
@@ -323,7 +323,9 @@
<type name="rfc3339_string"/>
<type name="rfc3339_time_unit"/>
<desc>
- <p>Converts an RFC 3339 timestamp into system time.</p>
+ <p>Converts an RFC 3339 timestamp into system time. The data format
+ of RFC 3339 timestamps is described by
+ <url href="https://www.ietf.org/rfc/rfc3339.txt">RFC 3339</url>.</p>
<p>Valid option:</p>
<taglist>
<tag><c>{unit, Unit}</c></tag>
@@ -378,7 +380,10 @@
<type name="rfc3339_string"/>
<type name="rfc3339_time_unit"/>
<desc>
- <p>Converts a system time into RFC 3339 timestamp.</p>
+ <p>Converts a system time into an RFC 3339 timestamp. The data format
+ of RFC 3339 timestamps is described by
+ <url href="https://www.ietf.org/rfc/rfc3339.txt">RFC 3339</url>.
+ The data format of offsets is also described by RFC 3339.</p>
<p>Valid options:</p>
<taglist>
<tag><c>{offset, Offset}</c></tag>
diff --git a/lib/stdlib/doc/src/digraph.xml b/lib/stdlib/doc/src/digraph.xml
index db96beed6c..a5252b443b 100644
--- a/lib/stdlib/doc/src/digraph.xml
+++ b/lib/stdlib/doc/src/digraph.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml
index 305376a425..f8c54fb79a 100644
--- a/lib/stdlib/doc/src/ets.xml
+++ b/lib/stdlib/doc/src/ets.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -49,14 +49,16 @@
associated with each key. A <c>bag</c> or <c>duplicate_bag</c> table can
have many objects associated with each key.</p>
+ <marker id="max_ets_tables"></marker>
<note>
<p>
The number of tables stored at one Erlang node <em>used</em> to
be limited. This is no longer the case (except by memory usage).
The previous default limit was about 1400 tables and
could be increased by setting the environment variable
- <c>ERL_MAX_ETS_TABLES</c> before starting the Erlang runtime
- system. This hard limit has been removed, but it is currently
+ <c>ERL_MAX_ETS_TABLES</c> or the command line option
+ <seealso marker="erts:erl#+e"><c>+e</c></seealso> before starting the
+ Erlang runtime system. This hard limit has been removed, but it is currently
useful to set the <c>ERL_MAX_ETS_TABLES</c> anyway. It should be
set to an approximate of the maximum amount of tables used. This since
an internal table for named tables is sized using this value. If
diff --git a/lib/stdlib/doc/src/gb_sets.xml b/lib/stdlib/doc/src/gb_sets.xml
index 2a3785dc27..03397b4503 100644
--- a/lib/stdlib/doc/src/gb_sets.xml
+++ b/lib/stdlib/doc/src/gb_sets.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2001</year><year>2016</year>
+ <year>2001</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/gen_event.xml b/lib/stdlib/doc/src/gen_event.xml
index 012737c390..f793ec7fdf 100644
--- a/lib/stdlib/doc/src/gen_event.xml
+++ b/lib/stdlib/doc/src/gen_event.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -207,7 +207,7 @@ gen_event:stop -----> Module:terminate/2
</item>
<item>
<p>If the event handler is deleted later, the event manager
- sends a message<c>{gen_event_EXIT,Handler,Reason}</c> to
+ sends a message <c>{gen_event_EXIT,Handler,Reason}</c> to
the calling process. <c>Reason</c> is one of the following:</p>
<list type="bulleted">
<item>
@@ -458,8 +458,7 @@ gen_event:stop -----> Module:terminate/2
with the expected reason. Any other reason than <c>normal</c>,
<c>shutdown</c>, or <c>{shutdown,Term}</c> causes an
error report to be issued using
- <seealso marker="kernel:error_logger#format/2">
- <c>error_logger:format/2</c></seealso>.
+ <seealso marker="kernel:logger"><c>logger(3)</c></seealso>.
The default <c>Reason</c> is <c>normal</c>.</p>
<p><c>Timeout</c> is an integer greater than zero that
specifies how many milliseconds to wait for the event manager to
diff --git a/lib/stdlib/doc/src/gen_server.xml b/lib/stdlib/doc/src/gen_server.xml
index da74e793e6..106bda85f5 100644
--- a/lib/stdlib/doc/src/gen_server.xml
+++ b/lib/stdlib/doc/src/gen_server.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -486,8 +486,7 @@ gen_server:abcast -----> Module:handle_cast/2
with the expected reason. Any other reason than <c>normal</c>,
<c>shutdown</c>, or <c>{shutdown,Term}</c> causes an
error report to be issued using
- <seealso marker="kernel:error_logger#format/2">
- <c>error_logger:format/2</c></seealso>.
+ <seealso marker="kernel:logger"><c>logger(3)</c></seealso>.
The default <c>Reason</c> is <c>normal</c>.</p>
<p><c>Timeout</c> is an integer greater than zero that
specifies how many milliseconds to wait for the server to
@@ -861,8 +860,7 @@ gen_server:abcast -----> Module:handle_cast/2
<c>shutdown</c>, or <c>{shutdown,Term}</c>, the <c>gen_server</c>
process is assumed to terminate because of an error and
an error report is issued using
- <seealso marker="kernel:error_logger#format/2">
- <c>error_logger:format/2</c></seealso>.</p>
+ <seealso marker="kernel:logger"><c>logger(3)</c></seealso>.</p>
</desc>
</func>
</funcs>
diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml
index e918e83df7..eb0f7d24f0 100644
--- a/lib/stdlib/doc/src/gen_statem.xml
+++ b/lib/stdlib/doc/src/gen_statem.xml
@@ -722,7 +722,7 @@ handle_event(_, _, State, Data) ->
right before entering the initial state even though this
formally is not a state change.
In this case <c>OldState</c> will be the same as <c>State</c>,
- which can not happen for a subsequent state change,
+ which cannot happen for a subsequent state change,
but will happen when repeating the state enter call.
</p>
</desc>
@@ -1256,7 +1256,7 @@ handle_event(_, _, State, Data) ->
<desc>
<p>
<c><anno>State</anno></c> is the current state
- and it can not be changed since the state callback
+ and it cannot be changed since the state callback
was called with a
<seealso marker="#type-state_enter"><em>state enter call</em></seealso>.
</p>
@@ -1778,7 +1778,7 @@ handle_event(_, _, State, Data) ->
with the expected reason. Any other reason than <c>normal</c>,
<c>shutdown</c>, or <c>{shutdown,Term}</c> causes an
error report to be issued through
- <seealso marker="kernel:error_logger#format/2"><c>error_logger:format/2</c></seealso>.
+ <seealso marker="kernel:logger"><c>logger(3)</c></seealso>.
The default <c><anno>Reason</anno></c> is <c>normal</c>.
</p>
<p>
@@ -1922,7 +1922,7 @@ handle_event(_, _, State, Data) ->
<p>
If the function returns a failure <c>Reason</c>, the ongoing
upgrade fails and rolls back to the old release.
- Note that <c>Reason</c> can not be an <c>{ok,_,_}</c> tuple
+ Note that <c>Reason</c> cannot be an <c>{ok,_,_}</c> tuple
since that will be regarded as a
<c>{ok,NewState,NewData}</c> tuple,
and that a tuple matching <c>{ok,_}</c>
@@ -2208,7 +2208,7 @@ init(Args) -> erlang:error(not_implemented, [Args]).</pre>
<seealso marker="erts:erlang#throw/1"><c>throw</c></seealso>
to return the result, which can be useful.
For example to bail out with <c>throw(keep_state_and_data)</c>
- from deep within complex code that can not
+ from deep within complex code that cannot
return <c>{next_state,State,Data}</c> because
<c>State</c> or <c>Data</c> is no longer in scope.
</p>
@@ -2286,7 +2286,7 @@ init(Args) -> erlang:error(not_implemented, [Args]).</pre>
<c>shutdown</c>, or <c>{shutdown,Term}</c>,
the <c>gen_statem</c> is assumed to terminate because of an error
and an error report is issued using
- <seealso marker="kernel:error_logger#format/2"><c>error_logger:format/2</c></seealso>.
+ <seealso marker="kernel:logger"><c>logger(3)</c></seealso>.
</p>
</desc>
</func>
diff --git a/lib/stdlib/doc/src/io.xml b/lib/stdlib/doc/src/io.xml
index f1037ec76b..d4a2713840 100644
--- a/lib/stdlib/doc/src/io.xml
+++ b/lib/stdlib/doc/src/io.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -332,11 +332,22 @@ Here T = [{attributes,[[{id,age,1.5},
{tag,{'PRIVATE',3}},
{mode,implicit}]
ok</pre>
+
+ <p>As from Erlang/OTP 21.0, a field width of value
+ <c>0</c> can be used for specifying that a line is
+ infinitely long, which means that no line breaks
+ are inserted. For example:</p>
+
+ <pre>
+5> <input>io:fwrite("~0p~n", [lists:seq(1, 30)]).</input>
+[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]
+ok</pre>
+
<p>When the modifier <c>l</c> is specified, no detection of
printable character lists takes place, for example:</p>
<pre>
-5> <input>S = [{a,"a"}, {b, "b"}].</input>
-6> <input>io:fwrite("~15p~n", [S]).</input>
+6> <input>S = [{a,"a"}, {b, "b"}],
+ io:fwrite("~15p~n", [S]).</input>
[{a,"a"},
{b,"b"}]
ok
diff --git a/lib/stdlib/doc/src/io_lib.xml b/lib/stdlib/doc/src/io_lib.xml
index 4a2b425e8e..a3df2897ac 100644
--- a/lib/stdlib/doc/src/io_lib.xml
+++ b/lib/stdlib/doc/src/io_lib.xml
@@ -163,16 +163,20 @@
<p>Returns a character list that represents <c><anno>Data</anno></c>
formatted in accordance with <c><anno>Format</anno></c> in
the same way as
- <seealso marker="#fwrite/2"><c>fwrite/2</c></seealso> and
- <seealso marker="#format/2"><c>format/2</c></seealso>,
- but takes an extra argument, a list of options.</p>
- <p>Available options:</p>
- <taglist>
- <tag><c><anno>CharsLimit</anno></c></tag>
- <item>
- <p>A soft limit on the number of characters returned.</p>
- </item>
- </taglist>
+ <seealso marker="#fwrite/2"><c>fwrite/2</c></seealso> and
+ <seealso marker="#format/2"><c>format/2</c></seealso>,
+ but takes an extra argument, a list of options.</p>
+ <p>Valid option:</p>
+ <taglist>
+ <tag><c>{chars_limit, <anno>CharsLimit</anno>}</c></tag>
+ <item>
+ <p>A soft limit on the number of characters returned.
+ When the number of characters is reached, remaining
+ structures are replaced by "<c>...</c>".
+ <c><anno>CharsLimit</anno></c> defaults to -1, which
+ means no limit on the number of characters returned.</p>
+ </item>
+ </taglist>
</desc>
</func>
@@ -390,11 +394,11 @@
everything below this level is replaced by "<c>...</c>".
<c><anno>Depth</anno></c> defaults to -1, which means
no limitation. Option <c><anno>CharsLimit</anno></c> puts a
- soft limit on the number of characters returned. When the
- number of characters is reached, remaining structures are
- replaced by "<c>...</c>". <c><anno>CharsLimit</anno></c>
- defaults to -1, which means no limit on the number of
- characters returned.</p>
+ soft limit on the number of characters returned. When the
+ number of characters is reached, remaining structures are
+ replaced by "<c>...</c>". <c><anno>CharsLimit</anno></c>
+ defaults to -1, which means no limit on the number of
+ characters returned.</p>
<p><em>Example:</em></p>
<pre>
1> <input>lists:flatten(io_lib:write({1,[2],[3],[4,5],6,7,8,9})).</input>
diff --git a/lib/stdlib/doc/src/lib.xml b/lib/stdlib/doc/src/lib.xml
deleted file mode 100644
index 58dad7c9e0..0000000000
--- a/lib/stdlib/doc/src/lib.xml
+++ /dev/null
@@ -1,103 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1996</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>lib</title>
- <prepared></prepared>
- <docno></docno>
- <date></date>
- <rev></rev>
- </header>
- <module>lib</module>
- <modulesummary>Useful library functions.</modulesummary>
- <description>
- <warning>
- <p>This module is retained for backward compatibility. It can disappear
- without warning in a future Erlang/OTP release.</p>
- </warning>
- </description>
-
- <funcs>
- <func>
- <name name="error_message" arity="2"/>
- <fsummary>Print error message.</fsummary>
- <desc>
- <p>Prints error message <c><anno>Args</anno></c> in accordance with
- <c><anno>Format</anno></c>. Similar to
- <seealso marker="io#format/1"><c>io:format/2</c></seealso>.</p>
- </desc>
- </func>
-
- <func>
- <name name="flush_receive" arity="0"/>
- <fsummary>Flush messages.</fsummary>
- <desc>
- <p>Flushes the message buffer of the current process.</p>
- </desc>
- </func>
-
- <func>
- <name name="nonl" arity="1"/>
- <fsummary>Remove last newline.</fsummary>
- <desc>
- <p>Removes the last newline character, if any, in
- <c><anno>String1</anno></c>.</p>
- </desc>
- </func>
-
- <func>
- <name name="progname" arity="0"/>
- <fsummary>Return name of Erlang start script.</fsummary>
- <desc>
- <p>Returns the name of the script that started the current
- Erlang session.</p>
- </desc>
- </func>
-
- <func>
- <name name="send" arity="2"/>
- <fsummary>Send a message.</fsummary>
- <desc>
- <p>Makes it possible to send a message using the <c>apply/3</c> BIF.</p>
- </desc>
- </func>
-
- <func>
- <name name="sendw" arity="2"/>
- <fsummary>Send a message and wait for an answer.</fsummary>
- <desc>
- <p>As <seealso marker="#send/2"><c>send/2</c></seealso>,
- but waits for an answer. It is implemented as follows:</p>
- <code type="none">
-sendw(To, Msg) ->
- To ! {self(),Msg},
- receive
- Reply -> Reply
- end.</code>
- <p>The returned message is not necessarily a reply to the sent
- message.</p>
- </desc>
- </func>
- </funcs>
-</erlref>
-
diff --git a/lib/stdlib/doc/src/maps.xml b/lib/stdlib/doc/src/maps.xml
index 987d92989d..4c5199ca2b 100644
--- a/lib/stdlib/doc/src/maps.xml
+++ b/lib/stdlib/doc/src/maps.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2013</year><year>2016</year>
+ <year>2013</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -35,9 +35,10 @@
<datatypes>
<datatype>
- <name name="iterator"/>
+ <name name="iterator" n_vars="2"/>
<desc>
- <p>An iterator representing the key value associations in a map.</p>
+ <p>An iterator representing the associations in a map with keys of type
+ <c><anno>Key</anno></c> and values of type <c><anno>Value</anno></c>.</p>
<p>Created using <seealso marker="#iterator-1"><c>maps:iterator/1</c></seealso>.</p>
<p>Consumed by <seealso marker="#next-1"><c>maps:next/1</c></seealso>,
<seealso marker="#filter-2"><c>maps:filter/2</c></seealso>,
@@ -45,6 +46,10 @@
<seealso marker="#map-2"><c>maps:map/2</c></seealso>.</p>
</desc>
</datatype>
+
+ <datatype>
+ <name name="iterator" n_vars="0"/>
+ </datatype>
</datatypes>
<funcs>
@@ -90,13 +95,13 @@
<name name="fold" arity="3"/>
<fsummary></fsummary>
<desc>
- <p>Calls <c>F(K, V, AccIn)</c> for every <c><anno>K</anno></c> to value
- <c><anno>V</anno></c> association in <c><anno>MapOrIter</anno></c> in
- any order. Function <c>fun F/3</c> must return a new
- accumulator, which is passed to the next successive call.
- This function returns the final value of the accumulator. The initial
- accumulator value <c><anno>Init</anno></c> is returned if the map is
- empty.</p>
+ <p>Calls <c>F(Key, Value, AccIn)</c> for every <c><anno>Key</anno></c>
+ to value <c><anno>Value</anno></c> association in
+ <c><anno>MapOrIter</anno></c> in any order. Function <c>fun F/3</c>
+ must return a new accumulator, which is passed to the next successive
+ call. This function returns the final value of the accumulator.
+ The initial accumulator value <c><anno>Init</anno></c> is returned
+ if the map is empty.</p>
<p>The call fails with a <c>{badmap,Map}</c> exception if
<c><anno>MapOrIter</anno></c> is not a map or valid iterator,
or with <c>badarg</c> if <c><anno>Fun</anno></c> is not a
@@ -234,11 +239,12 @@ none</code>
<fsummary></fsummary>
<desc>
<p>Produces a new map <c><anno>Map</anno></c> by calling function
- <c>fun F(K, V1)</c> for every <c><anno>K</anno></c> to value
- <c><anno>V1</anno></c> association in <c><anno>MapOrIter</anno></c> in
- any order. Function <c>fun F/2</c> must return value
- <c><anno>V2</anno></c> to be associated with key <c><anno>K</anno></c>
- for the new map <c><anno>Map</anno></c>.</p>
+ <c>fun F(Key, Value1)</c> for every <c><anno>Key</anno></c> to value
+ <c><anno>Value1</anno></c> association in
+ <c><anno>MapOrIter</anno></c> in any order. Function <c>fun Fun/2</c>
+ must return value <c><anno>Value2</anno></c> to be associated with
+ key <c><anno>Key</anno></c> for the new map
+ <c><anno>Map</anno></c>.</p>
<p>The call fails with a <c>{badmap,Map}</c> exception if
<c><anno>MapOrIter</anno></c> is not a map or valid iterator,
or with <c>badarg</c> if <c><anno>Fun</anno></c> is not a
diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml
index e26c4aba74..8b6de03f5f 100644
--- a/lib/stdlib/doc/src/notes.xml
+++ b/lib/stdlib/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,444 @@
</header>
<p>This document describes the changes made to the STDLIB application.</p>
+<section><title>STDLIB 3.5.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug that could cause a crash when formatting a
+ list of non-characters using the control sequences
+ <c>p</c> or <c>P</c> and limiting the output with the
+ option <c>chars_limit</c>. </p>
+ <p>
+ Own Id: OTP-15159</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>STDLIB 3.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p><c>gen_statem</c> improvements.</p> <p> When using an
+ exception that is valid but not allowed in a state enter
+ call, the reason has been changed from
+ <c>{bad_action_from_state_function,Action}</c> to
+ <c>{bad_state_enter_action_from_state_function,Action}</c>.
+ </p><p> Timer parsing has been improved. Many erroneous
+ timeout tuples was not handled correctly. </p><p> The
+ documentation has been updated, in particular the User's
+ Guide and the pointer to it from the Reference Manual is
+ much more obvious. </p>
+ <p>
+ Own Id: OTP-14015</p>
+ </item>
+ <item>
+ <p>
+ The type specifications for <c>file:posix/0</c> and
+ <c>inet:posix/0</c> have been updated according to which
+ errors file and socket operations should be able to
+ return.</p>
+ <p>
+ Own Id: OTP-14019 Aux Id: ERL-550 </p>
+ </item>
+ <item>
+ <p> File operations used to accept <seealso
+ marker="kernel:file#type-name_all">filenames</seealso>
+ containing null characters (integer value zero). This
+ caused the name to be truncated and in some cases
+ arguments to primitive operations to be mixed up.
+ Filenames containing null characters inside the filename
+ are now <em>rejected</em> and will cause primitive file
+ operations to fail. </p> <p> Also environment variable
+ operations used to accept <seealso
+ marker="kernel:os#type-env_var_name">names</seealso> and
+ <seealso
+ marker="kernel:os#type-env_var_value">values</seealso> of
+ environment variables containing null characters (integer
+ value zero). This caused operations to silently produce
+ erroneous results. Environment variable names and values
+ containing null characters inside the name or value are
+ now <em>rejected</em> and will cause environment variable
+ operations to fail. </p> <p>Primitive environment
+ variable operations also used to accept the <c>$=</c>
+ character in environment variable names causing various
+ problems. <c>$=</c> characters in environment variable
+ names are now also <em>rejected</em>. </p> <p>Also
+ <seealso
+ marker="kernel:os#cmd/1"><c>os:cmd/1</c></seealso> now
+ reject null characters inside its <seealso
+ marker="kernel:os#type-os_command">command</seealso>.
+ </p> <p><seealso
+ marker="erts:erlang#open_port/2"><c>erlang:open_port/2</c></seealso>
+ will also reject null characters inside the port name
+ from now on.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14543 Aux Id: ERL-370 </p>
+ </item>
+ <item>
+ <p> Make <c>io_lib:unscan_format/1</c> work with pad char
+ and default precision. </p>
+ <p>
+ Own Id: OTP-14958 Aux Id: PR-1735 </p>
+ </item>
+ <item>
+ <p> The control sequence modifiers <c>t</c> and <c>l</c>
+ can be used together in the same control sequence which
+ makes it possible to have Unicode atoms and no detection
+ of printable character lists at the same time. </p>
+ <p>
+ Own Id: OTP-14971 Aux Id: PR-1743 </p>
+ </item>
+ <item>
+ <p> Fix a bug in the Erlang code linter: the check of
+ guard expressions no longer returns <c>false</c> if the
+ map syntax is used. The bug affected the Erlang shell,
+ the Debugger, and other modules evaluating abstract code.
+ </p>
+ <p>
+ Own Id: OTP-15035 Aux Id: ERL-613 </p>
+ </item>
+ <item>
+ <p>
+ A sys debug fun of type {Fun,State} should not be
+ possible to install twice. This was, however, possible if
+ the current State was 'undefined', which was mistaken for
+ non-existing fun. This has been corrected.</p>
+ <p>
+ Own Id: OTP-15049</p>
+ </item>
+ <item>
+ <p>
+ Fix <c>io:putchars/2</c> stacktrace rewriting at errors
+ to point to a valid function.</p>
+ <p>
+ Own Id: OTP-15101</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The <c>gen_server</c> has gotten a new callback
+ <c>handle_continue/2</c> for check pointing the state.
+ This is useful at least when implementing behaviours on
+ top of <c>gen_server</c> and for some start up scenarios.</p>
+ <p>
+ Own Id: OTP-13019 Aux Id: PR-1490 </p>
+ </item>
+ <item>
+ <p> The semantics of timeout parameter
+ <c>{clean_timeout,infinity}</c> to
+ <c>gen_statem:call/3</c> has been changed to use a proxy
+ process for the call. With this change
+ <c>clean_timeout</c> implicates a proxy process with no
+ exceptions. This may be a hard to observe
+ incompatibility: in the presence of network problems a
+ late reply could arrive in the caller's message queue
+ when catching errors. That will not happen after this
+ correction. </p><p> The semantics of timeout parameter
+ <c>infinity</c> has not been changed. </p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-13073 Aux Id: PR-1595 </p>
+ </item>
+ <item>
+ <p>A new logging API is added to Erlang/OTP, see the
+ <seealso
+ marker="kernel:logger"><c>logger(3)</c></seealso> manual
+ page, and section <seealso
+ marker="kernel:logger_chapter">Logging</seealso> in the
+ Kernel User's Guide.</p>
+ <p>Calls to <c>error_logger</c> are automatically
+ redirected to the new API, and legacy error logger event
+ handlers can still be used. It is, however, recommended
+ to use the Logger API directly when writing new code.</p>
+ <p>Notice the following potential incompatibilities:</p>
+ <list> <item><p>Kernel configuration parameters
+ <c>error_logger</c> still works, but is overruled if the
+ default handler's output destination is configured with
+ Kernel configuration parameter <c>logger</c>.</p> <p>In
+ general, parameters for configuring error logger are
+ overwritten by new parameters for configuring
+ Logger.</p></item> <item><p>The concept of SASL error
+ logging is deprecated, meaning that by default the SASL
+ application does not affect which log events are
+ logged.</p> <p>By default, supervisor reports and crash
+ reports are logged by the default Logger handler started
+ by Kernel, and end up at the same destination (terminal
+ or file) as other standard log event from Erlang/OTP.</p>
+ <p>Progress reports are not logged by default, but can be
+ enabled by setting the primary log level to info, for
+ example with the Kernel configuration parameter
+ <c>logger_level</c>.</p> <p>To obtain backwards
+ compatibility with the SASL error logging functionality
+ from earlier releases, set Kernel configuration parameter
+ <c>logger_sasl_compatible</c> to <c>true</c>. This
+ prevents the default Logger handler from logging any
+ supervisor-, crash-, or progress reports. Instead, SASL
+ adds a separate Logger handler during application start,
+ which takes care of these log events. The SASL
+ configuration parameters <c>sasl_error_logger</c> and
+ <c>sasl_errlog_type</c> specify the destination (terminal
+ or file) and severity level to log for these
+ events.</p></item></list>
+ <p>
+ Since Logger is new in Erlang/OTP 21.0, we do reserve the
+ right to introduce changes to the Logger API and
+ functionality in patches following this release. These
+ changes might or might not be backwards compatible with
+ the initial version.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-13295</p>
+ </item>
+ <item>
+ <p> Add functions
+ <c>calendar:system_time_to_local_time/2</c> and
+ <c>calendar:system_time_to_universal_time/2</c>. </p>
+ <p>
+ Own Id: OTP-13413</p>
+ </item>
+ <item>
+ <p> Functions <c>rand:uniform_real/0</c> and
+ <c>rand:uniform_real_s/1</c> have been added. They
+ produce uniformly distributed numbers in the range <c>0.0
+ =&lt; X &lt; 1.0</c> that are as close to random real
+ numbers as Normalized IEEE 754 Double Precision allows.
+ Because the random real number exactly <c>0.0</c> is
+ infinitely improbable they will never return exactly
+ <c>0.0</c>. </p><p> These properties are useful when you
+ need to call for example <c>math:log(X)</c> or <c>1 /
+ X</c> on a random value <c>X</c>, since that will never
+ fail with a number from these new functions. </p>
+ <p>
+ Own Id: OTP-13764 Aux Id: PR-1574 </p>
+ </item>
+ <item>
+ <p>
+ Added maps:iterator/0 and maps:next/1 to be used for
+ iterating over the key-value associations in a map.</p>
+ <p>
+ Own Id: OTP-14012</p>
+ </item>
+ <item>
+ <p>Changed the default behaviour of <c>.erlang</c>
+ loading: <c>.erlang</c> is no longer loaded from the
+ current directory. <c>c:erlangrc(PathList)</c> can be
+ used to search and load an <c>.erlang</c> file from user
+ specified directories.</p> <p><c>escript</c>,
+ <c>erlc</c>, <c>dialyzer</c> and <c>typer</c> no longer
+ load an <c>.erlang</c> at all.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14439</p>
+ </item>
+ <item>
+ <p>
+ Added new uri_string module to stdlib for handling URIs
+ (RFC 3986).</p>
+ <p>
+ Own Id: OTP-14496</p>
+ </item>
+ <item>
+ <p>
+ Update Unicode specification to version 10.0.</p>
+ <p>
+ Own Id: OTP-14503</p>
+ </item>
+ <item>
+ <p><c>filelib:wildcard()</c> now allows characters with a
+ special meaning to be escaped using backslashes.</p>
+ <p>This is an incompatible change, but note that the use
+ of backslashes in wildcards would already work
+ differently on Windows and Unix. Existing calls to
+ <c>filelib:wildcard()</c> needs to be updated. On
+ Windows, directory separators must always be written as a
+ slash.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14577</p>
+ </item>
+ <item>
+ <p>
+ The supervisor now stores its child specifications in a
+ map instead of a list. This causes a significant
+ improvement when starting many children under a
+ non-simple_one_for_one supervisor.</p>
+ <p>
+ Own Id: OTP-14586</p>
+ </item>
+ <item>
+ <p> The <c>base64</c> module is optimized. </p> <p> Note
+ that the functions <c>encode/1</c>, <c>decode/1</c>, and
+ <c>mime_decode/1</c> fail unless called with an argument
+ of the documented type. They used to accept any
+ <c>iodata()</c>. </p>
+ <p>
+ Own Id: OTP-14624 Aux Id: PR-1565 </p>
+ </item>
+ <item>
+ <p> Add function <c>lists:search/2</c>. </p>
+ <p>
+ Own Id: OTP-14675 Aux Id: PR-102 </p>
+ </item>
+ <item>
+ <p>
+ uri_string module extended with functions for handling
+ application/x-www-form-urlencoded query strings based on
+ the HTML5 specification.</p>
+ <p>
+ Own Id: OTP-14747</p>
+ </item>
+ <item>
+ <p> Add functions
+ <c>calendar:rfc3339_to_system_time/1,2</c> and
+ <c>calendar:system_time_to_rfc3339/1,2</c>. </p>
+ <p>
+ Own Id: OTP-14764</p>
+ </item>
+ <item>
+ <p> The stack traces returned by the functions of the
+ <c>erl_eval</c> module more accurately reflect where the
+ exception occurred. </p>
+ <p>
+ Own Id: OTP-14826 Aux Id: PR 1540 </p>
+ </item>
+ <item>
+ <p> Add options <c>atime</c>, <c>mtime</c>, <c>ctime</c>,
+ <c>uid</c>, and <c>gid</c> to the <c>erl_tar:add/3,4</c>
+ functions. </p>
+ <p>
+ Own Id: OTP-14834 Aux Id: PR 1608 </p>
+ </item>
+ <item>
+ <p>Added <c>ets:whereis/1</c> for retrieving the table
+ identifier of a named table.</p>
+ <p>
+ Own Id: OTP-14884</p>
+ </item>
+ <item>
+ <p>
+ Improved URI normalization functions in the uri_string
+ module.</p>
+ <p>
+ Own Id: OTP-14910</p>
+ </item>
+ <item>
+ <p> The new functions <c>io_lib:fwrite/3</c> and
+ <c>io_lib:format/3</c> take a third argument, an option
+ list. The only option is <c>chars_limit</c>, which is
+ used for limiting the number of returned characters. The
+ limit is soft, which means that the number of returned
+ characters exceeds the limit with at most a smallish
+ amount. If the limit is set, the functions
+ <c>format/3</c> and <c>fwrite/3</c> try to distribute the
+ number of characters evenly over the control sequences
+ <c>pPswW</c>. Furthermore, the control sequences
+ <c>pPwP</c> try to distribute the number of characters
+ evenly over substructures. </p> <p> A modification of the
+ control sequences <c>pPwW</c> is that even if there is no
+ limit on the number of returned characters, all
+ associations of a map are printed to the same depth. The
+ aim is to give a more consistent output as the order of
+ map keys is not defined. As before, if the depth is less
+ than the number of associations of a map, the selection
+ of associations to print is arbitrary. </p>
+ <p>
+ Own Id: OTP-14983</p>
+ </item>
+ <item>
+ <p> Add functions <c>ordsets:is_empty/1</c> and
+ <c>sets:is_empty/1</c>. </p>
+ <p>
+ Own Id: OTP-14996 Aux Id: ERL-557, PR-1703 </p>
+ </item>
+ <item>
+ <p>
+ Improve performance of <c>string:uppercase/1</c>,
+ <c>string:lowercase/1</c> and <c>string:casefold/1</c>
+ when handling ASCII characters.</p>
+ <p>
+ Own Id: OTP-14998</p>
+ </item>
+ <item>
+ <p>External funs with literal values for module, name,
+ and arity (e.g. <c>erlang:abs/1</c>) are now treated as
+ literals. That means more efficient code that produces
+ less garbage on the heap.</p>
+ <p>
+ Own Id: OTP-15003</p>
+ </item>
+ <item>
+ <p>
+ sys:statistics(Pid,get) did not report 'out' messages
+ from gen_server. This is now corrected.</p>
+ <p>
+ Own Id: OTP-15047</p>
+ </item>
+ <item>
+ <p>
+ A sys debug function can now have the format
+ {Id,Fun,State} in addition to the old {Fun,State}. This
+ allows installing multiple instances of a debug fun.</p>
+ <p>
+ Own Id: OTP-15048</p>
+ </item>
+ <item>
+ <p> The <c>lib</c> module is removed:</p> <list
+ type="bulleted"> <item><c>lib:error_message/2</c> is
+ removed.</item> <item><c>lib:flush_receive/0</c> is
+ removed.</item> <item><c>lib:nonl/1</c> is
+ removed.</item> <item><c>lib:progname/0</c> is replaced
+ by <c>ct:get_progname/0</c>.</item>
+ <item><c>lib:send/2</c> is removed.</item>
+ <item><c>lib:sendw/2</c> is removed.</item> </list>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15072 Aux Id: PR 1786, OTP-15114 </p>
+ </item>
+ <item>
+ <p>
+ Function <c>ets:delete_all_objects/1</c> now yields the
+ scheduler thread for large tables that take significant
+ time to clear. This to improve real time characteristics
+ of other runnable processes.</p>
+ <p>
+ Own Id: OTP-15078</p>
+ </item>
+ <item>
+ <p> In control sequences of the functions
+ <c>io:fwrite/2,3</c> and <c>io_lib:fwrite/2,3</c>
+ containing <c>p</c> or <c>P</c>, a field width of value
+ <c>0</c> means that no line breaks are inserted. This is
+ in contrast to the old behaviour, where <c>0</c> used to
+ insert line breaks after every subterm. To insert line
+ breaks after every subterm, a field width of value
+ <c>1</c> can be used. </p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15103 Aux Id: ERL-607 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>STDLIB 3.4.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -3221,7 +3659,7 @@
you use erlang:halt/2 with an integer first argument and
an option list containing {flush,false} as the second
argument. Note that now is flushing not dependant of the
- exit code, and you can not only flush async threads
+ exit code, and you cannot only flush async threads
operations which we deemed as a strange behaviour anyway.
</p>
<p>Also, erlang:halt/1,2 has gotten a new feature: If the
@@ -3735,9 +4173,9 @@
Supervisors should not save child-specs for temporary
processes when they terminate as they should not be
restarted. Saving the temporary child spec will result in
- that you can not start a new temporary process with the
+ that you cannot start a new temporary process with the
same child spec as an already terminated temporary
- process. Since R14B02 you can not restart a temporary
+ process. Since R14B02 you cannot restart a temporary
temporary process as arguments are no longer saved, it
has however always been semantically incorrect to restart
a temporary process. Thanks to Filipe David Manana for
diff --git a/lib/stdlib/doc/src/ordsets.xml b/lib/stdlib/doc/src/ordsets.xml
index 2d891d7a5a..11f98c8fb7 100644
--- a/lib/stdlib/doc/src/ordsets.xml
+++ b/lib/stdlib/doc/src/ordsets.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/proc_lib.xml b/lib/stdlib/doc/src/proc_lib.xml
index cb152d1935..b85fab67d5 100644
--- a/lib/stdlib/doc/src/proc_lib.xml
+++ b/lib/stdlib/doc/src/proc_lib.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -59,18 +59,17 @@
<p>When a process that is started using <c>proc_lib</c> terminates
abnormally (that is, with another exit reason than <c>normal</c>,
<c>shutdown</c>, or <c>{shutdown,Term}</c>), a <em>crash report</em>
- is generated, which is written to terminal by the default SASL
- event handler. That is, the crash report is normally only visible
- if the SASL application is started; see
- <seealso marker="sasl:sasl_app"><c>sasl(6)</c></seealso> and section
+ is generated, which is written to terminal by the default logger
+ handler setup by Kernel. For more information about how crash reports
+ were logged prior to Erlang/OTP 21.0, see
<seealso marker="sasl:error_logging">SASL Error Logging</seealso>
in the SASL User's Guide.</p>
<p>Unlike in "plain Erlang", <c>proc_lib</c> processes will not generate
<em>error reports</em>, which are written to the terminal by the
- emulator and do not require SASL to be started. All exceptions are
+ emulator. All exceptions are
converted to <em>exits</em> which are ignored by the default
- <c>error_logger</c> handler.</p>
+ <c>logger</c> handler.</p>
<p>The crash report contains the previously stored information, such
as ancestors and initial function, the termination reason, and
@@ -115,12 +114,22 @@
<name name="format" arity="2"/>
<fsummary>Format a crash report.</fsummary>
<desc>
- <p>This function can be used by a user-defined event handler to
+ <note>
+ <p>This function is deprecated in the sense that
+ the <c>error_logger</c> is no longer the preferred
+ interface for logging in Erlang/OTP. A
+ new <seealso marker="kernel:logger_chapter">logging
+ API</seealso> was added in Erlang/OTP 21.0, but
+ legacy <c>error_logger</c> handlers can still be used. New
+ Logger handlers do not need to use this function, since
+ the formatting callback (<c>report_cb</c>) is included as
+ metadata in the log event.</p>
+ </note>
+ <p>This function can be used by a user-defined legacy
+ <c>error_logger</c> event handler to
format a crash report. The crash report is sent using
- <seealso marker="kernel:error_logger#error_report/2">
- <c>error_logger:error_report(crash_report,
- <anno>CrashReport</anno>)</c></seealso>.
- That is, the event to be handled is of the format
+ <seealso marker="kernel:logger">
+ <c>logger(3)</c></seealso>, and the event to be handled is of the format
<c>{error_report, GL, {Pid, crash_report,
<anno>CrashReport</anno>}}</c>,
where <c>GL</c> is the group leader pid of process
@@ -132,7 +141,19 @@
<name name="format" arity="3"/>
<fsummary>Format a crash report.</fsummary>
<desc>
- <p>This function can be used by a user-defined event handler to
+ <note>
+ <p>This function is deprecated in the sense that
+ the <c>error_logger</c> is no longer the preferred
+ interface for logging in Erlang/OTP. A
+ new <seealso marker="kernel:logger_chapter">logging
+ API</seealso> was added in Erlang/OTP 21.0, but
+ legacy <c>error_logger</c> handlers can still be used. New
+ Logger handlers do not need to used this function, since
+ the formatting callback (<c>report_cb</c>) is included as
+ metadata in the log event.</p>
+ </note>
+ <p>This function can be used by a user-defined legacy
+ <c>error_logger</c> event handler to
format a crash report. When <anno>Depth</anno> is specified as a
positive integer, it is used in the format string to
limit the output as follows: <c>io_lib:format("~P",
@@ -395,6 +416,8 @@ init(Parent) ->
<title>See Also</title>
<p><seealso marker="kernel:error_logger">
<c>error_logger(3)</c></seealso></p>
+ <p><seealso marker="kernel:logger">
+ <c>logger(3)</c></seealso></p>
</section>
</erlref>
diff --git a/lib/stdlib/doc/src/ref_man.xml b/lib/stdlib/doc/src/ref_man.xml
index 68bfddbc71..8d61833d1f 100644
--- a/lib/stdlib/doc/src/ref_man.xml
+++ b/lib/stdlib/doc/src/ref_man.xml
@@ -4,7 +4,7 @@
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -66,7 +66,6 @@
<xi:include href="gen_statem.xml"/>
<xi:include href="io.xml"/>
<xi:include href="io_lib.xml"/>
- <xi:include href="lib.xml"/>
<xi:include href="lists.xml"/>
<xi:include href="log_mf_h.xml"/>
<xi:include href="maps.xml"/>
diff --git a/lib/stdlib/doc/src/sets.xml b/lib/stdlib/doc/src/sets.xml
index 1ed96ddc3f..8db3e1e623 100644
--- a/lib/stdlib/doc/src/sets.xml
+++ b/lib/stdlib/doc/src/sets.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2000</year><year>2017</year>
+ <year>2000</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/specs.xml b/lib/stdlib/doc/src/specs.xml
index d559adf9b6..fd2d625685 100644
--- a/lib/stdlib/doc/src/specs.xml
+++ b/lib/stdlib/doc/src/specs.xml
@@ -33,7 +33,6 @@
<xi:include href="../specs/specs_gen_statem.xml"/>
<xi:include href="../specs/specs_io.xml"/>
<xi:include href="../specs/specs_io_lib.xml"/>
- <xi:include href="../specs/specs_lib.xml"/>
<xi:include href="../specs/specs_lists.xml"/>
<xi:include href="../specs/specs_log_mf_h.xml"/>
<xi:include href="../specs/specs_maps.xml"/>
diff --git a/lib/stdlib/doc/src/string.xml b/lib/stdlib/doc/src/string.xml
index 4a3d37dcb6..3348464eba 100644
--- a/lib/stdlib/doc/src/string.xml
+++ b/lib/stdlib/doc/src/string.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/sys.xml b/lib/stdlib/doc/src/sys.xml
index 59e5bb6cb5..9fe816e33a 100644
--- a/lib/stdlib/doc/src/sys.xml
+++ b/lib/stdlib/doc/src/sys.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/doc/src/timer.xml b/lib/stdlib/doc/src/timer.xml
index 53107ade2c..e913e33589 100644
--- a/lib/stdlib/doc/src/timer.xml
+++ b/lib/stdlib/doc/src/timer.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/stdlib/include/assert.hrl b/lib/stdlib/include/assert.hrl
index 2ec89e7d8a..28d25c6589 100644
--- a/lib/stdlib/include/assert.hrl
+++ b/lib/stdlib/include/assert.hrl
@@ -140,7 +140,7 @@
-endif.
%% This is mostly a convenience which gives more detailed reports.
-%% Note: Guard is a guarded pattern, and can not be used for value.
+%% Note: Guard is a guarded pattern, and cannot be used for value.
-ifdef(NOASSERT).
-define(assertMatch(Guard, Expr), ok).
-define(assertMatch(Guard, Expr, Comment), ok).
@@ -289,7 +289,7 @@
end).
-endif.
-%% Note: Class and Term are patterns, and can not be used for value.
+%% Note: Class and Term are patterns, and cannot be used for value.
%% Term can be a guarded pattern, but Class cannot.
-ifdef(NOASSERT).
-define(assertException(Class, Term, Expr), ok).
@@ -364,7 +364,7 @@
?assertException(throw, Term, Expr, Comment)).
%% This is the inverse case of assertException, for convenience.
-%% Note: Class and Term are patterns, and can not be used for value.
+%% Note: Class and Term are patterns, and cannot be used for value.
%% Both Class and Term can be guarded patterns.
-ifdef(NOASSERT).
-define(assertNotException(Class, Term, Expr), ok).
diff --git a/lib/stdlib/src/Makefile b/lib/stdlib/src/Makefile
index dc3735055a..c95f7637f7 100644
--- a/lib/stdlib/src/Makefile
+++ b/lib/stdlib/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2017. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -62,6 +62,7 @@ MODULES= \
erl_anno \
erl_bits \
erl_compile \
+ erl_error \
erl_eval \
erl_expand_records \
erl_internal \
@@ -91,7 +92,6 @@ MODULES= \
io_lib_format \
io_lib_fread \
io_lib_pretty \
- lib \
lists \
log_mf_h \
maps \
@@ -176,6 +176,7 @@ docs:
primary_bootstrap_compiler: \
$(BOOTSTRAP_COMPILER)/ebin/epp.beam \
$(BOOTSTRAP_COMPILER)/ebin/erl_anno.beam \
+ $(BOOTSTRAP_COMPILER)/ebin/erl_error.beam \
$(BOOTSTRAP_COMPILER)/ebin/erl_scan.beam \
$(BOOTSTRAP_COMPILER)/ebin/erl_parse.beam \
$(BOOTSTRAP_COMPILER)/ebin/erl_lint.beam \
diff --git a/lib/stdlib/src/array.erl b/lib/stdlib/src/array.erl
index a237eaa489..939b1fb488 100644
--- a/lib/stdlib/src/array.erl
+++ b/lib/stdlib/src/array.erl
@@ -290,7 +290,7 @@ new(Size, Fixed, Default) ->
end,
#array{size = Size, max = M, default = Default, elements = E}.
--spec find_max(integer(), integer()) -> integer().
+-spec find_max(integer(), non_neg_integer()) -> non_neg_integer().
find_max(I, M) when I >= M ->
find_max(I, ?extend(M));
diff --git a/lib/stdlib/src/beam_lib.erl b/lib/stdlib/src/beam_lib.erl
index 24349c74e8..01181b1097 100644
--- a/lib/stdlib/src/beam_lib.erl
+++ b/lib/stdlib/src/beam_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -690,30 +690,31 @@ chunk_to_data(debug_info=Id, Chunk, File, _Cs, AtomTable, Mod) ->
<<0:8,N:8,Mode0:N/binary,Rest/binary>> ->
Mode = binary_to_atom(Mode0, utf8),
Term = decrypt_chunk(Mode, Mod, File, Id, Rest),
- {AtomTable, {Id, Term}};
+ {AtomTable, {Id, anno_from_term(Term)}};
_ ->
case catch binary_to_term(Chunk) of
{'EXIT', _} ->
error({invalid_chunk, File, chunk_name_to_id(Id, File)});
Term ->
- {AtomTable, {Id, Term}}
+ {AtomTable, {Id, anno_from_term(Term)}}
end
end;
chunk_to_data(abstract_code=Id, Chunk, File, _Cs, AtomTable, Mod) ->
+ %% Before Erlang/OTP 20.0.
case Chunk of
<<>> ->
{AtomTable, {Id, no_abstract_code}};
<<0:8,N:8,Mode0:N/binary,Rest/binary>> ->
Mode = binary_to_atom(Mode0, utf8),
Term = decrypt_chunk(Mode, Mod, File, Id, Rest),
- {AtomTable, {Id, anno_from_term(Term)}};
+ {AtomTable, {Id, old_anno_from_term(Term)}};
_ ->
case catch binary_to_term(Chunk) of
{'EXIT', _} ->
error({invalid_chunk, File, chunk_name_to_id(Id, File)});
Term ->
try
- {AtomTable, {Id, anno_from_term(Term)}}
+ {AtomTable, {Id, old_anno_from_term(Term)}}
catch
_:_ ->
error({invalid_chunk, File,
@@ -947,14 +948,24 @@ decrypt_chunk(Type, Module, File, Id, Bin) ->
error({key_missing_or_invalid, File, Id})
end.
-anno_from_term({raw_abstract_v1, Forms}) ->
+old_anno_from_term({raw_abstract_v1, Forms}) ->
{raw_abstract_v1, anno_from_forms(Forms)};
-anno_from_term({Tag, Forms}) when Tag =:= abstract_v1; Tag =:= abstract_v2 ->
+old_anno_from_term({Tag, Forms}) when Tag =:= abstract_v1;
+ Tag =:= abstract_v2 ->
try {Tag, anno_from_forms(Forms)}
catch
_:_ ->
{Tag, Forms}
end;
+old_anno_from_term(T) ->
+ T.
+
+anno_from_term({debug_info_v1=Tag1, erl_abstract_code=Tag2, {Forms, Opts}}) ->
+ try {Tag1, Tag2, {anno_from_forms(Forms), Opts}}
+ catch
+ _:_ ->
+ {Tag1, Tag2, {Forms, Opts}}
+ end;
anno_from_term(T) ->
T.
diff --git a/lib/stdlib/src/binary.erl b/lib/stdlib/src/binary.erl
index 7d0e42489e..52b9fedc9c 100644
--- a/lib/stdlib/src/binary.erl
+++ b/lib/stdlib/src/binary.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/src/c.erl b/lib/stdlib/src/c.erl
index 13f78841aa..0362b72536 100644
--- a/lib/stdlib/src/c.erl
+++ b/lib/stdlib/src/c.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl
index e1a36abc70..e016d5a80e 100644
--- a/lib/stdlib/src/dets.erl
+++ b/lib/stdlib/src/dets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/src/dets_utils.erl b/lib/stdlib/src/dets_utils.erl
index 4c8ea9e82b..12394bd1ad 100644
--- a/lib/stdlib/src/dets_utils.erl
+++ b/lib/stdlib/src/dets_utils.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/src/edlin.erl b/lib/stdlib/src/edlin.erl
index 5df9c504f9..f027d05f55 100644
--- a/lib/stdlib/src/edlin.erl
+++ b/lib/stdlib/src/edlin.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index 77cc88eb08..cc34d4bdd3 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -38,7 +38,7 @@
-type epp_handle() :: pid().
-type source_encoding() :: latin1 | utf8.
--type ifdef() :: 'ifdef' | 'ifndef' | 'else'.
+-type ifdef() :: 'ifdef' | 'ifndef' | 'if' | 'else'.
-type name() :: atom().
-type argspec() :: 'none' %No arguments
@@ -221,6 +221,8 @@ format_error({illegal_function,Macro}) ->
io_lib:format("?~s can only be used within a function", [Macro]);
format_error({illegal_function_usage,Macro}) ->
io_lib:format("?~s must not begin a form", [Macro]);
+format_error(elif_after_else) ->
+ "'elif' following 'else'";
format_error({'NYI',What}) ->
io_lib:format("not yet implemented '~s'", [What]);
format_error({error,Term}) ->
@@ -571,6 +573,7 @@ init_server(Pid, Name, Options, St0) ->
predef_macros(File) ->
Machine = list_to_atom(erlang:system_info(machine)),
Anno = line1(),
+ OtpVersion = list_to_integer(erlang:system_info(otp_release)),
Defs = [{'FILE', {none,[{string,Anno,File}]}},
{'FUNCTION_NAME', undefined},
{'FUNCTION_ARITY', undefined},
@@ -580,7 +583,8 @@ predef_macros(File) ->
{'BASE_MODULE', undefined},
{'BASE_MODULE_STRING', undefined},
{'MACHINE', {none,[{atom,Anno,Machine}]}},
- {Machine, {none,[{atom,Anno,true}]}}
+ {Machine, {none,[{atom,Anno,true}]}},
+ {'OTP_RELEASE', {none,[{integer,Anno,OtpVersion}]}}
],
maps:from_list(Defs).
@@ -1085,21 +1089,118 @@ scan_else(_Toks, Else, From, St) ->
epp_reply(From, {error,{loc(Else),epp,{bad,'else'}}}),
wait_req_scan(St).
-%% scan_if(Tokens, EndifToken, From, EppState)
+%% scan_if(Tokens, IfToken, From, EppState)
%% Handle the conditional parsing of a file.
-%% Report a badly formed if test and then treat as false macro.
+scan_if([{'(',_}|_]=Toks, If, From, St) ->
+ try eval_if(Toks, St) of
+ true ->
+ scan_toks(From, St#epp{istk=['if'|St#epp.istk]});
+ _ ->
+ skip_toks(From, St, ['if'])
+ catch
+ throw:Error0 ->
+ Error = case Error0 of
+ {_,erl_parse,_} ->
+ {error,Error0};
+ _ ->
+ {error,{loc(If),epp,Error0}}
+ end,
+ epp_reply(From, Error),
+ wait_req_skip(St, ['if'])
+ end;
scan_if(_Toks, If, From, St) ->
- epp_reply(From, {error,{loc(If),epp,{'NYI','if'}}}),
+ epp_reply(From, {error,{loc(If),epp,{bad,'if'}}}),
wait_req_skip(St, ['if']).
+eval_if(Toks0, St) ->
+ Toks = expand_macros(Toks0, St),
+ Es1 = case erl_parse:parse_exprs(Toks) of
+ {ok,Es0} -> Es0;
+ {error,E} -> throw(E)
+ end,
+ Es = rewrite_expr(Es1, St),
+ assert_guard_expr(Es),
+ Bs = erl_eval:new_bindings(),
+ LocalFun = fun(_Name, _Args) ->
+ error(badarg)
+ end,
+ try erl_eval:exprs(Es, Bs, {value,LocalFun}) of
+ {value,Res,_} ->
+ Res
+ catch
+ _:_ ->
+ false
+ end.
+
+assert_guard_expr([E0]) ->
+ E = rewrite_expr(E0, none),
+ case erl_lint:is_guard_expr(E) of
+ false ->
+ throw({bad,'if'});
+ true ->
+ ok
+ end;
+assert_guard_expr(_) ->
+ throw({bad,'if'}).
+
+%% Dual-purpose rewriting function. When the second argument is
+%% an #epp{} record, calls to defined(Symbol) will be evaluated.
+%% When the second argument is 'none', legal calls to our built-in
+%% functions are eliminated in order to turn the expression into
+%% a legal guard expression.
+
+rewrite_expr({call,_,{atom,_,defined},[N0]}, #epp{macs=Macs}) ->
+ %% Evaluate defined(Symbol).
+ N = case N0 of
+ {var,_,N1} -> N1;
+ {atom,_,N1} -> N1;
+ _ -> throw({bad,'if'})
+ end,
+ {atom,0,maps:is_key(N, Macs)};
+rewrite_expr({call,_,{atom,_,Name},As0}, none) ->
+ As = rewrite_expr(As0, none),
+ Arity = length(As),
+ case erl_internal:bif(Name, Arity) andalso
+ not erl_internal:guard_bif(Name, Arity) of
+ false ->
+ %% A guard BIF, an -if built-in, or an unknown function.
+ %% Eliminate the call so that erl_lint will not complain.
+ %% The call might fail later at evaluation time.
+ to_conses(As);
+ true ->
+ %% An auto-imported BIF (not guard BIF). Not allowed.
+ throw({bad,'if'})
+ end;
+rewrite_expr([H|T], St) ->
+ [rewrite_expr(H, St)|rewrite_expr(T, St)];
+rewrite_expr(Tuple, St) when is_tuple(Tuple) ->
+ list_to_tuple(rewrite_expr(tuple_to_list(Tuple), St));
+rewrite_expr(Other, _) ->
+ Other.
+
+to_conses([H|T]) ->
+ {cons,0,H,to_conses(T)};
+to_conses([]) ->
+ {nil,0}.
+
%% scan_elif(Tokens, EndifToken, From, EppState)
%% Handle the conditional parsing of a file.
%% Report a badly formed if test and then treat as false macro.
scan_elif(_Toks, Elif, From, St) ->
- epp_reply(From, {error,{loc(Elif),epp,{'NYI','elif'}}}),
- wait_req_scan(St).
+ case St#epp.istk of
+ ['else'|Cis] ->
+ epp_reply(From, {error,{loc(Elif),
+ epp,{illegal,"unbalanced",'elif'}}}),
+ wait_req_skip(St#epp{istk=Cis}, ['else']);
+ [_I|Cis] ->
+ skip_toks(From, St#epp{istk=Cis}, ['elif']);
+ [] ->
+ epp_reply(From, {error,{loc(Elif),epp,
+ {illegal,"unbalanced",elif}}}),
+ wait_req_scan(St)
+ end.
%% scan_endif(Tokens, EndifToken, From, EppState)
%% If we are in an if body then exit it, else report an error.
@@ -1158,6 +1259,8 @@ skip_toks(From, St, [I|Sis]) ->
skip_toks(From, St#epp{location=Cl}, ['if',I|Sis]);
{ok,[{'-',_Lh},{atom,_Le,'else'}=Else|_Toks],Cl}->
skip_else(Else, From, St#epp{location=Cl}, [I|Sis]);
+ {ok,[{'-',_Lh},{atom,_Le,'elif'}=Elif|Toks],Cl}->
+ skip_elif(Toks, Elif, From, St#epp{location=Cl}, [I|Sis]);
{ok,[{'-',_Lh},{atom,_Le,endif}|_Toks],Cl} ->
skip_toks(From, St#epp{location=Cl}, Sis);
{ok,_Toks,Cl} ->
@@ -1188,11 +1291,21 @@ skip_toks(From, St, []) ->
skip_else(Else, From, St, ['else'|Sis]) ->
epp_reply(From, {error,{loc(Else),epp,{illegal,"repeated",'else'}}}),
wait_req_skip(St, ['else'|Sis]);
+skip_else(_Else, From, St, ['elif'|Sis]) ->
+ skip_toks(From, St, ['else'|Sis]);
skip_else(_Else, From, St, [_I]) ->
scan_toks(From, St#epp{istk=['else'|St#epp.istk]});
skip_else(_Else, From, St, Sis) ->
skip_toks(From, St, Sis).
+skip_elif(_Toks, Elif, From, St, ['else'|_]=Sis) ->
+ epp_reply(From, {error,{loc(Elif),epp,elif_after_else}}),
+ wait_req_skip(St, Sis);
+skip_elif(Toks, Elif, From, St, [_I]) ->
+ scan_if(Toks, Elif, From, St);
+skip_elif(_Toks, _Elif, From, St, Sis) ->
+ skip_toks(From, St, Sis).
+
%% macro_pars(Tokens, ArgStack)
%% macro_expansion(Tokens, Anno)
%% Extract the macro parameters and the expansion from a macro definition.
diff --git a/lib/stdlib/src/lib.erl b/lib/stdlib/src/erl_error.erl
index 51e0c3f77e..fdcb9e824c 100644
--- a/lib/stdlib/src/lib.erl
+++ b/lib/stdlib/src/erl_error.erl
@@ -17,337 +17,12 @@
%%
%% %CopyrightEnd%
%%
--module(lib).
-
--export([flush_receive/0, error_message/2, progname/0, nonl/1, send/2,
- sendw/2, eval_str/1]).
-
--export([extended_parse_exprs/1, extended_parse_term/1,
- subst_values_for_vars/2]).
+-module(erl_error).
-export([format_exception/6, format_exception/7,
format_stacktrace/4, format_stacktrace/5,
format_call/4, format_call/5, format_fun/1, format_fun/2]).
--spec flush_receive() -> 'ok'.
-
-flush_receive() ->
- receive
- _Any ->
- flush_receive()
- after
- 0 ->
- ok
- end.
-
-%%
-%% Functions for doing standard system format i/o.
-%%
--spec error_message(Format, Args) -> 'ok' when
- Format :: io:format(),
- Args :: [term()].
-
-error_message(Format, Args) ->
- io:format(<<"** ~ts **\n">>, [io_lib:format(Format, Args)]).
-
-%% Return the name of the script that starts (this) erlang
-%%
--spec progname() -> atom().
-
-progname() ->
- case init:get_argument(progname) of
- {ok, [[Prog]]} ->
- list_to_atom(Prog);
- _Other ->
- no_prog_name
- end.
-
--spec nonl(String1) -> String2 when
- String1 :: string(),
- String2 :: string().
-
-nonl([10]) -> [];
-nonl([]) -> [];
-nonl([H|T]) -> [H|nonl(T)].
-
--spec send(To, Msg) -> Msg when
- To :: pid() | atom() | {atom(), node()},
- Msg :: term().
-
-send(To, Msg) -> To ! Msg.
-
--spec sendw(To, Msg) -> term() when
- To :: pid() | atom() | {atom(), node()},
- Msg :: term().
-
-sendw(To, Msg) ->
- To ! {self(), Msg},
- receive
- Reply -> Reply
- end.
-
-%% eval_str(InStr) -> {ok, OutStr} | {error, ErrStr'}
-%% InStr must represent a body
-%% Note: If InStr is a binary it has to be a Latin-1 string.
-%% If you have a UTF-8 encoded binary you have to call
-%% unicode:characters_to_list/1 before the call to eval_str().
-
--define(result(F,D), lists:flatten(io_lib:format(F, D))).
-
--spec eval_str(string() | unicode:latin1_binary()) ->
- {'ok', string()} | {'error', string()}.
-
-eval_str(Str) when is_list(Str) ->
- case erl_scan:tokens([], Str, 0) of
- {more, _} ->
- {error, "Incomplete form (missing .<cr>)??"};
- {done, {ok, Toks, _}, Rest} ->
- case all_white(Rest) of
- true ->
- case erl_parse:parse_exprs(Toks) of
- {ok, Exprs} ->
- case catch erl_eval:exprs(Exprs, erl_eval:new_bindings()) of
- {value, Val, _} ->
- {ok, Val};
- Other ->
- {error, ?result("*** eval: ~p", [Other])}
- end;
- {error, {_Line, Mod, Args}} ->
- Msg = ?result("*** ~ts",[Mod:format_error(Args)]),
- {error, Msg}
- end;
- false ->
- {error, ?result("Non-white space found after "
- "end-of-form :~ts", [Rest])}
- end
- end;
-eval_str(Bin) when is_binary(Bin) ->
- eval_str(binary_to_list(Bin)).
-
-all_white([$\s|T]) -> all_white(T);
-all_white([$\n|T]) -> all_white(T);
-all_white([$\t|T]) -> all_white(T);
-all_white([]) -> true;
-all_white(_) -> false.
-
-%% `Tokens' is assumed to have been scanned with the 'text' option.
-%% The annotations of the returned expressions are locations.
-%%
-%% Can handle pids, ports, references, and external funs ("items").
-%% Known items are represented by variables in the erl_parse tree, and
-%% the items themselves are stored in the returned bindings.
-
--spec extended_parse_exprs(Tokens) ->
- {'ok', ExprList, Bindings} | {'error', ErrorInfo} when
- Tokens :: [erl_scan:token()],
- ExprList :: [erl_parse:abstract_expr()],
- Bindings :: erl_eval:binding_struct(),
- ErrorInfo :: erl_parse:error_info().
-
-extended_parse_exprs(Tokens) ->
- Ts = tokens_fixup(Tokens),
- case erl_parse:parse_exprs(Ts) of
- {ok, Exprs0} ->
- {Exprs, Bs} = expr_fixup(Exprs0),
- {ok, reset_expr_anno(Exprs), Bs};
- _ErrorInfo ->
- erl_parse:parse_exprs(reset_token_anno(Ts))
- end.
-
-tokens_fixup([]) -> [];
-tokens_fixup([T|Ts]=Ts0) ->
- try token_fixup(Ts0) of
- {NewT, NewTs} ->
- [NewT|tokens_fixup(NewTs)]
- catch
- _:_ ->
- [T|tokens_fixup(Ts)]
- end.
-
-token_fixup(Ts) ->
- {AnnoL, NewTs, FixupTag} = unscannable(Ts),
- String = lists:append([erl_anno:text(A) || A <- AnnoL]),
- _ = (fixup_fun(FixupTag))(String),
- NewAnno = erl_anno:set_text(fixup_text(FixupTag), hd(AnnoL)),
- {{string, NewAnno, String}, NewTs}.
-
-unscannable([{'#', A1}, {var, A2, 'Fun'}, {'<', A3}, {atom, A4, _},
- {'.', A5}, {float, A6, _}, {'>', A7}|Ts]) ->
- {[A1, A2, A3, A4, A5, A6, A7], Ts, function};
-unscannable([{'#', A1}, {var, A2, 'Fun'}, {'<', A3}, {atom, A4, _},
- {'.', A5}, {atom, A6, _}, {'.', A7}, {integer, A8, _},
- {'>', A9}|Ts]) ->
- {[A1, A2, A3, A4, A5, A6, A7, A8, A9], Ts, function};
-unscannable([{'<', A1}, {float, A2, _}, {'.', A3}, {integer, A4, _},
- {'>', A5}|Ts]) ->
- {[A1, A2, A3, A4, A5], Ts, pid};
-unscannable([{'#', A1}, {var, A2, 'Port'}, {'<', A3}, {float, A4, _},
- {'>', A5}|Ts]) ->
- {[A1, A2, A3, A4, A5], Ts, port};
-unscannable([{'#', A1}, {var, A2, 'Ref'}, {'<', A3}, {float, A4, _},
- {'.', A5}, {float, A6, _}, {'>', A7}|Ts]) ->
- {[A1, A2, A3, A4, A5, A6, A7], Ts, reference}.
-
-expr_fixup(Expr0) ->
- {Expr, Bs, _} = expr_fixup(Expr0, erl_eval:new_bindings(), 1),
- {Expr, Bs}.
-
-expr_fixup({string,A,S}=T, Bs0, I) ->
- try string_fixup(A, S) of
- Value ->
- Var = new_var(I),
- Bs = erl_eval:add_binding(Var, Value, Bs0),
- {{var, A, Var}, Bs, I+1}
- catch
- _:_ ->
- {T, Bs0, I}
- end;
-expr_fixup(Tuple, Bs0, I0) when is_tuple(Tuple) ->
- {L, Bs, I} = expr_fixup(tuple_to_list(Tuple), Bs0, I0),
- {list_to_tuple(L), Bs, I};
-expr_fixup([E0|Es0], Bs0, I0) ->
- {E, Bs1, I1} = expr_fixup(E0, Bs0, I0),
- {Es, Bs, I} = expr_fixup(Es0, Bs1, I1),
- {[E|Es], Bs, I};
-expr_fixup(T, Bs, I) ->
- {T, Bs, I}.
-
-string_fixup(A, S) ->
- Text = erl_anno:text(A),
- FixupTag = fixup_tag(Text, S),
- (fixup_fun(FixupTag))(S).
-
-new_var(I) ->
- list_to_atom(lists:concat(['__ExtendedParseExprs_', I, '__'])).
-
-reset_token_anno(Tokens) ->
- [setelement(2, T, (reset_anno())(element(2, T))) || T <- Tokens].
-
-reset_expr_anno(Exprs) ->
- [erl_parse:map_anno(reset_anno(), E) || E <- Exprs].
-
-reset_anno() ->
- fun(A) -> erl_anno:new(erl_anno:location(A)) end.
-
-fixup_fun(function) -> fun function/1;
-fixup_fun(pid) -> fun erlang:list_to_pid/1;
-fixup_fun(port) -> fun erlang:list_to_port/1;
-fixup_fun(reference) -> fun erlang:list_to_ref/1.
-
-function(S) ->
- %% External function.
- {ok, [_, _, _,
- {atom, _, Module}, _,
- {atom, _, Function}, _,
- {integer, _, Arity}|_], _} = erl_scan:string(S),
- erlang:make_fun(Module, Function, Arity).
-
-fixup_text(function) -> "function";
-fixup_text(pid) -> "pid";
-fixup_text(port) -> "port";
-fixup_text(reference) -> "reference".
-
-fixup_tag("function", "#"++_) -> function;
-fixup_tag("pid", "<"++_) -> pid;
-fixup_tag("port", "#"++_) -> port;
-fixup_tag("reference", "#"++_) -> reference.
-
-%%% End of extended_parse_exprs.
-
-%% `Tokens' is assumed to have been scanned with the 'text' option.
-%%
-%% Can handle pids, ports, references, and external funs.
-
--spec extended_parse_term(Tokens) ->
- {'ok', Term} | {'error', ErrorInfo} when
- Tokens :: [erl_scan:token()],
- Term :: term(),
- ErrorInfo :: erl_parse:error_info().
-
-extended_parse_term(Tokens) ->
- case extended_parse_exprs(Tokens) of
- {ok, [Expr], Bindings} ->
- try normalise(Expr, Bindings) of
- Term ->
- {ok, Term}
- catch
- _:_ ->
- Loc = erl_anno:location(element(2, Expr)),
- {error,{Loc,?MODULE,"bad term"}}
- end;
- {ok, [_,Expr|_], _Bindings} ->
- Loc = erl_anno:location(element(2, Expr)),
- {error,{Loc,?MODULE,"bad term"}};
- {error, _} = Error ->
- Error
- end.
-
-%% From erl_parse.
-normalise({var, _, V}, Bs) ->
- {value, Value} = erl_eval:binding(V, Bs),
- Value;
-normalise({char,_,C}, _Bs) -> C;
-normalise({integer,_,I}, _Bs) -> I;
-normalise({float,_,F}, _Bs) -> F;
-normalise({atom,_,A}, _Bs) -> A;
-normalise({string,_,S}, _Bs) -> S;
-normalise({nil,_}, _Bs) -> [];
-normalise({bin,_,Fs}, Bs) ->
- {value, B, _} =
- eval_bits:expr_grp(Fs, [],
- fun(E, _) ->
- {value, normalise(E, Bs), []}
- end, [], true),
- B;
-normalise({cons,_,Head,Tail}, Bs) ->
- [normalise(Head, Bs)|normalise(Tail, Bs)];
-normalise({tuple,_,Args}, Bs) ->
- list_to_tuple(normalise_list(Args, Bs));
-normalise({map,_,Pairs}, Bs) ->
- maps:from_list(lists:map(fun
- %% only allow '=>'
- ({map_field_assoc,_,K,V}) ->
- {normalise(K, Bs),normalise(V, Bs)}
- end, Pairs));
-%% Special case for unary +/-.
-normalise({op,_,'+',{char,_,I}}, _Bs) -> I;
-normalise({op,_,'+',{integer,_,I}}, _Bs) -> I;
-normalise({op,_,'+',{float,_,F}}, _Bs) -> F;
-normalise({op,_,'-',{char,_,I}}, _Bs) -> -I; %Weird, but compatible!
-normalise({op,_,'-',{integer,_,I}}, _Bs) -> -I;
-normalise({op,_,'-',{float,_,F}}, _Bs) -> -F;
-normalise({'fun',_,{function,{atom,_,M},{atom,_,F},{integer,_,A}}}, _Bs) ->
- %% Since "#Fun<M.F.A>" is recognized, "fun M:F/A" should be too.
- fun M:F/A.
-
-normalise_list([H|T], Bs) ->
- [normalise(H, Bs)|normalise_list(T, Bs)];
-normalise_list([], _Bs) ->
- [].
-
-%% To be used on ExprList and Bindings returned from extended_parse_exprs().
-%% Substitute {value, A, Item} for {var, A, ExtendedParseVar}.
-%% {value, A, Item} is a shell/erl_eval convention, and for example
-%% the linter cannot handle it.
-
--spec subst_values_for_vars(ExprList, Bindings) -> [term()] when
- ExprList :: [erl_parse:abstract_expr()],
- Bindings :: erl_eval:binding_struct().
-
-subst_values_for_vars({var, A, V}=Var, Bs) ->
- case erl_eval:binding(V, Bs) of
- {value, Value} ->
- {value, A, Value};
- unbound ->
- Var
- end;
-subst_values_for_vars(L, Bs) when is_list(L) ->
- [subst_values_for_vars(E, Bs) || E <- L];
-subst_values_for_vars(T, Bs) when is_tuple(T) ->
- list_to_tuple(subst_values_for_vars(tuple_to_list(T), Bs));
-subst_values_for_vars(T, _Bs) ->
- T.
-
%%% Formatting of exceptions, mfa:s and funs.
%% -> iolist() (no \n at end)
diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl
index 4ee11383da..2066b2f60f 100644
--- a/lib/stdlib/src/erl_eval.erl
+++ b/lib/stdlib/src/erl_eval.erl
@@ -27,8 +27,9 @@
-export([exprs/2,exprs/3,exprs/4,expr/2,expr/3,expr/4,expr/5,
expr_list/2,expr_list/3,expr_list/4]).
-export([new_bindings/0,bindings/1,binding/2,add_binding/3,del_binding/2]).
-
--export([is_constant_expr/1, partial_eval/1]).
+-export([extended_parse_exprs/1, extended_parse_term/1,
+ subst_values_for_vars/2]).
+-export([is_constant_expr/1, partial_eval/1, eval_str/1]).
%% Is used by standalone Erlang (escript).
%% Also used by shell.erl.
@@ -328,7 +329,8 @@ expr({'fun',Line,{clauses,Cs}} = Ex, Bs, Lf, Ef, RBs) ->
20 -> fun (A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T) ->
eval_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T], Info) end;
_Other ->
- erlang:raise(error, {'argument_limit',{'fun',Line,Cs}},
+ L = erl_anno:location(Line),
+ erlang:raise(error, {'argument_limit',{'fun',L,to_terms(Cs)}},
?STACKTRACE)
end,
ret_expr(F, Bs, RBs);
@@ -380,7 +382,9 @@ expr({named_fun,Line,Name,Cs} = Ex, Bs, Lf, Ef, RBs) ->
eval_named_fun([A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T],
RF, Info) end;
_Other ->
- erlang:raise(error, {'argument_limit',{named_fun,Line,Name,Cs}},
+ L = erl_anno:location(Line),
+ erlang:raise(error, {'argument_limit',
+ {named_fun,L,Name,to_terms(Cs)}},
?STACKTRACE)
end,
ret_expr(F, Bs, RBs);
@@ -1091,7 +1095,7 @@ match(Pat, Term, Bs) ->
match(Pat, Term, Bs, BBs) ->
case catch match1(Pat, Term, Bs, BBs) of
invalid ->
- erlang:raise(error, {illegal_pattern,Pat}, ?STACKTRACE);
+ erlang:raise(error, {illegal_pattern,to_term(Pat)}, ?STACKTRACE);
Other ->
Other
end.
@@ -1286,6 +1290,230 @@ merge_bindings(Bs1, Bs2) ->
%% error -> Bs
%% end
%% end, Bs2, Bs1).
+
+to_terms(Abstrs) ->
+ [to_term(Abstr) || Abstr <- Abstrs].
+
+to_term(Abstr) ->
+ erl_parse:anno_to_term(Abstr).
+
+%% Substitute {value, A, Item} for {var, A, Var}, preserving A.
+%% {value, A, Item} is a shell/erl_eval convention, and for example
+%% the linter cannot handle it.
+
+-spec subst_values_for_vars(ExprList, Bindings) -> [term()] when
+ ExprList :: [erl_parse:abstract_expr()],
+ Bindings :: binding_struct().
+
+subst_values_for_vars({var, A, V}=Var, Bs) ->
+ case erl_eval:binding(V, Bs) of
+ {value, Value} ->
+ {value, A, Value};
+ unbound ->
+ Var
+ end;
+subst_values_for_vars(L, Bs) when is_list(L) ->
+ [subst_values_for_vars(E, Bs) || E <- L];
+subst_values_for_vars(T, Bs) when is_tuple(T) ->
+ list_to_tuple(subst_values_for_vars(tuple_to_list(T), Bs));
+subst_values_for_vars(T, _Bs) ->
+ T.
+
+%% `Tokens' is assumed to have been scanned with the 'text' option.
+%% The annotations of the returned expressions are locations.
+%%
+%% Can handle pids, ports, references, and external funs ("items").
+%% Known items are represented by variables in the erl_parse tree, and
+%% the items themselves are stored in the returned bindings.
+
+-spec extended_parse_exprs(Tokens) ->
+ {'ok', ExprList, Bindings} | {'error', ErrorInfo} when
+ Tokens :: [erl_scan:token()],
+ ExprList :: [erl_parse:abstract_expr()],
+ Bindings :: erl_eval:binding_struct(),
+ ErrorInfo :: erl_parse:error_info().
+
+extended_parse_exprs(Tokens) ->
+ Ts = tokens_fixup(Tokens),
+ case erl_parse:parse_exprs(Ts) of
+ {ok, Exprs0} ->
+ {Exprs, Bs} = expr_fixup(Exprs0),
+ {ok, reset_expr_anno(Exprs), Bs};
+ _ErrorInfo ->
+ erl_parse:parse_exprs(reset_token_anno(Ts))
+ end.
+
+tokens_fixup([]) -> [];
+tokens_fixup([T|Ts]=Ts0) ->
+ try token_fixup(Ts0) of
+ {NewT, NewTs} ->
+ [NewT|tokens_fixup(NewTs)]
+ catch
+ _:_ ->
+ [T|tokens_fixup(Ts)]
+ end.
+
+token_fixup(Ts) ->
+ {AnnoL, NewTs, FixupTag} = unscannable(Ts),
+ String = lists:append([erl_anno:text(A) || A <- AnnoL]),
+ _ = (fixup_fun(FixupTag))(String),
+ NewAnno = erl_anno:set_text(fixup_text(FixupTag), hd(AnnoL)),
+ {{string, NewAnno, String}, NewTs}.
+
+unscannable([{'#', A1}, {var, A2, 'Fun'}, {'<', A3}, {atom, A4, _},
+ {'.', A5}, {float, A6, _}, {'>', A7}|Ts]) ->
+ {[A1, A2, A3, A4, A5, A6, A7], Ts, function};
+unscannable([{'#', A1}, {var, A2, 'Fun'}, {'<', A3}, {atom, A4, _},
+ {'.', A5}, {atom, A6, _}, {'.', A7}, {integer, A8, _},
+ {'>', A9}|Ts]) ->
+ {[A1, A2, A3, A4, A5, A6, A7, A8, A9], Ts, function};
+unscannable([{'<', A1}, {float, A2, _}, {'.', A3}, {integer, A4, _},
+ {'>', A5}|Ts]) ->
+ {[A1, A2, A3, A4, A5], Ts, pid};
+unscannable([{'#', A1}, {var, A2, 'Port'}, {'<', A3}, {float, A4, _},
+ {'>', A5}|Ts]) ->
+ {[A1, A2, A3, A4, A5], Ts, port};
+unscannable([{'#', A1}, {var, A2, 'Ref'}, {'<', A3}, {float, A4, _},
+ {'.', A5}, {float, A6, _}, {'>', A7}|Ts]) ->
+ {[A1, A2, A3, A4, A5, A6, A7], Ts, reference}.
+
+expr_fixup(Expr0) ->
+ {Expr, Bs, _} = expr_fixup(Expr0, erl_eval:new_bindings(), 1),
+ {Expr, Bs}.
+
+expr_fixup({string,A,S}=T, Bs0, I) ->
+ try string_fixup(A, S) of
+ Value ->
+ Var = new_var(I),
+ Bs = erl_eval:add_binding(Var, Value, Bs0),
+ {{var, A, Var}, Bs, I+1}
+ catch
+ _:_ ->
+ {T, Bs0, I}
+ end;
+expr_fixup(Tuple, Bs0, I0) when is_tuple(Tuple) ->
+ {L, Bs, I} = expr_fixup(tuple_to_list(Tuple), Bs0, I0),
+ {list_to_tuple(L), Bs, I};
+expr_fixup([E0|Es0], Bs0, I0) ->
+ {E, Bs1, I1} = expr_fixup(E0, Bs0, I0),
+ {Es, Bs, I} = expr_fixup(Es0, Bs1, I1),
+ {[E|Es], Bs, I};
+expr_fixup(T, Bs, I) ->
+ {T, Bs, I}.
+
+string_fixup(A, S) ->
+ Text = erl_anno:text(A),
+ FixupTag = fixup_tag(Text, S),
+ (fixup_fun(FixupTag))(S).
+
+new_var(I) ->
+ list_to_atom(lists:concat(['__ExtendedParseExprs_', I, '__'])).
+
+reset_token_anno(Tokens) ->
+ [setelement(2, T, (reset_anno())(element(2, T))) || T <- Tokens].
+
+reset_expr_anno(Exprs) ->
+ [erl_parse:map_anno(reset_anno(), E) || E <- Exprs].
+
+reset_anno() ->
+ fun(A) -> erl_anno:new(erl_anno:location(A)) end.
+
+fixup_fun(function) -> fun function/1;
+fixup_fun(pid) -> fun erlang:list_to_pid/1;
+fixup_fun(port) -> fun erlang:list_to_port/1;
+fixup_fun(reference) -> fun erlang:list_to_ref/1.
+
+function(S) ->
+ %% External function.
+ {ok, [_, _, _,
+ {atom, _, Module}, _,
+ {atom, _, Function}, _,
+ {integer, _, Arity}|_], _} = erl_scan:string(S),
+ erlang:make_fun(Module, Function, Arity).
+
+fixup_text(function) -> "function";
+fixup_text(pid) -> "pid";
+fixup_text(port) -> "port";
+fixup_text(reference) -> "reference".
+
+fixup_tag("function", "#"++_) -> function;
+fixup_tag("pid", "<"++_) -> pid;
+fixup_tag("port", "#"++_) -> port;
+fixup_tag("reference", "#"++_) -> reference.
+
+%%% End of extended_parse_exprs.
+
+%% `Tokens' is assumed to have been scanned with the 'text' option.
+%%
+%% Can handle pids, ports, references, and external funs.
+
+-spec extended_parse_term(Tokens) ->
+ {'ok', Term} | {'error', ErrorInfo} when
+ Tokens :: [erl_scan:token()],
+ Term :: term(),
+ ErrorInfo :: erl_parse:error_info().
+
+extended_parse_term(Tokens) ->
+ case extended_parse_exprs(Tokens) of
+ {ok, [Expr], Bindings} ->
+ try normalise(Expr, Bindings) of
+ Term ->
+ {ok, Term}
+ catch
+ _:_ ->
+ Loc = erl_anno:location(element(2, Expr)),
+ {error,{Loc,?MODULE,"bad term"}}
+ end;
+ {ok, [_,Expr|_], _Bindings} ->
+ Loc = erl_anno:location(element(2, Expr)),
+ {error,{Loc,?MODULE,"bad term"}};
+ {error, _} = Error ->
+ Error
+ end.
+
+%% From erl_parse.
+normalise({var, _, V}, Bs) ->
+ {value, Value} = erl_eval:binding(V, Bs),
+ Value;
+normalise({char,_,C}, _Bs) -> C;
+normalise({integer,_,I}, _Bs) -> I;
+normalise({float,_,F}, _Bs) -> F;
+normalise({atom,_,A}, _Bs) -> A;
+normalise({string,_,S}, _Bs) -> S;
+normalise({nil,_}, _Bs) -> [];
+normalise({bin,_,Fs}, Bs) ->
+ {value, B, _} =
+ eval_bits:expr_grp(Fs, [],
+ fun(E, _) ->
+ {value, normalise(E, Bs), []}
+ end, [], true),
+ B;
+normalise({cons,_,Head,Tail}, Bs) ->
+ [normalise(Head, Bs)|normalise(Tail, Bs)];
+normalise({tuple,_,Args}, Bs) ->
+ list_to_tuple(normalise_list(Args, Bs));
+normalise({map,_,Pairs}, Bs) ->
+ maps:from_list(lists:map(fun
+ %% only allow '=>'
+ ({map_field_assoc,_,K,V}) ->
+ {normalise(K, Bs),normalise(V, Bs)}
+ end, Pairs));
+%% Special case for unary +/-.
+normalise({op,_,'+',{char,_,I}}, _Bs) -> I;
+normalise({op,_,'+',{integer,_,I}}, _Bs) -> I;
+normalise({op,_,'+',{float,_,F}}, _Bs) -> F;
+normalise({op,_,'-',{char,_,I}}, _Bs) -> -I; %Weird, but compatible!
+normalise({op,_,'-',{integer,_,I}}, _Bs) -> -I;
+normalise({op,_,'-',{float,_,F}}, _Bs) -> -F;
+normalise({'fun',_,{function,{atom,_,M},{atom,_,F},{integer,_,A}}}, _Bs) ->
+ %% Since "#Fun<M.F.A>" is recognized, "fun M:F/A" should be too.
+ fun M:F/A.
+
+normalise_list([H|T], Bs) ->
+ [normalise(H, Bs)|normalise_list(T, Bs)];
+normalise_list([], _Bs) ->
+ [].
+
%%----------------------------------------------------------------------------
%%
%% Evaluate expressions:
@@ -1338,6 +1566,50 @@ ev_expr({cons,_,H,T}) -> [ev_expr(H) | ev_expr(T)].
%% true = erl_internal:guard_bif(F, length(As)),
%% apply(erlang, F, [ev_expr(X) || X <- As]);
+%% eval_str(InStr) -> {ok, OutStr} | {error, ErrStr'}
+%% InStr must represent a body
+%% Note: If InStr is a binary it has to be a Latin-1 string.
+%% If you have a UTF-8 encoded binary you have to call
+%% unicode:characters_to_list/1 before the call to eval_str().
+
+-define(result(F,D), lists:flatten(io_lib:format(F, D))).
+
+-spec eval_str(string() | unicode:latin1_binary()) ->
+ {'ok', string()} | {'error', string()}.
+
+eval_str(Str) when is_list(Str) ->
+ case erl_scan:tokens([], Str, 0) of
+ {more, _} ->
+ {error, "Incomplete form (missing .<cr>)??"};
+ {done, {ok, Toks, _}, Rest} ->
+ case all_white(Rest) of
+ true ->
+ case erl_parse:parse_exprs(Toks) of
+ {ok, Exprs} ->
+ case catch erl_eval:exprs(Exprs, erl_eval:new_bindings()) of
+ {value, Val, _} ->
+ {ok, Val};
+ Other ->
+ {error, ?result("*** eval: ~p", [Other])}
+ end;
+ {error, {_Line, Mod, Args}} ->
+ Msg = ?result("*** ~ts",[Mod:format_error(Args)]),
+ {error, Msg}
+ end;
+ false ->
+ {error, ?result("Non-white space found after "
+ "end-of-form :~ts", [Rest])}
+ end
+ end;
+eval_str(Bin) when is_binary(Bin) ->
+ eval_str(binary_to_list(Bin)).
+
+all_white([$\s|T]) -> all_white(T);
+all_white([$\n|T]) -> all_white(T);
+all_white([$\t|T]) -> all_white(T);
+all_white([]) -> true;
+all_white(_) -> false.
+
ret_expr(_Old, New) ->
%% io:format("~w: reduced ~s => ~s~n",
%% [line(Old), erl_pp:expr(Old), erl_pp:expr(New)]),
diff --git a/lib/stdlib/src/erl_internal.erl b/lib/stdlib/src/erl_internal.erl
index dd509191ef..939abaff00 100644
--- a/lib/stdlib/src/erl_internal.erl
+++ b/lib/stdlib/src/erl_internal.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -74,6 +74,7 @@ guard_bif(element, 2) -> true;
guard_bif(float, 1) -> true;
guard_bif(floor, 1) -> true;
guard_bif(hd, 1) -> true;
+guard_bif(is_map_key, 2) -> true;
guard_bif(length, 1) -> true;
guard_bif(map_size, 1) -> true;
guard_bif(map_get, 2) -> true;
@@ -109,7 +110,6 @@ new_type_test(is_function, 2) -> true;
new_type_test(is_integer, 1) -> true;
new_type_test(is_list, 1) -> true;
new_type_test(is_map, 1) -> true;
-new_type_test(is_map_key, 2) -> true;
new_type_test(is_number, 1) -> true;
new_type_test(is_pid, 1) -> true;
new_type_test(is_port, 1) -> true;
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index 0c338b5952..9602f0bcd9 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -980,7 +980,7 @@ Erlang code.
-type af_unary_op(T) :: {'op', anno(), unary_op(), T}.
--type unary_op() :: '+' | '*' | 'bnot' | 'not'.
+-type unary_op() :: '+' | '-' | 'bnot' | 'not'.
%% See also lib/stdlib/{src/erl_bits.erl,include/erl_bits.hrl}.
-type type_specifier_list() :: 'default' | [type_specifier(), ...].
diff --git a/lib/stdlib/src/erl_posix_msg.erl b/lib/stdlib/src/erl_posix_msg.erl
index 8959fea498..b9ed4a3a9d 100644
--- a/lib/stdlib/src/erl_posix_msg.erl
+++ b/lib/stdlib/src/erl_posix_msg.erl
@@ -81,9 +81,9 @@ message_1(el2hlt) -> <<"level 2 halted">>;
message_1(el2nsync) -> <<"level 2 not synchronized">>;
message_1(el3hlt) -> <<"level 3 halted">>;
message_1(el3rst) -> <<"level 3 reset">>;
-message_1(elibacc) -> <<"can not access a needed shared library">>;
+message_1(elibacc) -> <<"cannot access a needed shared library">>;
message_1(elibbad) -> <<"accessing a corrupted shared library">>;
-message_1(elibexec) -> <<"can not exec a shared library directly">>;
+message_1(elibexec) -> <<"cannot exec a shared library directly">>;
message_1(elibmax) ->
<<"attempting to link in more shared libraries than system limit">>;
message_1(elibscn) -> <<".lib section in a.out corrupted">>;
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index 367dbefb82..dd302a2880 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -59,7 +59,7 @@
_ -> ?TEST(T)
end).
-define(EXPRS_TEST(L),
- [?TEST(E) || E <- L]).
+ _ = [?TEST(E) || E <- L]).
-define(TEST(T),
%% Assumes that erl_anno has been compiled with DEBUG=true.
%% erl_pp does not use the annoations, but test it anyway.
diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl
index beea9927d2..3f14894b55 100644
--- a/lib/stdlib/src/escript.erl
+++ b/lib/stdlib/src/escript.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -882,7 +882,7 @@ format_exception(Class, Reason, StackTrace) ->
io_lib:format("~." ++ integer_to_list(I) ++ P, [Term, 50])
end,
StackFun = fun(M, _F, _A) -> (M =:= erl_eval) or (M =:= ?MODULE) end,
- lib:format_exception(1, Class, Reason, StackTrace, StackFun, PF, Enc).
+ erl_error:format_exception(1, Class, Reason, StackTrace, StackFun, PF, Enc).
encoding() ->
[{encoding, Encoding}] = enc(),
diff --git a/lib/stdlib/src/ets.erl b/lib/stdlib/src/ets.erl
index 6a559f0be5..29f907ad73 100644
--- a/lib/stdlib/src/ets.erl
+++ b/lib/stdlib/src/ets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -77,7 +77,9 @@
whereis/1]).
%% internal exports
--export([internal_request_all/0]).
+-export([internal_request_all/0,
+ internal_delete_all/2,
+ internal_select_delete/2]).
-spec all() -> [Tab] when
Tab :: tab().
@@ -116,7 +118,15 @@ delete(_, _) ->
-spec delete_all_objects(Tab) -> true when
Tab :: tab().
-delete_all_objects(_) ->
+delete_all_objects(Tab) ->
+ _ = ets:internal_delete_all(Tab, undefined),
+ true.
+
+-spec internal_delete_all(Tab, undefined) -> NumDeleted when
+ Tab :: tab(),
+ NumDeleted :: non_neg_integer().
+
+internal_delete_all(_, _) ->
erlang:nif_error(undef).
-spec delete_object(Tab, Object) -> true when
@@ -378,7 +388,17 @@ select_count(_, _) ->
MatchSpec :: match_spec(),
NumDeleted :: non_neg_integer().
-select_delete(_, _) ->
+select_delete(Tab, [{'_',[],[true]}]) ->
+ ets:internal_delete_all(Tab, undefined);
+select_delete(Tab, MatchSpec) ->
+ ets:internal_select_delete(Tab, MatchSpec).
+
+-spec internal_select_delete(Tab, MatchSpec) -> NumDeleted when
+ Tab :: tab(),
+ MatchSpec :: match_spec(),
+ NumDeleted :: non_neg_integer().
+
+internal_select_delete(_, _) ->
erlang:nif_error(undef).
-spec select_replace(Tab, MatchSpec) -> NumReplaced when
diff --git a/lib/stdlib/src/file_sorter.erl b/lib/stdlib/src/file_sorter.erl
index 7f74e71136..191e050538 100644
--- a/lib/stdlib/src/file_sorter.erl
+++ b/lib/stdlib/src/file_sorter.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/src/gen.erl b/lib/stdlib/src/gen.erl
index 2e6223d2bb..a7f743bd4c 100644
--- a/lib/stdlib/src/gen.erl
+++ b/lib/stdlib/src/gen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/src/gen_event.erl b/lib/stdlib/src/gen_event.erl
index 3ee2031d02..8213282867 100644
--- a/lib/stdlib/src/gen_event.erl
+++ b/lib/stdlib/src/gen_event.erl
@@ -589,7 +589,7 @@ server_update(Handler1, Func, Event, SName) ->
?LOG_WARNING(#{label=>{gen_event,no_handle_info},
module=>Mod1,
message=>Event},
- #{domain=>[beam,erlang,otp],
+ #{domain=>[otp],
report_cb=>fun gen_event:format_log/1,
error_logger=>#{tag=>warning_msg}}), % warningmap??
{ok, Handler1};
@@ -751,7 +751,7 @@ report_error(Handler, Reason, State, LastIn, SName) ->
state=>format_status(terminate,Handler#handler.module,
get(),State),
reason=>Reason},
- #{domain=>[beam,erlang,otp],
+ #{domain=>[otp],
report_cb=>fun gen_event:format_log/1,
error_logger=>#{tag=>error}}).
diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl
index 77826c3dc6..caaaf8fa2e 100644
--- a/lib/stdlib/src/gen_fsm.erl
+++ b/lib/stdlib/src/gen_fsm.erl
@@ -129,25 +129,25 @@
%% logger callback
-export([format_log/1]).
--deprecated({start, 3, next_major_release}).
--deprecated({start, 4, next_major_release}).
--deprecated({start_link, 3, next_major_release}).
--deprecated({start_link, 4, next_major_release}).
--deprecated({stop, 1, next_major_release}).
--deprecated({stop, 3, next_major_release}).
--deprecated({send_event, 2, next_major_release}).
--deprecated({sync_send_event, 2, next_major_release}).
--deprecated({sync_send_event, 3, next_major_release}).
--deprecated({send_all_state_event, 2, next_major_release}).
--deprecated({sync_send_all_state_event, 2, next_major_release}).
--deprecated({sync_send_all_state_event, 3, next_major_release}).
--deprecated({reply, 2, next_major_release}).
--deprecated({start_timer, 2, next_major_release}).
--deprecated({send_event_after, 2, next_major_release}).
--deprecated({cancel_timer, 1, next_major_release}).
--deprecated({enter_loop, 4, next_major_release}).
--deprecated({enter_loop, 5, next_major_release}).
--deprecated({enter_loop, 6, next_major_release}).
+-deprecated({start, 3, eventually}).
+-deprecated({start, 4, eventually}).
+-deprecated({start_link, 3, eventually}).
+-deprecated({start_link, 4, eventually}).
+-deprecated({stop, 1, eventually}).
+-deprecated({stop, 3, eventually}).
+-deprecated({send_event, 2, eventually}).
+-deprecated({sync_send_event, 2, eventually}).
+-deprecated({sync_send_event, 3, eventually}).
+-deprecated({send_all_state_event, 2, eventually}).
+-deprecated({sync_send_all_state_event, 2, eventually}).
+-deprecated({sync_send_all_state_event, 3, eventually}).
+-deprecated({reply, 2, eventually}).
+-deprecated({start_timer, 2, eventually}).
+-deprecated({send_event_after, 2, eventually}).
+-deprecated({cancel_timer, 1, eventually}).
+-deprecated({enter_loop, 4, eventually}).
+-deprecated({enter_loop, 5, eventually}).
+-deprecated({enter_loop, 6, eventually}).
%%% ---------------------------------------------------
%%% Interface functions.
@@ -505,7 +505,7 @@ handle_msg(Msg, Parent, Name, StateName, StateData, Mod, _Time, HibernateAfterTi
?LOG_WARNING(#{label=>{gen_fsm,no_handle_info},
module=>Mod,
message=>Msg},
- #{domain=>[beam,erlang,otp],
+ #{domain=>[otp],
report_cb=>fun gen_fsm:format_log/1,
error_logger=>#{tag=>warning_msg}}),
loop(Parent, Name, StateName, StateData, Mod, infinity, HibernateAfterTimeout, []);
@@ -616,7 +616,7 @@ error_info(Reason, Name, Msg, StateName, StateData, Debug) ->
state_name=>StateName,
state_data=>StateData,
reason=>Reason},
- #{domain=>[beam,erlang,otp],
+ #{domain=>[otp],
report_cb=>fun gen_fsm:format_log/1,
error_logger=>#{tag=>error}}),
sys:print_log(Debug),
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index 035dd871ff..44e9231ebe 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -645,7 +645,7 @@ try_dispatch(Mod, Func, Msg, State) ->
#{label=>{gen_server,no_handle_info},
module=>Mod,
message=>Msg},
- #{domain=>[beam,erlang,otp],
+ #{domain=>[otp],
report_cb=>fun gen_server:format_log/1,
error_logger=>#{tag=>warning_msg}}),
{ok, {noreply, State}};
@@ -891,7 +891,7 @@ error_info(Reason, Name, From, Msg, Mod, State, Debug) ->
state=>format_status(terminate, Mod, get(), State),
reason=>Reason,
client_info=>client_stacktrace(From)},
- #{domain=>[beam,erlang,otp],
+ #{domain=>[otp],
report_cb=>fun gen_server:format_log/1,
error_logger=>#{tag=>error}}),
sys:print_log(Debug),
@@ -934,14 +934,14 @@ format_log(#{label:={gen_server,terminate},
end
end;
_ ->
- logger:limit_term(Reason)
+ error_logger:limit_term(Reason)
end,
{ClientFmt,ClientArgs} = format_client_log(Client),
{"** Generic server ~tp terminating \n"
"** Last message in was ~tp~n"
"** When Server state == ~tp~n"
"** Reason for termination == ~n** ~tp~n" ++ ClientFmt,
- [Name, Msg, logger:limit_term(State), Reason1] ++ ClientArgs};
+ [Name, Msg, error_logger:limit_term(State), Reason1] ++ ClientArgs};
format_log(#{label:={gen_server,no_handle_info},
module:=Mod,
message:=Msg}) ->
diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl
index f558f0d33e..faa43fbc1e 100644
--- a/lib/stdlib/src/gen_statem.erl
+++ b/lib/stdlib/src/gen_statem.erl
@@ -1448,13 +1448,13 @@ loop_event_done(
[?sys_debug(
Debug_0,
{S#state.name,State},
- {postpone,Event_0,State}),
+ {postpone,Event_0,NextState}),
Event_0|P_0];
false ->
[?sys_debug(
Debug_0,
{S#state.name,State},
- {consume,Event_0,State})|P_0]
+ {consume,Event_0,NextState})|P_0]
end,
{Events_2,P_2,Timers_2} =
%% Move all postponed events to queue,
@@ -1900,7 +1900,7 @@ error_info(
state_enter=>StateEnter,
state=>format_status(terminate, get(), S),
reason=>{Class,Reason,Stacktrace}},
- #{domain=>[beam,erlang,otp],
+ #{domain=>[otp],
report_cb=>fun gen_statem:format_log/1,
error_logger=>#{tag=>error}}).
@@ -1938,7 +1938,7 @@ format_log(#{label:={gen_statem,terminate},
_ -> {Reason,Stacktrace}
end,
[LimitedP, LimitedFmtData, LimitedFixedReason] =
- [logger:limit_term(D) || D <- [P, FmtData, FixedReason]],
+ [error_logger:limit_term(D) || D <- [P, FmtData, FixedReason]],
CBMode =
case StateEnter of
true ->
diff --git a/lib/stdlib/src/io.erl b/lib/stdlib/src/io.erl
index f510f61e9f..63c9a6bddf 100644
--- a/lib/stdlib/src/io.erl
+++ b/lib/stdlib/src/io.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2015. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -86,7 +86,16 @@ put_chars(Chars) ->
CharData :: unicode:chardata().
put_chars(Io, Chars) ->
- o_request(Io, {put_chars,unicode,Chars}, put_chars).
+ put_chars(Io, unicode, Chars).
+
+%% This function is here to make the erlang:raise in o_request actually raise to
+%% a valid function.
+-spec put_chars(IoDevice, Encoding, CharData) -> 'ok' when
+ IoDevice :: device(),
+ Encoding :: unicode,
+ CharData :: unicode:chardata().
+put_chars(Io, Encoding, Chars) ->
+ o_request(Io, {put_chars,Encoding,Chars}, put_chars).
-spec nl() -> 'ok'.
diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl
index 3a5aba60b4..8223a52873 100644
--- a/lib/stdlib/src/io_lib.erl
+++ b/lib/stdlib/src/io_lib.erl
@@ -178,11 +178,11 @@ fread(Cont, Chars, Format) ->
Data :: [term()].
format(Format, Args) ->
- case catch io_lib_format:fwrite(Format, Args) of
- {'EXIT',_} ->
- erlang:error(badarg, [Format, Args]);
- Other ->
- Other
+ try io_lib_format:fwrite(Format, Args)
+ catch
+ C:R:S ->
+ test_modules_loaded(C, R, S),
+ erlang:error(badarg, [Format, Args])
end.
-spec format(Format, Data, Options) -> chars() when
@@ -193,11 +193,11 @@ format(Format, Args) ->
CharsLimit :: chars_limit().
format(Format, Args, Options) ->
- case catch io_lib_format:fwrite(Format, Args, Options) of
- {'EXIT',_} ->
- erlang:error(badarg, [Format, Args, Options]);
- Other ->
- Other
+ try io_lib_format:fwrite(Format, Args, Options)
+ catch
+ C:R:S ->
+ test_modules_loaded(C, R, S),
+ erlang:error(badarg, [Format, Args])
end.
-spec scan_format(Format, Data) -> FormatList when
@@ -208,7 +208,9 @@ format(Format, Args, Options) ->
scan_format(Format, Args) ->
try io_lib_format:scan(Format, Args)
catch
- _:_ -> erlang:error(badarg, [Format, Args])
+ C:R:S ->
+ test_modules_loaded(C, R, S),
+ erlang:error(badarg, [Format, Args])
end.
-spec unscan_format(FormatList) -> {Format, Data} when
@@ -223,7 +225,12 @@ unscan_format(FormatList) ->
FormatList :: [char() | format_spec()].
build_text(FormatList) ->
- io_lib_format:build(FormatList).
+ try io_lib_format:build(FormatList)
+ catch
+ C:R:S ->
+ test_modules_loaded(C, R, S),
+ erlang:error(badarg, [FormatList])
+ end.
-spec build_text(FormatList, Options) -> chars() when
FormatList :: [char() | format_spec()],
@@ -232,7 +239,23 @@ build_text(FormatList) ->
CharsLimit :: chars_limit().
build_text(FormatList, Options) ->
- io_lib_format:build(FormatList, Options).
+ try io_lib_format:build(FormatList, Options)
+ catch
+ C:R:S ->
+ test_modules_loaded(C, R, S),
+ erlang:error(badarg, [FormatList, Options])
+ end.
+
+%% Failure to load a module must not be labeled as badarg.
+%% C, R, and S are included so that the original error, which could be
+%% a bug in io_lib_format, can be found by tracing on
+%% test_modules_loaded/3.
+test_modules_loaded(_C, _R, _S) ->
+ Modules = [io_lib_format, io_lib_pretty, string, unicode],
+ case code:ensure_modules_loaded(Modules) of
+ ok -> ok;
+ Error -> erlang:error(Error)
+ end.
-spec print(Term) -> chars() when
Term :: term().
diff --git a/lib/stdlib/src/io_lib_format.erl b/lib/stdlib/src/io_lib_format.erl
index c814ab50d4..e247b00a04 100644
--- a/lib/stdlib/src/io_lib_format.erl
+++ b/lib/stdlib/src/io_lib_format.erl
@@ -38,18 +38,16 @@
%% and it also splits the handling of the control characters into two
%% parts.
--spec fwrite(Format, Data) -> FormatList when
+-spec fwrite(Format, Data) -> io_lib:chars() when
Format :: io:format(),
- Data :: [term()],
- FormatList :: [char() | io_lib:format_spec()].
+ Data :: [term()].
fwrite(Format, Args) ->
build(scan(Format, Args)).
--spec fwrite(Format, Data, Options) -> FormatList when
+-spec fwrite(Format, Data, Options) -> io_lib:chars() when
Format :: io:format(),
Data :: [term()],
- FormatList :: [char() | io_lib:format_spec()],
Options :: [Option],
Option :: {'chars_limit', CharsLimit},
CharsLimit :: io_lib:chars_limit().
diff --git a/lib/stdlib/src/io_lib_pretty.erl b/lib/stdlib/src/io_lib_pretty.erl
index 3d5a979b3e..ba9d9e8434 100644
--- a/lib/stdlib/src/io_lib_pretty.erl
+++ b/lib/stdlib/src/io_lib_pretty.erl
@@ -131,6 +131,8 @@ print(Term, Col, Ll, D, M0, T, RecDefFun, Enc, Str) when is_tuple(Term);
%% use Len as CHAR_MAX if M0 = -1
M = max_cs(M0, Len),
if
+ Ll =:= 0 ->
+ write(If);
Len < Ll - Col, Len =< M ->
%% write the whole thing on a single line when there is room
write(If);
@@ -720,7 +722,7 @@ printable_list(L, _D, T, latin1) when T < 0 ->
io_lib:printable_latin1_list(L);
printable_list(L, _D, T, Enc) when T >= 0 ->
case slice(L, tsub(T, 2)) of
- {prefix, ""} ->
+ false ->
false;
{prefix, Prefix} when Enc =:= latin1 ->
io_lib:printable_latin1_list(Prefix) andalso {true, Prefix};
@@ -736,11 +738,17 @@ printable_list(L, _D, T, _Uni) when T < 0->
io_lib:printable_list(L).
slice(L, N) ->
- case string:length(L) =< N of
+ try string:length(L) =< N of
true ->
all;
false ->
- {prefix, string:slice(L, 0, N)}
+ case string:slice(L, 0, N) of
+ "" ->
+ false;
+ Prefix ->
+ {prefix, Prefix}
+ end
+ catch _:_ -> false
end.
printable_bin0(Bin, D, T, Enc) ->
diff --git a/lib/stdlib/src/maps.erl b/lib/stdlib/src/maps.erl
index a13f340709..51965ddb57 100644
--- a/lib/stdlib/src/maps.erl
+++ b/lib/stdlib/src/maps.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,7 +21,7 @@
-module(maps).
-export([get/3, filter/2,fold/3,
- map/2, size/1,
+ map/2, size/1, new/0,
update_with/3, update_with/4,
without/2, with/2,
iterator/1, next/1]).
@@ -29,13 +29,15 @@
%% BIFs
-export([get/2, find/2, from_list/1,
is_key/2, keys/1, merge/2,
- new/0, put/3, remove/2, take/2,
+ put/3, remove/2, take/2,
to_list/1, update/3, values/1]).
--opaque iterator() :: {term(), term(), iterator()}
- | none | nonempty_improper_list(integer(),map()).
+-opaque iterator(Key, Value) :: {Key, Value, iterator(Key, Value)} | none
+ | nonempty_improper_list(integer(), #{Key => Value}).
--export_type([iterator/0]).
+-type iterator() :: iterator(term(), term()).
+
+-export_type([iterator/2, iterator/0]).
-dialyzer({no_improper_lists, iterator/1}).
@@ -50,9 +52,7 @@
get(_,_) -> erlang:nif_error(undef).
-spec find(Key,Map) -> {ok, Value} | error when
- Key :: term(),
- Map :: map(),
- Value :: term().
+ Map :: #{Key => Value, _ => _}.
find(_,_) -> erlang:nif_error(undef).
@@ -75,9 +75,8 @@ is_key(_,_) -> erlang:nif_error(undef).
-spec keys(Map) -> Keys when
- Map :: map(),
- Keys :: [Key],
- Key :: term().
+ Map :: #{Key => _},
+ Keys :: [Key].
keys(_) -> erlang:nif_error(undef).
@@ -91,13 +90,6 @@ keys(_) -> erlang:nif_error(undef).
merge(_,_) -> erlang:nif_error(undef).
-
--spec new() -> Map when
- Map :: map().
-
-new() -> erlang:nif_error(undef).
-
-
%% Shadowed by erl_bif_types: maps:put/3
-spec put(Key,Value,Map1) -> Map2 when
Key :: term(),
@@ -116,17 +108,13 @@ put(_,_,_) -> erlang:nif_error(undef).
remove(_,_) -> erlang:nif_error(undef).
-spec take(Key,Map1) -> {Value,Map2} | error when
- Key :: term(),
- Map1 :: map(),
- Value :: term(),
- Map2 :: map().
+ Map1 :: #{Key => Value, _ => _},
+ Map2 :: #{_ => _}.
take(_,_) -> erlang:nif_error(undef).
-spec to_list(Map) -> [{Key,Value}] when
- Map :: map(),
- Key :: term(),
- Value :: term().
+ Map :: #{Key => Value}.
to_list(Map) when is_map(Map) ->
to_list_internal(erts_internal:map_next(0, Map, []));
@@ -140,79 +128,69 @@ to_list_internal(Acc) ->
%% Shadowed by erl_bif_types: maps:update/3
-spec update(Key,Value,Map1) -> Map2 when
- Key :: term(),
- Value :: term(),
- Map1 :: map(),
- Map2 :: map().
+ Map1 :: #{Key := _, _ => _},
+ Map2 :: #{Key := Value, _ => _}.
update(_,_,_) -> erlang:nif_error(undef).
-spec values(Map) -> Values when
- Map :: map(),
- Values :: [Value],
- Value :: term().
+ Map :: #{_ => Value},
+ Values :: [Value].
values(_) -> erlang:nif_error(undef).
%% End of BIFs
+-spec new() -> Map when
+ Map :: #{}.
+
+new() -> #{}.
+
-spec update_with(Key,Fun,Map1) -> Map2 when
- Key :: term(),
- Map1 :: map(),
- Map2 :: map(),
- Fun :: fun((Value1 :: term()) -> Value2 :: term()).
+ Map1 :: #{Key := Value1, _ => _},
+ Map2 :: #{Key := Value2, _ => _},
+ Fun :: fun((Value1) -> Value2).
update_with(Key,Fun,Map) when is_function(Fun,1), is_map(Map) ->
- try maps:get(Key,Map) of
- Val -> maps:update(Key,Fun(Val),Map)
- catch
- error:{badkey,_} ->
- erlang:error({badkey,Key},[Key,Fun,Map])
+ case Map of
+ #{Key := Value} -> Map#{Key := Fun(Value)};
+ #{} -> erlang:error({badkey,Key},[Key,Fun,Map])
end;
update_with(Key,Fun,Map) ->
erlang:error(error_type(Map),[Key,Fun,Map]).
-spec update_with(Key,Fun,Init,Map1) -> Map2 when
- Key :: term(),
- Map1 :: Map1,
- Map2 :: Map2,
- Fun :: fun((Value1 :: term()) -> Value2 :: term()),
- Init :: term().
+ Map1 :: #{Key => Value1, _ => _},
+ Map2 :: #{Key := Value2 | Init, _ => _},
+ Fun :: fun((Value1) -> Value2).
update_with(Key,Fun,Init,Map) when is_function(Fun,1), is_map(Map) ->
- case maps:find(Key,Map) of
- {ok,Val} -> maps:update(Key,Fun(Val),Map);
- error -> maps:put(Key,Init,Map)
+ case Map of
+ #{Key := Value} -> Map#{Key := Fun(Value)};
+ #{} -> Map#{Key => Init}
end;
update_with(Key,Fun,Init,Map) ->
erlang:error(error_type(Map),[Key,Fun,Init,Map]).
-spec get(Key, Map, Default) -> Value | Default when
- Key :: term(),
- Map :: map(),
- Value :: term(),
- Default :: term().
+ Map :: #{Key => Value, _ => _}.
get(Key,Map,Default) when is_map(Map) ->
- case maps:find(Key, Map) of
- {ok, Value} ->
- Value;
- error ->
- Default
+ case Map of
+ #{Key := Value} -> Value;
+ #{} -> Default
end;
get(Key,Map,Default) ->
erlang:error({badmap,Map},[Key,Map,Default]).
--spec filter(Pred,MapOrIter) -> Map when
+-spec filter(Pred, MapOrIter) -> Map when
Pred :: fun((Key, Value) -> boolean()),
- Key :: term(),
- Value :: term(),
- MapOrIter :: map() | iterator(),
- Map :: map().
+ MapOrIter :: #{Key => Value} | iterator(Key, Value),
+ Map :: #{Key => Value}.
filter(Pred,Map) when is_function(Pred,2), is_map(Map) ->
maps:from_list(filter_1(Pred, iterator(Map)));
@@ -235,21 +213,18 @@ filter_1(Pred, Iter) ->
end.
-spec fold(Fun,Init,MapOrIter) -> Acc when
- Fun :: fun((K, V, AccIn) -> AccOut),
+ Fun :: fun((Key, Value, AccIn) -> AccOut),
Init :: term(),
- Acc :: term(),
- AccIn :: term(),
- AccOut :: term(),
- MapOrIter :: map() | iterator(),
- K :: term(),
- V :: term().
+ Acc :: AccOut,
+ AccIn :: Init | AccOut,
+ MapOrIter :: #{Key => Value} | iterator(Key, Value).
fold(Fun,Init,Map) when is_function(Fun,3), is_map(Map) ->
fold_1(Fun,Init,iterator(Map));
fold(Fun,Init,Iterator) when is_function(Fun,3), ?IS_ITERATOR(Iterator) ->
fold_1(Fun,Init,Iterator);
fold(Fun,Init,Map) ->
- erlang:error(error_type(Map),[Fun,Init,Map]).
+ erlang:error(error_type_iter(Map),[Fun,Init,Map]).
fold_1(Fun, Acc, Iter) ->
case next(Iter) of
@@ -260,19 +235,16 @@ fold_1(Fun, Acc, Iter) ->
end.
-spec map(Fun,MapOrIter) -> Map when
- Fun :: fun((K, V1) -> V2),
- MapOrIter :: map() | iterator(),
- Map :: map(),
- K :: term(),
- V1 :: term(),
- V2 :: term().
+ Fun :: fun((Key, Value1) -> Value2),
+ MapOrIter :: #{Key => Value1} | iterator(Key, Value1),
+ Map :: #{Key => Value2}.
map(Fun,Map) when is_function(Fun, 2), is_map(Map) ->
maps:from_list(map_1(Fun, iterator(Map)));
map(Fun,Iterator) when is_function(Fun, 2), ?IS_ITERATOR(Iterator) ->
maps:from_list(map_1(Fun, Iterator));
map(Fun,Map) ->
- erlang:error(error_type(Map),[Fun,Map]).
+ erlang:error(error_type_iter(Map),[Fun,Map]).
map_1(Fun, Iter) ->
case next(Iter) of
@@ -291,17 +263,15 @@ size(Val) ->
erlang:error({badmap,Val},[Val]).
-spec iterator(Map) -> Iterator when
- Map :: map(),
- Iterator :: iterator().
+ Map :: #{Key => Value},
+ Iterator :: iterator(Key, Value).
iterator(M) when is_map(M) -> [0 | M];
iterator(M) -> erlang:error({badmap, M}, [M]).
-spec next(Iterator) -> {Key, Value, NextIterator} | 'none' when
- Iterator :: iterator(),
- Key :: term(),
- Value :: term(),
- NextIterator :: iterator().
+ Iterator :: iterator(Key, Value),
+ NextIterator :: iterator(Key, Value).
next({K, V, I}) ->
{K, V, I};
next([Path | Map]) when is_integer(Path), is_map(Map) ->
@@ -318,29 +288,29 @@ next(Iter) ->
K :: term().
without(Ks,M) when is_list(Ks), is_map(M) ->
- lists:foldl(fun(K, M1) -> maps:remove(K, M1) end, M, Ks);
+ lists:foldl(fun maps:remove/2, M, Ks);
without(Ks,M) ->
erlang:error(error_type(M),[Ks,M]).
-spec with(Ks, Map1) -> Map2 when
Ks :: [K],
- Map1 :: map(),
- Map2 :: map(),
- K :: term().
+ Map1 :: #{K => V, _ => _},
+ Map2 :: #{K => V}.
with(Ks,Map1) when is_list(Ks), is_map(Map1) ->
- Fun = fun(K, List) ->
- case maps:find(K, Map1) of
- {ok, V} ->
- [{K, V} | List];
- error ->
- List
- end
- end,
- maps:from_list(lists:foldl(Fun, [], Ks));
+ maps:from_list(with_1(Ks, Map1));
with(Ks,M) ->
erlang:error(error_type(M),[Ks,M]).
+with_1([K|Ks], Map) ->
+ case Map of
+ #{K := V} -> [{K,V}|with_1(Ks, Map)];
+ #{} -> with_1(Ks, Map)
+ end;
+with_1([], _Map) -> [].
-error_type(M) when is_map(M); ?IS_ITERATOR(M) -> badarg;
+error_type(M) when is_map(M) -> badarg;
error_type(V) -> {badmap, V}.
+
+error_type_iter(M) when is_map(M); ?IS_ITERATOR(M) -> badarg;
+error_type_iter(V) -> {badmap, V}.
diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl
index 428c23524b..d117481d2e 100644
--- a/lib/stdlib/src/ms_transform.erl
+++ b/lib/stdlib/src/ms_transform.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/src/ordsets.erl b/lib/stdlib/src/ordsets.erl
index 939e147ad8..176047079b 100644
--- a/lib/stdlib/src/ordsets.erl
+++ b/lib/stdlib/src/ordsets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index a17addcc42..aaed13ba3a 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -612,6 +612,17 @@ obsolete_1(erlang, get_stacktrace, 0) ->
obsolete_1(erlang, hash, 2) ->
{removed, {erlang, phash2, 2}, "20.0"};
+%% Add in OTP 21.
+
+obsolete_1(ssl, ssl_accept, 1) ->
+ {deprecated, "deprecated; use ssl:handshake/1 instead"};
+obsolete_1(ssl, ssl_accept, 2) ->
+ {deprecated, "deprecated; use ssl:handshake/2 instead"};
+obsolete_1(ssl, ssl_accept, 3) ->
+ {deprecated, "deprecated; use ssl:handshake/3 instead"};
+obsolete_1(otp_mib, F, _) when F =:= load; F =:= unload ->
+ {deprecated, "deprecated; functionality will be removed in a future release"};
+
%% not obsolete
obsolete_1(_, _, _) ->
diff --git a/lib/stdlib/src/pool.erl b/lib/stdlib/src/pool.erl
index b12ff205b1..599be55607 100644
--- a/lib/stdlib/src/pool.erl
+++ b/lib/stdlib/src/pool.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/src/proc_lib.erl b/lib/stdlib/src/proc_lib.erl
index 8d01840313..d07c62500b 100644
--- a/lib/stdlib/src/proc_lib.erl
+++ b/lib/stdlib/src/proc_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@
start/3, start/4, start/5, start_link/3, start_link/4, start_link/5,
hibernate/3,
init_ack/1, init_ack/2,
- init_p/3,init_p/5,format/1,format/2,format/3,report_cb/1,
+ init_p/3,init_p/5,format/1,format/2,format/3,report_cb/2,
initial_call/1,
translate_initial_call/1,
stop/1, stop/3]).
@@ -508,8 +508,8 @@ crash_report(Class, Reason, StartF, Stacktrace) ->
?LOG_ERROR(#{label=>{proc_lib,crash},
report=>[my_info(Class, Reason, StartF, Stacktrace),
linked_info(self())]},
- #{domain=>[beam,erlang,otp,sasl],
- report_cb=>fun proc_lib:report_cb/1,
+ #{domain=>[otp,sasl],
+ report_cb=>fun proc_lib:report_cb/2,
logger_formatter=>#{title=>"CRASH REPORT"},
error_logger=>#{tag=>error_report,type=>crash_report}}).
@@ -553,10 +553,10 @@ get_ancestors(Pid) ->
%% assumed that all report handlers call proc_lib:format().
get_messages(Pid) ->
Messages = get_process_messages(Pid),
- {messages, logger:limit_term(Messages)}.
+ {messages, error_logger:limit_term(Messages)}.
get_process_messages(Pid) ->
- Depth = logger:get_format_depth(),
+ Depth = error_logger:get_format_depth(),
case Pid =/= self() orelse Depth =:= unlimited of
true ->
{messages, Messages} = get_process_info(Pid, messages),
@@ -586,7 +586,7 @@ get_cleaned_dictionary(Pid) ->
cleaned_dict(Dict) ->
CleanDict = clean_dict(Dict),
- logger:limit_term(CleanDict).
+ error_logger:limit_term(CleanDict).
clean_dict([{'$ancestors',_}|Dict]) ->
clean_dict(Dict);
@@ -750,14 +750,15 @@ check(Res) -> Res.
%%% Format a generated crash info structure.
%%% -----------------------------------------------------------
--spec report_cb(CrashReport) -> {Format,Args} when
- CrashReport :: #{label=>{proc_lib,crash},report=>[term()]},
- Format :: io:format(),
- Args :: [term()].
-report_cb(#{label:={proc_lib,crash},
- report:=CrashReport}) ->
- Depth = logger:get_format_depth(),
- get_format_and_args(CrashReport, utf8, Depth).
+-spec report_cb(CrashReport,FormatOpts) -> unicode:chardata() when
+ CrashReport :: #{label => {proc_lib,crash},
+ report => [term()]},
+ FormatOpts :: logger:report_cb_config().
+report_cb(#{label:={proc_lib,crash}, report:=CrashReport}, Extra) ->
+ Default = #{chars_limit => unlimited,
+ depth => unlimited,
+ encoding => latin1},
+ do_format(CrashReport, maps:merge(Default,Extra)).
-spec format(CrashReport) -> string() when
CrashReport :: [term()].
@@ -777,84 +778,85 @@ format(CrashReport, Encoding) ->
Depth :: unlimited | pos_integer().
format(CrashReport, Encoding, Depth) ->
- {F,A} = get_format_and_args(CrashReport, Encoding, Depth),
- lists:flatten(io_lib:format(F,A)).
+ do_format(CrashReport, #{chars_limit => unlimited,
+ depth => Depth,
+ encoding => Encoding}).
-get_format_and_args([OwnReport,LinkReport], Encoding, Depth) ->
- Extra = {Encoding,Depth},
+do_format([OwnReport,LinkReport], Extra) ->
MyIndent = " ",
- {OwnFormat,OwnArgs} = format_report(OwnReport, MyIndent, Extra, [], []),
- {LinkFormat,LinkArgs} = format_link_report(LinkReport, MyIndent, Extra, [], []),
- {" crasher:~n"++OwnFormat++" neighbours:~n"++LinkFormat,OwnArgs++LinkArgs}.
+ OwnFormat = format_report(OwnReport, MyIndent, Extra),
+ LinkFormat = format_link_report(LinkReport, MyIndent, Extra),
+ Str = io_lib:format(" crasher:~n~ts neighbours:~n~ts",
+ [OwnFormat, LinkFormat]),
+ lists:flatten(Str).
-format_link_report([], _Indent, _Extra, Format, Args) ->
- {lists:flatten(lists:reverse(Format)),lists:append(lists:reverse(Args))};
-format_link_report([Link|Reps], Indent, Extra, Format, Args) ->
+format_link_report([Link|Reps], Indent, Extra) ->
Rep = case Link of
{neighbour,Rep0} -> Rep0;
_ -> Link
end,
LinkIndent = [" ",Indent],
- {LinkFormat,LinkArgs} = format_report(Rep, LinkIndent, Extra, [], []),
- F = "~sneighbour:\n"++LinkFormat,
- A = [Indent|LinkArgs],
- format_link_report(Reps, Indent, Extra, [F|Format], [A|Args]);
-format_link_report(Rep, Indent, Extra, Format, Args) ->
- {F,A} = format_report(Rep, Indent, Extra, [], []),
- format_link_report([], Indent, Extra, [F|Format],[A|Args]).
-
-format_report([], _Indent, _Extra, Format, Args) ->
- {lists:flatten(lists:reverse(Format)),lists:append(lists:reverse(Args))};
-format_report([Rep|Reps], Indent, Extra, Format, Args) ->
- {F,A} = format_rep(Rep, Indent, Extra),
- format_report(Reps, Indent, Extra, [F|Format], [A|Args]);
-format_report(Rep, Indent, {Enc,unlimited}=Extra, Format, Args) ->
- {F,A} = {"~s~"++modifier(Enc)++"p~n", [Indent, Rep]},
- format_report([], Indent, Extra, [F|Format], [A|Args]);
-format_report(Rep, Indent, {Enc,Depth}=Extra, Format, Args) ->
- {F,A} = {"~s~"++modifier(Enc)++"P~n", [Indent, Rep, Depth]},
- format_report([], Indent, Extra, [F|Format], [A|Args]).
-
-format_rep({initial_call,InitialCall}, Indent, Extra) ->
- format_mfa(Indent, InitialCall, Extra);
-format_rep({error_info,{Class,Reason,StackTrace}}, _Indent, Extra) ->
- {lists:flatten(format_exception(Class, Reason, StackTrace, Extra)),[]};
-format_rep({Tag,Data}, Indent, Extra) ->
- format_tag(Indent, Tag, Data, Extra).
-
-format_mfa(Indent, {M,F,Args}=StartF, {Enc,_}=Extra) ->
+ [Indent,"neighbour:\n",format_report(Rep, LinkIndent, Extra)|
+ format_link_report(Reps, Indent, Extra)];
+format_link_report(Rep, Indent, Extra) ->
+ format_report(Rep, Indent, Extra).
+
+format_report(Rep, Indent, Extra) when is_list(Rep) ->
+ format_rep(Rep, Indent, Extra);
+format_report(Rep, Indent, #{encoding:=Enc,depth:=unlimited}) ->
+ io_lib:format("~s~"++modifier(Enc)++"p~n", [Indent, Rep]);
+format_report(Rep, Indent, #{encoding:=Enc,depth:=Depth}) ->
+ io_lib:format("~s~"++modifier(Enc)++"P~n", [Indent, Rep, Depth]).
+
+format_rep([{initial_call,InitialCall}|Rep], Indent, Extra) ->
+ [format_mfa(Indent, InitialCall, Extra)|format_rep(Rep, Indent, Extra)];
+format_rep([{error_info,{Class,Reason,StackTrace}}|Rep], Indent, Extra) ->
+ [format_exception(Class, Reason, StackTrace, Extra)|
+ format_rep(Rep, Indent, Extra)];
+format_rep([{Tag,Data}|Rep], Indent, Extra) ->
+ [format_tag(Indent, Tag, Data, Extra)|format_rep(Rep, Indent, Extra)];
+format_rep(_, _, _Extra) ->
+ [].
+
+format_exception(Class, Reason, StackTrace, #{encoding:=Enc}=Extra) ->
+ PF = pp_fun(Extra),
+ StackFun = fun(M, _F, _A) -> (M =:= erl_eval) or (M =:= ?MODULE) end,
+ %% EI = " exception: ",
+ EI = " ",
+ [EI, erl_error:format_exception(1+length(EI), Class, Reason,
+ StackTrace, StackFun, PF, Enc), "\n"].
+
+format_mfa(Indent, {M,F,Args}=StartF, #{encoding:=Enc}=Extra) ->
try
A = length(Args),
- {lists:flatten([Indent,"initial call: ",atom_to_list(M),
- $:,to_string(F, Enc),$/,integer_to_list(A),"\n"]),[]}
+ [Indent,"initial call: ",atom_to_list(M),$:,to_string(F, Enc),$/,
+ integer_to_list(A),"\n"]
catch
error:_ ->
format_tag(Indent, initial_call, StartF, Extra)
end.
-format_tag(Indent, Tag, Data, {Enc,Depth}) ->
- {P,Tl} = p(Enc, Depth),
- {"~s~p: ~80.18" ++ P ++ "\n", [Indent, Tag, Data|Tl]}.
-
-format_exception(Class, Reason, StackTrace, {Enc,_}=Extra) ->
- PF = pp_fun(Extra),
- StackFun = fun(M, _F, _A) -> (M =:= erl_eval) or (M =:= ?MODULE) end,
- %% EI = " exception: ",
- EI = " ",
- [EI, lib:format_exception(1+length(EI), Class, Reason,
- StackTrace, StackFun, PF, Enc), "\n"].
-
to_string(A, latin1) ->
io_lib:write_atom_as_latin1(A);
to_string(A, _) ->
io_lib:write_atom(A).
-pp_fun({Enc,Depth}) ->
+pp_fun(#{encoding:=Enc,depth:=Depth,chars_limit:=Limit}) ->
{P,Tl} = p(Enc, Depth),
+ Opts = if is_integer(Limit) -> [{chars_limit,Limit}];
+ true -> []
+ end,
fun(Term, I) ->
- io_lib:format("~." ++ integer_to_list(I) ++ P, [Term|Tl])
+ io_lib:format("~." ++ integer_to_list(I) ++ P, [Term|Tl], Opts)
end.
+format_tag(Indent, Tag, Data, #{encoding:=Enc,depth:=Depth,chars_limit:=Limit}) ->
+ {P,Tl} = p(Enc, Depth),
+ Opts = if is_integer(Limit) -> [{chars_limit,Limit}];
+ true -> []
+ end,
+ io_lib:format("~s~p: ~80.18" ++ P ++ "\n", [Indent, Tag, Data|Tl], Opts).
+
p(Encoding, Depth) ->
{Letter, Tl} = case Depth of
unlimited -> {"p", []};
diff --git a/lib/stdlib/src/qlc.erl b/lib/stdlib/src/qlc.erl
index 3a66f6930b..a1c1117e31 100644
--- a/lib/stdlib/src/qlc.erl
+++ b/lib/stdlib/src/qlc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -638,7 +638,7 @@ string_to_handle(Str, Options, Bindings) when is_list(Str) ->
case erl_scan:string(Str, 1, [text]) of
{ok, Tokens, _} ->
ScanRes =
- case lib:extended_parse_exprs(Tokens) of
+ case erl_eval:extended_parse_exprs(Tokens) of
{ok, [Expr0], SBs} ->
{ok, Expr0, SBs};
{ok, _ExprList, _SBs} ->
@@ -1196,8 +1196,8 @@ abstract1({table, TableDesc}, _NElements, _Depth, _A) ->
{ok, Tokens, _} =
erl_scan:string(lists:flatten(TableDesc++"."), 1, [text]),
{ok, Es, Bs} =
- lib:extended_parse_exprs(Tokens),
- [Expr] = lib:subst_values_for_vars(Es, Bs),
+ erl_eval:extended_parse_exprs(Tokens),
+ [Expr] = erl_eval:subst_values_for_vars(Es, Bs),
special(Expr);
false -> % abstract expression
TableDesc
@@ -3749,7 +3749,7 @@ maybe_error_logger(Name, Why) ->
expand_stacktrace(),
Trimmer = fun(M, _F, _A) -> M =:= erl_eval end,
Formater = fun(Term, I) -> io_lib:print(Term, I, 80, -1) end,
- X = lib:format_stacktrace(1, Stacktrace, Trimmer, Formater),
+ X = erl_error:format_stacktrace(1, Stacktrace, Trimmer, Formater),
error_logger:Name("qlc: temporary file was needed for ~w\n~ts\n",
[Why, lists:flatten(X)]).
diff --git a/lib/stdlib/src/rand.erl b/lib/stdlib/src/rand.erl
index 362e98006e..4951dc727b 100644
--- a/lib/stdlib/src/rand.erl
+++ b/lib/stdlib/src/rand.erl
@@ -486,7 +486,7 @@ uniform_real_s(Alg, Next, M0, BitNo, R1, V1, Bits) ->
{M1 * math:pow(2.0, BitNo - 56), {Alg, R1}};
BitNo =:= -1008 ->
%% Endgame
- %% For the last round we can not have 14 zeros or more
+ %% For the last round we cannot have 14 zeros or more
%% at the top of M1 because then we will underflow,
%% so we need at least 43 bits
if
diff --git a/lib/stdlib/src/sets.erl b/lib/stdlib/src/sets.erl
index ac0fc80526..8adb9016e2 100644
--- a/lib/stdlib/src/sets.erl
+++ b/lib/stdlib/src/sets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl
index 1be37672e7..c73cf22943 100644
--- a/lib/stdlib/src/shell.erl
+++ b/lib/stdlib/src/shell.erl
@@ -230,7 +230,7 @@ server_loop(N0, Eval_0, Bs00, RT, Ds00, History0, Results0) ->
{Res,Eval0} = get_command(Prompt, Eval_1, Bs0, RT, Ds0),
case Res of
{ok,Es0,XBs} ->
- Es1 = lib:subst_values_for_vars(Es0, XBs),
+ Es1 = erl_eval:subst_values_for_vars(Es0, XBs),
case expand_hist(Es1, N) of
{ok,Es} ->
{V,Eval,Bs,Ds} = shell_cmd(Es, Eval0, Bs0, RT, Ds0, cmd),
@@ -280,7 +280,7 @@ get_command(Prompt, Eval, Bs, RT, Ds) ->
io:scan_erl_exprs(group_leader(), Prompt, 1, [text])
of
{ok,Toks,_EndPos} ->
- lib:extended_parse_exprs(Toks);
+ erl_eval:extended_parse_exprs(Toks);
{eof,_EndPos} ->
eof;
{error,ErrorInfo,_EndPos} ->
@@ -589,7 +589,7 @@ report_exception(Class, Severity, {Reason,Stacktrace}, RT) ->
PF = fun(Term, I1) -> pp(Term, I1, RT) end,
SF = fun(M, _F, _A) -> (M =:= erl_eval) or (M =:= ?MODULE) end,
Enc = encoding(),
- Str = lib:format_exception(I, Class, Reason, Stacktrace, SF, PF, Enc),
+ Str = erl_error:format_exception(I, Class, Reason, Stacktrace, SF, PF, Enc),
io:requests([{put_chars, latin1, Tag},
{put_chars, unicode, Str},
nl]).
diff --git a/lib/stdlib/src/slave.erl b/lib/stdlib/src/slave.erl
index b3f3206d67..5e8c1a43ea 100644
--- a/lib/stdlib/src/slave.erl
+++ b/lib/stdlib/src/slave.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -187,7 +187,7 @@ start_link(Host, Name, Args) ->
start(Host, Name, Args, self()).
start(Host0, Name, Args, LinkTo) ->
- Prog = lib:progname(),
+ Prog = progname(),
start(Host0, Name, Args, LinkTo, Prog).
start(Host0, Name, Args, LinkTo, Prog) ->
@@ -296,7 +296,6 @@ mk_cmd(Host, Name, Args, Waiter, Prog0) ->
" -s slave slave_start ", node(),
" ", Waiter,
" ", Args]),
-
case after_char($@, atom_to_list(node())) of
Host ->
{ok, BasicCmd};
@@ -309,6 +308,15 @@ mk_cmd(Host, Name, Args, Waiter, Prog0) ->
end
end.
+%% Return the name of the script that starts (this) erlang
+progname() ->
+ case init:get_argument(progname) of
+ {ok, [[Prog]]} ->
+ Prog;
+ _Other ->
+ "no_prog_name"
+ end.
+
%% This is an attempt to distinguish between spaces in the program
%% path and spaces that separate arguments. The program is quoted to
%% allow spaces in the path.
@@ -317,7 +325,7 @@ mk_cmd(Host, Name, Args, Waiter, Prog0) ->
%% (through start/5) or if the -program switch to beam is used and
%% includes arguments (typically done by cerl in OTP test environment
%% in order to ensure that slave/peer nodes are started with the same
-%% emulator and flags as the test node. The return from lib:progname()
+%% emulator and flags as the test node. The result from progname()
%% could then typically be '/<full_path_to>/cerl -gcov').
quote_progname(Progname) ->
do_quote_progname(string:lexemes(to_list(Progname)," ")).
diff --git a/lib/stdlib/src/stdlib.app.src b/lib/stdlib/src/stdlib.app.src
index 5fb48acfab..cd09872b87 100644
--- a/lib/stdlib/src/stdlib.app.src
+++ b/lib/stdlib/src/stdlib.app.src
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -43,6 +43,7 @@
erl_anno,
erl_bits,
erl_compile,
+ erl_error,
erl_eval,
erl_expand_records,
erl_internal,
@@ -71,7 +72,6 @@
io_lib_format,
io_lib_fread,
io_lib_pretty,
- lib,
lists,
log_mf_h,
maps,
diff --git a/lib/stdlib/src/string.erl b/lib/stdlib/src/string.erl
index 0736374f21..2939e78d9d 100644
--- a/lib/stdlib/src/string.erl
+++ b/lib/stdlib/src/string.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -323,16 +323,30 @@ take(Str, Sep0, true, trailing) ->
%% Uppercase all chars in Str
-spec uppercase(String::unicode:chardata()) -> unicode:chardata().
uppercase(CD) when is_list(CD) ->
- uppercase_list(CD);
-uppercase(CD) when is_binary(CD) ->
- uppercase_bin(CD,<<>>).
+ try uppercase_list(CD, false)
+ catch unchanged -> CD
+ end;
+uppercase(<<CP1/utf8, Rest/binary>>=Orig) ->
+ try uppercase_bin(CP1, Rest, false) of
+ List -> unicode:characters_to_binary(List)
+ catch unchanged -> Orig
+ end;
+uppercase(<<>>) ->
+ <<>>.
%% Lowercase all chars in Str
-spec lowercase(String::unicode:chardata()) -> unicode:chardata().
lowercase(CD) when is_list(CD) ->
- lowercase_list(CD);
-lowercase(CD) when is_binary(CD) ->
- lowercase_bin(CD,<<>>).
+ try lowercase_list(CD, false)
+ catch unchanged -> CD
+ end;
+lowercase(<<CP1/utf8, Rest/binary>>=Orig) ->
+ try lowercase_bin(CP1, Rest, false) of
+ List -> unicode:characters_to_binary(List)
+ catch unchanged -> Orig
+ end;
+lowercase(<<>>) ->
+ <<>>.
%% Make a titlecase of the first char in Str
-spec titlecase(String::unicode:chardata()) -> unicode:chardata().
@@ -352,9 +366,16 @@ titlecase(CD) when is_binary(CD) ->
%% Make a comparable string of the Str should be used for equality tests only
-spec casefold(String::unicode:chardata()) -> unicode:chardata().
casefold(CD) when is_list(CD) ->
- casefold_list(CD);
-casefold(CD) when is_binary(CD) ->
- casefold_bin(CD,<<>>).
+ try casefold_list(CD, false)
+ catch unchanged -> CD
+ end;
+casefold(<<CP1/utf8, Rest/binary>>=Orig) ->
+ try casefold_bin(CP1, Rest, false) of
+ List -> unicode:characters_to_binary(List)
+ catch unchanged -> Orig
+ end;
+casefold(<<>>) ->
+ <<>>.
-spec to_integer(String) -> {Int, Rest} | {'error', Reason} when
String :: unicode:chardata(),
@@ -652,52 +673,127 @@ slice_bin(CD, CP1, N) when N > 0 ->
slice_bin(CD, CP1, 0) ->
byte_size(CD)+byte_size(<<CP1/utf8>>).
-uppercase_list(CPs0) ->
+uppercase_list([CP1|[CP2|_]=Cont], _Changed) when $a =< CP1, CP1 =< $z, CP2 < 256 ->
+ [CP1-32|uppercase_list(Cont, true)];
+uppercase_list([CP1|[CP2|_]=Cont], Changed) when CP1 < 128, CP2 < 256 ->
+ [CP1|uppercase_list(Cont, Changed)];
+uppercase_list([], true) ->
+ [];
+uppercase_list([], false) ->
+ throw(unchanged);
+uppercase_list(CPs0, Changed) ->
case unicode_util:uppercase(CPs0) of
- [Char|CPs] -> append(Char,uppercase_list(CPs));
- [] -> []
+ [Char|CPs] when Char =:= hd(CPs0) -> [Char|uppercase_list(CPs, Changed)];
+ [Char|CPs] -> append(Char,uppercase_list(CPs, true));
+ [] -> uppercase_list([], Changed)
end.
-uppercase_bin(CPs0, Acc) ->
- case unicode_util:uppercase(CPs0) of
- [Char|CPs] when is_integer(Char) ->
- uppercase_bin(CPs, <<Acc/binary, Char/utf8>>);
- [Chars|CPs] ->
- uppercase_bin(CPs, <<Acc/binary,
- << <<CP/utf8>> || CP <- Chars>>/binary >>);
- [] -> Acc
+uppercase_bin(CP1, <<CP2/utf8, Bin/binary>>, _Changed)
+ when $a =< CP1, CP1 =< $z, CP2 < 256 ->
+ [CP1-32|uppercase_bin(CP2, Bin, true)];
+uppercase_bin(CP1, <<CP2/utf8, Bin/binary>>, Changed)
+ when CP1 < 128, CP2 < 256 ->
+ [CP1|uppercase_bin(CP2, Bin, Changed)];
+uppercase_bin(CP1, Bin, Changed) ->
+ case unicode_util:uppercase([CP1|Bin]) of
+ [CP1|CPs] ->
+ case unicode_util:cp(CPs) of
+ [Next|Rest] ->
+ [CP1|uppercase_bin(Next, Rest, Changed)];
+ [] when Changed ->
+ [CP1];
+ [] ->
+ throw(unchanged)
+ end;
+ [Char|CPs] ->
+ case unicode_util:cp(CPs) of
+ [Next|Rest] ->
+ [Char|uppercase_bin(Next, Rest, true)];
+ [] ->
+ [Char]
+ end
end.
-lowercase_list(CPs0) ->
+lowercase_list([CP1|[CP2|_]=Cont], _Changed) when $A =< CP1, CP1 =< $Z, CP2 < 256 ->
+ [CP1+32|lowercase_list(Cont, true)];
+lowercase_list([CP1|[CP2|_]=Cont], Changed) when CP1 < 128, CP2 < 256 ->
+ [CP1|lowercase_list(Cont, Changed)];
+lowercase_list([], true) ->
+ [];
+lowercase_list([], false) ->
+ throw(unchanged);
+lowercase_list(CPs0, Changed) ->
case unicode_util:lowercase(CPs0) of
- [Char|CPs] -> append(Char,lowercase_list(CPs));
- [] -> []
+ [Char|CPs] when Char =:= hd(CPs0) -> [Char|lowercase_list(CPs, Changed)];
+ [Char|CPs] -> append(Char,lowercase_list(CPs, true));
+ [] -> lowercase_list([], Changed)
end.
-lowercase_bin(CPs0, Acc) ->
- case unicode_util:lowercase(CPs0) of
- [Char|CPs] when is_integer(Char) ->
- lowercase_bin(CPs, <<Acc/binary, Char/utf8>>);
- [Chars|CPs] ->
- lowercase_bin(CPs, <<Acc/binary,
- << <<CP/utf8>> || CP <- Chars>>/binary >>);
- [] -> Acc
+lowercase_bin(CP1, <<CP2/utf8, Bin/binary>>, _Changed)
+ when $A =< CP1, CP1 =< $Z, CP2 < 256 ->
+ [CP1+32|lowercase_bin(CP2, Bin, true)];
+lowercase_bin(CP1, <<CP2/utf8, Bin/binary>>, Changed)
+ when CP1 < 128, CP2 < 256 ->
+ [CP1|lowercase_bin(CP2, Bin, Changed)];
+lowercase_bin(CP1, Bin, Changed) ->
+ case unicode_util:lowercase([CP1|Bin]) of
+ [CP1|CPs] ->
+ case unicode_util:cp(CPs) of
+ [Next|Rest] ->
+ [CP1|lowercase_bin(Next, Rest, Changed)];
+ [] when Changed ->
+ [CP1];
+ [] ->
+ throw(unchanged)
+ end;
+ [Char|CPs] ->
+ case unicode_util:cp(CPs) of
+ [Next|Rest] ->
+ [Char|lowercase_bin(Next, Rest, true)];
+ [] ->
+ [Char]
+ end
end.
-casefold_list(CPs0) ->
+casefold_list([CP1|[CP2|_]=Cont], _Changed) when $A =< CP1, CP1 =< $Z, CP2 < 256 ->
+ [CP1+32|casefold_list(Cont, true)];
+casefold_list([CP1|[CP2|_]=Cont], Changed) when CP1 < 128, CP2 < 256 ->
+ [CP1|casefold_list(Cont, Changed)];
+casefold_list([], true) ->
+ [];
+casefold_list([], false) ->
+ throw(unchanged);
+casefold_list(CPs0, Changed) ->
case unicode_util:casefold(CPs0) of
- [Char|CPs] -> append(Char, casefold_list(CPs));
- [] -> []
+ [Char|CPs] when Char =:= hd(CPs0) -> [Char|casefold_list(CPs, Changed)];
+ [Char|CPs] -> append(Char,casefold_list(CPs, true));
+ [] -> casefold_list([], Changed)
end.
-casefold_bin(CPs0, Acc) ->
- case unicode_util:casefold(CPs0) of
- [Char|CPs] when is_integer(Char) ->
- casefold_bin(CPs, <<Acc/binary, Char/utf8>>);
- [Chars|CPs] ->
- casefold_bin(CPs, <<Acc/binary,
- << <<CP/utf8>> || CP <- Chars>>/binary >>);
- [] -> Acc
+casefold_bin(CP1, <<CP2/utf8, Bin/binary>>, _Changed)
+ when $A =< CP1, CP1 =< $Z, CP2 < 256 ->
+ [CP1+32|casefold_bin(CP2, Bin, true)];
+casefold_bin(CP1, <<CP2/utf8, Bin/binary>>, Changed)
+ when CP1 < 128, CP2 < 256 ->
+ [CP1|casefold_bin(CP2, Bin, Changed)];
+casefold_bin(CP1, Bin, Changed) ->
+ case unicode_util:casefold([CP1|Bin]) of
+ [CP1|CPs] ->
+ case unicode_util:cp(CPs) of
+ [Next|Rest] ->
+ [CP1|casefold_bin(Next, Rest, Changed)];
+ [] when Changed ->
+ [CP1];
+ [] ->
+ throw(unchanged)
+ end;
+ [Char|CPs] ->
+ case unicode_util:cp(CPs) of
+ [Next|Rest] ->
+ [Char|casefold_bin(Next, Rest, true)];
+ [] ->
+ [Char]
+ end
end.
%% Fast path for ascii searching for one character in lists
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index eb46ac611a..1ac7334830 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -43,7 +43,7 @@
{errorContext,Error},
{reason,Reason},
{offender,extract_child(Child)}]},
- #{domain=>[beam,erlang,otp,sasl],
+ #{domain=>[otp,sasl],
report_cb=>fun logger:format_otp_report/1,
logger_formatter=>#{title=>"SUPERVISOR REPORT"},
error_logger=>#{tag=>error_report,
@@ -580,7 +580,7 @@ handle_info({'EXIT', Pid, Reason}, State) ->
handle_info(Msg, State) ->
?LOG_ERROR("Supervisor received unexpected message: ~tp~n",[Msg],
- #{domain=>[beam,erlang,otp],
+ #{domain=>[otp],
error_logger=>#{tag=>error}}),
{noreply, State}.
@@ -1419,7 +1419,7 @@ report_progress(Child, SupName) ->
?LOG_INFO(#{label=>{supervisor,progress},
report=>[{supervisor,SupName},
{started,extract_child(Child)}]},
- #{domain=>[beam,erlang,otp,sasl],
+ #{domain=>[otp,sasl],
report_cb=>fun logger:format_otp_report/1,
logger_formatter=>#{title=>"PROGRESS REPORT"},
error_logger=>#{tag=>info_report,type=>progress}}).
diff --git a/lib/stdlib/src/supervisor_bridge.erl b/lib/stdlib/src/supervisor_bridge.erl
index 39372935fa..21ba6f53af 100644
--- a/lib/stdlib/src/supervisor_bridge.erl
+++ b/lib/stdlib/src/supervisor_bridge.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -135,7 +135,7 @@ report_progress(Pid, Mod, StartArgs, SupName) ->
report=>[{supervisor, SupName},
{started, [{pid, Pid},
{mfa, {Mod, init, [StartArgs]}}]}]},
- #{domain=>[beam,erlang,otp,sasl],
+ #{domain=>[otp,sasl],
report_cb=>fun logger:format_otp_report/1,
logger_formatter=>#{title=>"PROGRESS REPORT"},
error_logger=>#{tag=>info_report,type=>progress}}).
@@ -146,7 +146,7 @@ report_error(Error, Reason, #state{name = Name, pid = Pid, mod = Mod}) ->
{errorContext, Error},
{reason, Reason},
{offender, [{pid, Pid}, {mod, Mod}]}]},
- #{domain=>[beam,erlang,otp,sasl],
+ #{domain=>[otp,sasl],
report_cb=>fun logger:format_otp_report/1,
logger_formatter=>#{title=>"SUPERVISOR REPORT"},
error_logger=>#{tag=>error_report,type=>supervisor_report}}).
diff --git a/lib/stdlib/src/uri_string.erl b/lib/stdlib/src/uri_string.erl
index 28d36ea229..d33dc89af8 100644
--- a/lib/stdlib/src/uri_string.erl
+++ b/lib/stdlib/src/uri_string.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -297,7 +297,10 @@
NormalizedURI :: uri_string()
| error().
normalize(URIMap) ->
- normalize(URIMap, []).
+ try normalize(URIMap, [])
+ catch
+ throw:{error, Atom, RestData} -> {error, Atom, RestData}
+ end.
-spec normalize(URI, Options) -> NormalizedURI when
@@ -412,7 +415,7 @@ transcode(URIString, Options) when is_list(URIString) ->
%% (application/x-www-form-urlencoded encoding algorithm)
%%-------------------------------------------------------------------------
-spec compose_query(QueryList) -> QueryString when
- QueryList :: [{unicode:chardata(), unicode:chardata()}],
+ QueryList :: [{unicode:chardata(), unicode:chardata() | true}],
QueryString :: uri_string()
| error().
compose_query(List) ->
@@ -420,7 +423,7 @@ compose_query(List) ->
-spec compose_query(QueryList, Options) -> QueryString when
- QueryList :: [{unicode:chardata(), unicode:chardata()}],
+ QueryList :: [{unicode:chardata(), unicode:chardata() | true}],
Options :: [{encoding, atom()}],
QueryString :: uri_string()
| error().
@@ -432,6 +435,11 @@ compose_query(List, Options) ->
throw:{error, Atom, RestData} -> {error, Atom, RestData}
end.
%%
+compose_query([{Key,true}|Rest], Options, IsList, Acc) ->
+ Separator = get_separator(Rest),
+ K = form_urlencode(Key, Options),
+ IsListNew = IsList orelse is_list(Key),
+ compose_query(Rest, Options, IsListNew, <<Acc/binary,K/binary,Separator/binary>>);
compose_query([{Key,Value}|Rest], Options, IsList, Acc) ->
Separator = get_separator(Rest),
K = form_urlencode(Key, Options),
@@ -451,7 +459,7 @@ compose_query([], _Options, IsList, Acc) ->
%%-------------------------------------------------------------------------
-spec dissect_query(QueryString) -> QueryList when
QueryString :: uri_string(),
- QueryList :: [{unicode:chardata(), unicode:chardata()}]
+ QueryList :: [{unicode:chardata(), unicode:chardata() | true}]
| error().
dissect_query(<<>>) ->
[];
@@ -523,34 +531,34 @@ parse_relative_part(?STRING_REST("//", Rest), URI) ->
{T, URI1} ->
Userinfo = calculate_parsed_userinfo(Rest, T),
URI2 = maybe_add_path(URI1),
- URI2#{userinfo => decode_userinfo(Userinfo)}
+ URI2#{userinfo => Userinfo}
catch
throw:{_,_,_} ->
{T, URI1} = parse_host(Rest, URI),
Host = calculate_parsed_host_port(Rest, T),
URI2 = maybe_add_path(URI1),
- URI2#{host => decode_host(remove_brackets(Host))}
+ URI2#{host => remove_brackets(Host)}
end;
parse_relative_part(?STRING_REST($/, Rest), URI) ->
{T, URI1} = parse_segment(Rest, URI), % path-absolute
Path = calculate_parsed_part(Rest, T),
- URI1#{path => decode_path(?STRING_REST($/, Path))};
+ URI1#{path => ?STRING_REST($/, Path)};
parse_relative_part(?STRING_REST($?, Rest), URI) ->
{T, URI1} = parse_query(Rest, URI), % path-empty ?query
Query = calculate_parsed_query_fragment(Rest, T),
URI2 = maybe_add_path(URI1),
- URI2#{query => decode_query(Query)};
+ URI2#{query => Query};
parse_relative_part(?STRING_REST($#, Rest), URI) ->
{T, URI1} = parse_fragment(Rest, URI), % path-empty
Fragment = calculate_parsed_query_fragment(Rest, T),
URI2 = maybe_add_path(URI1),
- URI2#{fragment => decode_fragment(Fragment)};
+ URI2#{fragment => Fragment};
parse_relative_part(?STRING_REST(Char, Rest), URI) ->
case is_segment_nz_nc(Char) of
true ->
{T, URI1} = parse_segment_nz_nc(Rest, URI), % path-noscheme
Path = calculate_parsed_part(Rest, T),
- URI1#{path => decode_path(?STRING_REST(Char, Path))};
+ URI1#{path => ?STRING_REST(Char, Path)};
false -> throw({error,invalid_uri,[Char]})
end.
@@ -593,11 +601,11 @@ parse_segment(?STRING_REST($/, Rest), URI) ->
parse_segment(?STRING_REST($?, Rest), URI) ->
{T, URI1} = parse_query(Rest, URI), % ?query
Query = calculate_parsed_query_fragment(Rest, T),
- {Rest, URI1#{query => decode_query(Query)}};
+ {Rest, URI1#{query => Query}};
parse_segment(?STRING_REST($#, Rest), URI) ->
{T, URI1} = parse_fragment(Rest, URI),
Fragment = calculate_parsed_query_fragment(Rest, T),
- {Rest, URI1#{fragment => decode_fragment(Fragment)}};
+ {Rest, URI1#{fragment => Fragment}};
parse_segment(?STRING_REST(Char, Rest), URI) ->
case is_pchar(Char) of
true -> parse_segment(Rest, URI);
@@ -616,11 +624,11 @@ parse_segment_nz_nc(?STRING_REST($/, Rest), URI) ->
parse_segment_nz_nc(?STRING_REST($?, Rest), URI) ->
{T, URI1} = parse_query(Rest, URI), % ?query
Query = calculate_parsed_query_fragment(Rest, T),
- {Rest, URI1#{query => decode_query(Query)}};
+ {Rest, URI1#{query => Query}};
parse_segment_nz_nc(?STRING_REST($#, Rest), URI) ->
{T, URI1} = parse_fragment(Rest, URI),
Fragment = calculate_parsed_query_fragment(Rest, T),
- {Rest, URI1#{fragment => decode_fragment(Fragment)}};
+ {Rest, URI1#{fragment => Fragment}};
parse_segment_nz_nc(?STRING_REST(Char, Rest), URI) ->
case is_segment_nz_nc(Char) of
true -> parse_segment_nz_nc(Rest, URI);
@@ -709,31 +717,31 @@ parse_hier(?STRING_REST("//", Rest), URI) ->
try parse_userinfo(Rest, URI) of
{T, URI1} ->
Userinfo = calculate_parsed_userinfo(Rest, T),
- {Rest, URI1#{userinfo => decode_userinfo(Userinfo)}}
+ {Rest, URI1#{userinfo => Userinfo}}
catch
throw:{_,_,_} ->
{T, URI1} = parse_host(Rest, URI),
Host = calculate_parsed_host_port(Rest, T),
- {Rest, URI1#{host => decode_host(remove_brackets(Host))}}
+ {Rest, URI1#{host => remove_brackets(Host)}}
end;
parse_hier(?STRING_REST($/, Rest), URI) ->
{T, URI1} = parse_segment(Rest, URI), % path-absolute
Path = calculate_parsed_part(Rest, T),
- {Rest, URI1#{path => decode_path(?STRING_REST($/, Path))}};
+ {Rest, URI1#{path => ?STRING_REST($/, Path)}};
parse_hier(?STRING_REST($?, Rest), URI) ->
{T, URI1} = parse_query(Rest, URI), % path-empty ?query
Query = calculate_parsed_query_fragment(Rest, T),
- {Rest, URI1#{query => decode_query(Query)}};
+ {Rest, URI1#{query => Query}};
parse_hier(?STRING_REST($#, Rest), URI) ->
{T, URI1} = parse_fragment(Rest, URI), % path-empty
Fragment = calculate_parsed_query_fragment(Rest, T),
- {Rest, URI1#{fragment => decode_fragment(Fragment)}};
+ {Rest, URI1#{fragment => Fragment}};
parse_hier(?STRING_REST(Char, Rest), URI) -> % path-rootless
case is_pchar(Char) of
true -> % segment_nz
{T, URI1} = parse_segment(Rest, URI),
Path = calculate_parsed_part(Rest, T),
- {Rest, URI1#{path => decode_path(?STRING_REST(Char, Path))}};
+ {Rest, URI1#{path => ?STRING_REST(Char, Path)}};
false -> throw({error,invalid_uri,[Char]})
end;
parse_hier(?STRING_EMPTY, URI) ->
@@ -770,7 +778,7 @@ parse_userinfo(?CHAR($@), URI) ->
parse_userinfo(?STRING_REST($@, Rest), URI) ->
{T, URI1} = parse_host(Rest, URI),
Host = calculate_parsed_host_port(Rest, T),
- {Rest, URI1#{host => decode_host(remove_brackets(Host))}};
+ {Rest, URI1#{host => remove_brackets(Host)}};
parse_userinfo(?STRING_REST(Char, Rest), URI) ->
case is_userinfo(Char) of
true -> parse_userinfo(Rest, URI);
@@ -836,20 +844,25 @@ parse_host(?STRING_REST($:, Rest), URI) ->
parse_host(?STRING_REST($/, Rest), URI) ->
{T, URI1} = parse_segment(Rest, URI), % path-abempty
Path = calculate_parsed_part(Rest, T),
- {Rest, URI1#{path => decode_path(?STRING_REST($/, Path))}};
+ {Rest, URI1#{path => ?STRING_REST($/, Path)}};
parse_host(?STRING_REST($?, Rest), URI) ->
{T, URI1} = parse_query(Rest, URI), % path-empty ?query
Query = calculate_parsed_query_fragment(Rest, T),
- {Rest, URI1#{query => decode_query(Query)}};
+ {Rest, URI1#{query => Query}};
parse_host(?STRING_REST($[, Rest), URI) ->
parse_ipv6_bin(Rest, [], URI);
parse_host(?STRING_REST($#, Rest), URI) ->
{T, URI1} = parse_fragment(Rest, URI), % path-empty
Fragment = calculate_parsed_query_fragment(Rest, T),
- {Rest, URI1#{fragment => decode_fragment(Fragment)}};
+ {Rest, URI1#{fragment => Fragment}};
parse_host(?STRING_REST(Char, Rest), URI) ->
case is_digit(Char) of
- true -> parse_ipv4_bin(Rest, [Char], URI);
+ true ->
+ try parse_ipv4_bin(Rest, [Char], URI)
+ catch
+ throw:{_,_,_} ->
+ parse_reg_name(?STRING_REST(Char, Rest), URI)
+ end;
false -> parse_reg_name(?STRING_REST(Char, Rest), URI)
end;
parse_host(?STRING_EMPTY, URI) ->
@@ -865,15 +878,15 @@ parse_reg_name(?STRING_REST($:, Rest), URI) ->
parse_reg_name(?STRING_REST($/, Rest), URI) ->
{T, URI1} = parse_segment(Rest, URI), % path-abempty
Path = calculate_parsed_part(Rest, T),
- {Rest, URI1#{path => decode_path(?STRING_REST($/, Path))}};
+ {Rest, URI1#{path => ?STRING_REST($/, Path)}};
parse_reg_name(?STRING_REST($?, Rest), URI) ->
{T, URI1} = parse_query(Rest, URI), % path-empty ?query
Query = calculate_parsed_query_fragment(Rest, T),
- {Rest, URI1#{query => decode_query(Query)}};
+ {Rest, URI1#{query => Query}};
parse_reg_name(?STRING_REST($#, Rest), URI) ->
{T, URI1} = parse_fragment(Rest, URI), % path-empty
Fragment = calculate_parsed_query_fragment(Rest, T),
- {Rest, URI1#{fragment => decode_fragment(Fragment)}};
+ {Rest, URI1#{fragment => Fragment}};
parse_reg_name(?STRING_REST(Char, Rest), URI) ->
case is_reg_name(Char) of
true -> parse_reg_name(Rest, URI);
@@ -899,17 +912,17 @@ parse_ipv4_bin(?STRING_REST($/, Rest), Acc, URI) ->
_ = validate_ipv4_address(lists:reverse(Acc)),
{T, URI1} = parse_segment(Rest, URI), % path-abempty
Path = calculate_parsed_part(Rest, T),
- {Rest, URI1#{path => decode_path(?STRING_REST($/, Path))}};
+ {Rest, URI1#{path => ?STRING_REST($/, Path)}};
parse_ipv4_bin(?STRING_REST($?, Rest), Acc, URI) ->
_ = validate_ipv4_address(lists:reverse(Acc)),
{T, URI1} = parse_query(Rest, URI), % path-empty ?query
Query = calculate_parsed_query_fragment(Rest, T),
- {Rest, URI1#{query => decode_query(Query)}};
+ {Rest, URI1#{query => Query}};
parse_ipv4_bin(?STRING_REST($#, Rest), Acc, URI) ->
_ = validate_ipv4_address(lists:reverse(Acc)),
{T, URI1} = parse_fragment(Rest, URI), % path-empty
Fragment = calculate_parsed_query_fragment(Rest, T),
- {Rest, URI1#{fragment => decode_fragment(Fragment)}};
+ {Rest, URI1#{fragment => Fragment}};
parse_ipv4_bin(?STRING_REST(Char, Rest), Acc, URI) ->
case is_ipv4(Char) of
true -> parse_ipv4_bin(Rest, [Char|Acc], URI);
@@ -961,15 +974,15 @@ parse_ipv6_bin_end(?STRING_REST($:, Rest), URI) ->
parse_ipv6_bin_end(?STRING_REST($/, Rest), URI) ->
{T, URI1} = parse_segment(Rest, URI), % path-abempty
Path = calculate_parsed_part(Rest, T),
- {Rest, URI1#{path => decode_path(?STRING_REST($/, Path))}};
+ {Rest, URI1#{path => ?STRING_REST($/, Path)}};
parse_ipv6_bin_end(?STRING_REST($?, Rest), URI) ->
{T, URI1} = parse_query(Rest, URI), % path-empty ?query
Query = calculate_parsed_query_fragment(Rest, T),
- {Rest, URI1#{query => decode_query(Query)}};
+ {Rest, URI1#{query => Query}};
parse_ipv6_bin_end(?STRING_REST($#, Rest), URI) ->
{T, URI1} = parse_fragment(Rest, URI), % path-empty
Fragment = calculate_parsed_query_fragment(Rest, T),
- {Rest, URI1#{fragment => decode_fragment(Fragment)}};
+ {Rest, URI1#{fragment => Fragment}};
parse_ipv6_bin_end(?STRING_REST(Char, Rest), URI) ->
case is_ipv6(Char) of
true -> parse_ipv6_bin_end(Rest, URI);
@@ -999,15 +1012,15 @@ validate_ipv6_address(Addr) ->
parse_port(?STRING_REST($/, Rest), URI) ->
{T, URI1} = parse_segment(Rest, URI), % path-abempty
Path = calculate_parsed_part(Rest, T),
- {Rest, URI1#{path => decode_path(?STRING_REST($/, Path))}};
+ {Rest, URI1#{path => ?STRING_REST($/, Path)}};
parse_port(?STRING_REST($?, Rest), URI) ->
{T, URI1} = parse_query(Rest, URI), % path-empty ?query
Query = calculate_parsed_query_fragment(Rest, T),
- {Rest, URI1#{query => decode_query(Query)}};
+ {Rest, URI1#{query => Query}};
parse_port(?STRING_REST($#, Rest), URI) ->
{T, URI1} = parse_fragment(Rest, URI), % path-empty
Fragment = calculate_parsed_query_fragment(Rest, T),
- {Rest, URI1#{fragment => decode_fragment(Fragment)}};
+ {Rest, URI1#{fragment => Fragment}};
parse_port(?STRING_REST(Char, Rest), URI) ->
case is_digit(Char) of
true -> parse_port(Rest, URI);
@@ -1033,7 +1046,7 @@ parse_port(?STRING_EMPTY, URI) ->
parse_query(?STRING_REST($#, Rest), URI) ->
{T, URI1} = parse_fragment(Rest, URI),
Fragment = calculate_parsed_query_fragment(Rest, T),
- {Rest, URI1#{fragment => decode_fragment(Fragment)}};
+ {Rest, URI1#{fragment => Fragment}};
parse_query(?STRING_REST(Char, Rest), URI) ->
case is_query(Char) of
true -> parse_query(Rest, URI);
@@ -1088,6 +1101,31 @@ is_fragment(Char) -> is_pchar(Char).
%%
%%-------------------------------------------------------------------------
+%% Return true if input char is reserved.
+-spec is_reserved(char()) -> boolean().
+is_reserved($:) -> true;
+is_reserved($/) -> true;
+is_reserved($?) -> true;
+is_reserved($#) -> true;
+is_reserved($[) -> true;
+is_reserved($]) -> true;
+is_reserved($@) -> true;
+
+is_reserved($!) -> true;
+is_reserved($$) -> true;
+is_reserved($&) -> true;
+is_reserved($') -> true;
+is_reserved($() -> true;
+is_reserved($)) -> true;
+
+is_reserved($*) -> true;
+is_reserved($+) -> true;
+is_reserved($,) -> true;
+is_reserved($;) -> true;
+is_reserved($=) -> true;
+is_reserved(_) -> false.
+
+
%% Check if char is sub-delim.
-spec is_sub_delim(char()) -> boolean().
is_sub_delim($!) -> true;
@@ -1276,36 +1314,6 @@ byte_size_exl_head(Binary) -> byte_size(Binary) + 1.
%%
%% pct-encoded = "%" HEXDIG HEXDIG
%%-------------------------------------------------------------------------
--spec decode_userinfo(binary()) -> binary().
-decode_userinfo(Cs) ->
- check_utf8(decode(Cs, fun is_userinfo/1, <<>>)).
-
--spec decode_host(binary()) -> binary().
-decode_host(Cs) ->
- check_utf8(decode(Cs, fun is_host/1, <<>>)).
-
--spec decode_path(binary()) -> binary().
-decode_path(Cs) ->
- check_utf8(decode(Cs, fun is_path/1, <<>>)).
-
--spec decode_query(binary()) -> binary().
-decode_query(Cs) ->
- check_utf8(decode(Cs, fun is_query/1, <<>>)).
-
--spec decode_fragment(binary()) -> binary().
-decode_fragment(Cs) ->
- check_utf8(decode(Cs, fun is_fragment/1, <<>>)).
-
-
-%% Returns Cs if it is utf8 encoded.
-check_utf8(Cs) ->
- case unicode:characters_to_list(Cs) of
- {incomplete,_,_} ->
- throw({error,invalid_utf8,Cs});
- {error,_,_} ->
- throw({error,invalid_utf8,Cs});
- _ -> Cs
- end.
%%-------------------------------------------------------------------------
%% Percent-encode
@@ -1351,20 +1359,56 @@ encode_fragment(Cs) ->
%%-------------------------------------------------------------------------
%% Helper funtions for percent-decode
%%-------------------------------------------------------------------------
-decode(<<$%,C0,C1,Cs/binary>>, Fun, Acc) ->
+
+-spec decode(list()|binary()) -> list() | binary().
+decode(Cs) ->
+ decode(Cs, <<>>).
+%%
+decode(L, Acc) when is_list(L) ->
+ B0 = unicode:characters_to_binary(L),
+ B1 = decode(B0, Acc),
+ unicode:characters_to_list(B1);
+decode(<<$%,C0,C1,Cs/binary>>, Acc) ->
case is_hex_digit(C0) andalso is_hex_digit(C1) of
true ->
B = ?HEX2DEC(C0)*16+?HEX2DEC(C1),
- decode(Cs, Fun, <<Acc/binary, B>>);
+ case is_reserved(B) of
+ true ->
+ %% [2.2] Characters in the reserved set are protected from
+ %% normalization.
+ %% [2.1] For consistency, URI producers and normalizers should
+ %% use uppercase hexadecimal digits for all percent-
+ %% encodings.
+ H0 = hex_to_upper(C0),
+ H1 = hex_to_upper(C1),
+ decode(Cs, <<Acc/binary,$%,H0,H1>>);
+ false ->
+ decode(Cs, <<Acc/binary, B>>)
+ end;
false -> throw({error,invalid_percent_encoding,<<$%,C0,C1>>})
end;
-decode(<<C,Cs/binary>>, Fun, Acc) ->
- case Fun(C) of
- true -> decode(Cs, Fun, <<Acc/binary, C>>);
- false -> throw({error,invalid_percent_encoding,<<C,Cs/binary>>})
- end;
-decode(<<>>, _Fun, Acc) ->
- Acc.
+decode(<<C,Cs/binary>>, Acc) ->
+ decode(Cs, <<Acc/binary, C>>);
+decode(<<>>, Acc) ->
+ check_utf8(Acc).
+
+%% Returns Cs if it is utf8 encoded.
+check_utf8(Cs) ->
+ case unicode:characters_to_list(Cs) of
+ {incomplete,_,_} ->
+ throw({error,invalid_utf8,Cs});
+ {error,_,_} ->
+ throw({error,invalid_utf8,Cs});
+ _ -> Cs
+ end.
+
+%% Convert hex digit to uppercase form
+hex_to_upper(H) when $a =< H, H =< $f ->
+ H - 32;
+hex_to_upper(H) when $0 =< H, H =< $9;$A =< H, H =< $F->
+ H;
+hex_to_upper(H) ->
+ throw({error,invalid_input, H}).
%% Check if char is allowed in host
-spec is_host(char()) -> boolean().
@@ -1850,13 +1894,12 @@ dissect_query_key(<<$=,T/binary>>, IsList, Acc, Key, Value) ->
dissect_query_value(T, IsList, Acc, Key, Value);
dissect_query_key(<<"&#",T/binary>>, IsList, Acc, Key, Value) ->
dissect_query_key(T, IsList, Acc, <<Key/binary,"&#">>, Value);
-dissect_query_key(<<$&,_T/binary>>, _IsList, _Acc, _Key, _Value) ->
- throw({error, missing_value, "&"});
+dissect_query_key(T = <<$&,_/binary>>, IsList, Acc, Key, <<>>) ->
+ dissect_query_value(T, IsList, Acc, Key, true);
dissect_query_key(<<H,T/binary>>, IsList, Acc, Key, Value) ->
dissect_query_key(T, IsList, Acc, <<Key/binary,H>>, Value);
-dissect_query_key(B, _, _, _, _) ->
- throw({error, missing_value, B}).
-
+dissect_query_key(T = <<>>, IsList, Acc, Key, <<>>) ->
+ dissect_query_value(T, IsList, Acc, Key, true).
dissect_query_value(<<$&,T/binary>>, IsList, Acc, Key, Value) ->
K = form_urldecode(IsList, Key),
@@ -1869,9 +1912,10 @@ dissect_query_value(<<>>, IsList, Acc, Key, Value) ->
V = form_urldecode(IsList, Value),
lists:reverse([{K,V}|Acc]).
-
%% HTML 5.2 - 4.10.21.6 URL-encoded form data - WHATWG URL (10 Jan 2018) - UTF-8
%% HTML 5.0 - 4.10.22.6 URL-encoded form data - decoding (non UTF-8)
+form_urldecode(_, true) ->
+ true;
form_urldecode(true, B) ->
Result = base10_decode(form_urldecode(B, <<>>)),
convert_to_list(Result, utf8);
@@ -1925,9 +1969,10 @@ base10_decode_unicode(<<H,_/binary>>, _, _) ->
%%-------------------------------------------------------------------------
normalize_map(URIMap) ->
- normalize_path_segment(
- normalize_scheme_based(
- normalize_case(URIMap))).
+ normalize_path_segment(
+ normalize_scheme_based(
+ normalize_percent_encoding(
+ normalize_case(URIMap)))).
%% 6.2.2.1. Case Normalization
@@ -1942,6 +1987,18 @@ normalize_case(#{} = Map) ->
Map.
+%% 6.2.2.2. Percent-Encoding Normalization
+normalize_percent_encoding(Map) ->
+ Fun = fun (K,V) when K =:= userinfo; K =:= host; K =:= path;
+ K =:= query; K =:= fragment ->
+ decode(V);
+ %% Handle port and scheme
+ (_,V) ->
+ V
+ end,
+ maps:map(Fun, Map).
+
+
to_lower(Cs) when is_list(Cs) ->
B = convert_to_binary(Cs, utf8, utf8),
convert_to_list(to_lower(B), utf8);
diff --git a/lib/stdlib/src/zip.erl b/lib/stdlib/src/zip.erl
index 39be2abff6..a922bf3fbe 100644
--- a/lib/stdlib/src/zip.erl
+++ b/lib/stdlib/src/zip.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile
index ae2e3d0e2b..bbe3cefa42 100644
--- a/lib/stdlib/test/Makefile
+++ b/lib/stdlib/test/Makefile
@@ -88,6 +88,7 @@ MODULES= \
unicode_SUITE \
unicode_util_SUITE \
uri_string_SUITE \
+ uri_string_property_test_SUITE \
win32reg_SUITE \
y2k_SUITE \
select_SUITE \
@@ -152,6 +153,6 @@ release_tests_spec: make_emakefile
$(INSTALL_DATA) stdlib.spec stdlib_bench.spec $(EMAKEFILE) \
$(ERL_FILES) $(COVERFILE) "$(RELSYSDIR)"
chmod -R u+w "$(RELSYSDIR)"
- @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
+ @tar cf - *_SUITE_data property_test | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/stdlib/test/array_SUITE.erl b/lib/stdlib/test/array_SUITE.erl
index 956582c4fd..df520ebb54 100644
--- a/lib/stdlib/test/array_SUITE.erl
+++ b/lib/stdlib/test/array_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/test/beam_lib_SUITE.erl b/lib/stdlib/test/beam_lib_SUITE.erl
index 73219f8fd8..3597d6d94b 100644
--- a/lib/stdlib/test/beam_lib_SUITE.erl
+++ b/lib/stdlib/test/beam_lib_SUITE.erl
@@ -78,7 +78,7 @@ normal(Conf) when is_list(Conf) ->
BeamFile = Simple ++ ".beam",
simple_file(Source),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
do_normal(Source, PrivDir, BeamFile, []),
@@ -95,7 +95,7 @@ normal(Conf) when is_list(Conf) ->
file:delete(BeamFile),
file:delete(Source),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
true = (P0 == pps()),
ok.
@@ -173,7 +173,7 @@ error(Conf) when is_list(Conf) ->
WrongFile = Simple ++ "foo.beam",
simple_file(Source),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
{ok,_} = compile:file(Source, [{outdir,PrivDir},debug_info]),
ACopy = filename:join(PrivDir, "a_copy.beam"),
@@ -213,7 +213,7 @@ error(Conf) when is_list(Conf) ->
%% we have eliminated them.
ok = file:write_file(BeamFile, <<"FOR1",5:32,"BEAMfel">>),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
true = (P0 == pps()),
file:delete(Source),
file:delete(WrongFile),
@@ -273,7 +273,7 @@ cmp(Conf) when is_list(Conf) ->
{Source2D1, BeamFile2D1} = make_beam(Dir1, simple2, concat),
{SourceD2, BeamFileD2} = make_beam(Dir2, simple, concat),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
%% cmp
@@ -300,7 +300,7 @@ cmp(Conf) when is_list(Conf) ->
ver(not_a_directory, beam_lib:diff_dirs(foo, bar)),
true = (P0 == pps()),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
delete_files([SourceD1, BeamFileD1, Source2D1,
BeamFile2D1, SourceD2, BeamFileD2]),
@@ -321,7 +321,7 @@ cmp_literals(Conf) when is_list(Conf) ->
{SourceD1, BeamFileD1} = make_beam(Dir1, simple, constant),
{SourceD2, BeamFileD2} = make_beam(Dir2, simple, constant2),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
%% cmp
@@ -334,7 +334,7 @@ cmp_literals(Conf) when is_list(Conf) ->
ver(chunks_different, beam_lib:cmp(B1, B2)),
true = (P0 == pps()),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
delete_files([SourceD1, BeamFileD1, SourceD2, BeamFileD2]),
@@ -351,7 +351,7 @@ strip(Conf) when is_list(Conf) ->
{Source4D1, BeamFile4D1} = make_beam(PrivDir, constant, constant),
{Source5D1, BeamFile5D1} = make_beam(PrivDir, lines, lines),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
%% strip binary
@@ -392,7 +392,7 @@ strip(Conf) when is_list(Conf) ->
(catch lines:t(atom)),
true = (P0 == pps()),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
delete_files([SourceD1, BeamFileD1,
Source2D1, BeamFile2D1,
@@ -457,7 +457,7 @@ building(Conf) when is_list(Conf) ->
{SourceD1, BeamFileD1} = make_beam(Dir1, building, member),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
%% read all chunks
@@ -487,7 +487,7 @@ building(Conf) when is_list(Conf) ->
end, ChunkIds),
true = (P0 == pps()),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
delete_files([SourceD1, BeamFileD1, BeamFileD2]),
file:del_dir(Dir1),
@@ -535,7 +535,7 @@ encrypted_abstr_1(Conf) ->
%% Avoid getting an extra port when crypto starts erl_ddll.
erl_ddll:start(),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
Key = "#a_crypto_key",
@@ -549,7 +549,7 @@ encrypted_abstr_1(Conf) ->
ok = crypto:stop(), %To get rid of extra ets tables.
file:delete(BeamFile),
file:delete(Source),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
true = (P0 == pps()),
ok.
@@ -658,7 +658,7 @@ encrypted_abstr_file_1(Conf) ->
%% Avoid getting an extra port when crypto starts erl_ddll.
erl_ddll:start(),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
P0 = pps(),
Key = "Long And niCe 99Krypto Key",
@@ -676,7 +676,7 @@ encrypted_abstr_file_1(Conf) ->
file:delete(filename:join(PrivDir, ".erlang.crypt")),
file:delete(BeamFile),
file:delete(Source),
- NoOfTables = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
true = (P0 == pps()),
ok.
diff --git a/lib/stdlib/test/c_SUITE.erl b/lib/stdlib/test/c_SUITE.erl
index f01988478c..bd84cdd228 100644
--- a/lib/stdlib/test/c_SUITE.erl
+++ b/lib/stdlib/test/c_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl
index 7d82790b82..fe324391af 100644
--- a/lib/stdlib/test/dets_SUITE.erl
+++ b/lib/stdlib/test/dets_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl
index 9123bf2f28..10e1b75e0f 100644
--- a/lib/stdlib/test/epp_SUITE.erl
+++ b/lib/stdlib/test/epp_SUITE.erl
@@ -28,7 +28,8 @@
otp_8130/1, overload_mac/1, otp_8388/1, otp_8470/1,
otp_8562/1, otp_8665/1, otp_8911/1, otp_10302/1, otp_10820/1,
otp_11728/1, encoding/1, extends/1, function_macro/1,
- test_error/1, test_warning/1, otp_14285/1]).
+ test_error/1, test_warning/1, otp_14285/1,
+ test_if/1]).
-export([epp_parse_erl_form/2]).
@@ -69,7 +70,7 @@ all() ->
overload_mac, otp_8388, otp_8470, otp_8562,
otp_8665, otp_8911, otp_10302, otp_10820, otp_11728,
encoding, extends, function_macro, test_error, test_warning,
- otp_14285].
+ otp_14285, test_if].
groups() ->
[{upcase_mac, [], [upcase_mac_1, upcase_mac_2]},
@@ -799,7 +800,8 @@ otp_8130(Config) when is_list(Config) ->
PreDefMacs = macs(Epp),
['BASE_MODULE','BASE_MODULE_STRING','BEAM','FILE',
'FUNCTION_ARITY','FUNCTION_NAME',
- 'LINE','MACHINE','MODULE','MODULE_STRING'] = PreDefMacs,
+ 'LINE','MACHINE','MODULE','MODULE_STRING',
+ 'OTP_RELEASE'] = PreDefMacs,
{ok,[{'-',_},{atom,_,file}|_]} = epp:scan_erl_form(Epp),
{ok,[{'-',_},{atom,_,module}|_]} = epp:scan_erl_form(Epp),
{ok,[{atom,_,t}|_]} = epp:scan_erl_form(Epp),
@@ -952,27 +954,7 @@ ifdef(Config) ->
{define_c5,
<<"-\ndefine a.\n">>,
- {errors,[{{2,1},epp,{bad,define}}],[]}},
-
- {define_c6,
- <<"\n-if.\n"
- "-endif.\n">>,
- {errors,[{{2,2},epp,{'NYI','if'}}],[]}},
-
- {define_c7,
- <<"-ifndef(a).\n"
- "-elif.\n"
- "-endif.\n">>,
- {errors,[{{2,2},epp,{'NYI',elif}}],[]}},
-
- {define_c7,
- <<"-ifndef(a).\n"
- "-if.\n"
- "-elif.\n"
- "-endif.\n"
- "-endif.\n"
- "t() -> a.\n">>,
- {errors,[{{2,2},epp,{'NYI','if'}}],[]}}
+ {errors,[{{2,1},epp,{bad,define}}],[]}}
],
[] = compile(Config, Cs),
@@ -1117,6 +1099,147 @@ test_warning(Config) ->
[] = compile(Config, Cs),
ok.
+%% OTP-12847: Test the -if and -elif directives and the built-in
+%% function defined(Symbol).
+test_if(Config) ->
+ Cs = [{if_1c,
+ <<"-if.\n"
+ "-endif.\n"
+ "-if no_parentheses.\n"
+ "-endif.\n"
+ "-if(syntax error.\n"
+ "-endif.\n"
+ "-if(true).\n"
+ "-if(a+3).\n"
+ "syntax error not triggered here.\n"
+ "-endif.\n">>,
+ {errors,[{1,epp,{bad,'if'}},
+ {3,epp,{bad,'if'}},
+ {5,erl_parse,["syntax error before: ","error"]},
+ {11,epp,{illegal,"unterminated",'if'}}],
+ []}},
+
+ {if_2c, %Bad guard expressions.
+ <<"-if(is_list(integer_to_list(42))).\n" %Not guard BIF.
+ "-endif.\n"
+ "-if(begin true end).\n"
+ "-endif.\n">>,
+ {errors,[{1,epp,{bad,'if'}},
+ {3,epp,{bad,'if'}}],
+ []}},
+
+ {if_3c, %Invalid use of defined/1.
+ <<"-if defined(42).\n"
+ "-endif.\n">>,
+ {errors,[{1,epp,{bad,'if'}}],[]}},
+
+ {if_4c,
+ <<"-elif OTP_RELEASE > 18.\n">>,
+ {errors,[{1,epp,{illegal,"unbalanced",'elif'}}],[]}},
+
+ {if_5c,
+ <<"-ifdef(not_defined_today).\n"
+ "-else.\n"
+ "-elif OTP_RELEASE > 18.\n"
+ "-endif.\n">>,
+ {errors,[{3,epp,{illegal,"unbalanced",'elif'}}],[]}},
+
+ {if_6c,
+ <<"-if(defined(OTP_RELEASE)).\n"
+ "-else.\n"
+ "-elif(true).\n"
+ "-endif.\n">>,
+ {errors,[{3,epp,elif_after_else}],[]}},
+
+ {if_7c,
+ <<"-if(begin true end).\n" %Not a guard expression.
+ "-endif.\n">>,
+ {errors,[{1,epp,{bad,'if'}}],[]}}
+
+ ],
+ [] = compile(Config, Cs),
+
+ Ts = [{if_1,
+ <<"-if(?OTP_RELEASE > 18).\n"
+ "t() -> ok.\n"
+ "-else.\n"
+ "a bug.\n"
+ "-endif.\n">>,
+ ok},
+
+ {if_2,
+ <<"-if(false).\n"
+ "a bug.\n"
+ "-elif(?OTP_RELEASE > 18).\n"
+ "t() -> ok.\n"
+ "-else.\n"
+ "a bug.\n"
+ "-endif.\n">>,
+ ok},
+
+ {if_3,
+ <<"-if(true).\n"
+ "t() -> ok.\n"
+ "-elif(?OTP_RELEASE > 18).\n"
+ "a bug.\n"
+ "-else.\n"
+ "a bug.\n"
+ "-endif.\n">>,
+ ok},
+
+ {if_4,
+ <<"-define(a, 1).\n"
+ "-if(defined(a) andalso defined(OTP_RELEASE)).\n"
+ "t() -> ok.\n"
+ "-else.\n"
+ "a bug.\n"
+ "-endif.\n">>,
+ ok},
+
+ {if_5,
+ <<"-if(defined(a)).\n"
+ "a bug.\n"
+ "-else.\n"
+ "t() -> ok.\n"
+ "-endif.\n">>,
+ ok},
+
+ {if_6,
+ <<"-if(defined(not_defined_today)).\n"
+ " -if(true).\n"
+ " bug1.\n"
+ " -elif(true).\n"
+ " bug2.\n"
+ " -elif(true).\n"
+ " bug3.\n"
+ " -else.\n"
+ " bug4.\n"
+ " -endif.\n"
+ "-else.\n"
+ "t() -> ok.\n"
+ "-endif.\n">>,
+ ok},
+
+ {if_7,
+ <<"-if(not_builtin()).\n"
+ "a bug.\n"
+ "-else.\n"
+ "t() -> ok.\n"
+ "-endif.\n">>,
+ ok},
+
+ {if_8,
+ <<"-if(42).\n" %Not boolean.
+ "a bug.\n"
+ "-else.\n"
+ "t() -> ok.\n"
+ "-endif.\n">>,
+ ok}
+ ],
+ [] = run(Config, Ts),
+
+ ok.
+
%% Advanced test on overloading macros.
overload_mac(Config) when is_list(Config) ->
Cs = [
@@ -1249,7 +1372,7 @@ otp_8562(Config) when is_list(Config) ->
otp_8911(Config) when is_list(Config) ->
case test_server:is_cover() of
true ->
- {skip, "Testing cover, so can not run when cover is already running"};
+ {skip, "Testing cover, so cannot run when cover is already running"};
false ->
do_otp_8911(Config)
end.
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index f9ab83a120..c1613a7273 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -2730,7 +2730,7 @@ bif_clash(Config) when is_list(Config) ->
[],
{errors,[{2,erl_lint,{call_to_redefined_old_bif,{size,1}}}],[]}},
- %% Verify that warnings can not be turned off in the old way.
+ %% Verify that warnings cannot be turned off in the old way.
{clash2,
<<"-export([t/1,size/1]).
t(X) ->
diff --git a/lib/stdlib/test/error_logger_h_SUITE.erl b/lib/stdlib/test/error_logger_h_SUITE.erl
index d533305939..bf9b6d9ad6 100644
--- a/lib/stdlib/test/error_logger_h_SUITE.erl
+++ b/lib/stdlib/test/error_logger_h_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index 02211fa8df..fee8b204f4 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -87,6 +87,7 @@
-export([t_select_reverse/1]).
+-include_lib("stdlib/include/ms_transform.hrl"). % ets:fun2ms
-include_lib("common_test/include/ct.hrl").
-define(m(A,B), assert_eq(A,B)).
@@ -173,10 +174,12 @@ groups() ->
init_per_suite(Config) ->
erts_debug:set_internal_state(available_internal_state, true),
+ erts_debug:set_internal_state(ets_force_trap, true),
Config.
end_per_suite(_Config) ->
stop_spawn_logger(),
+ erts_debug:set_internal_state(ets_force_trap, false),
catch erts_debug:set_internal_state(available_internal_state, false),
ok.
@@ -812,7 +815,60 @@ t_delete_all_objects_do(Opts) ->
4000 = ets:info(T,size),
true = ets:delete_all_objects(T),
0 = ets:info(T,size),
- ets:delete(T).
+ ets:delete(T),
+
+ %% Test delete_all_objects is atomic
+ T2 = ets:new(t_delete_all_objects, [public | Opts]),
+ Self = self(),
+ Inserters = [spawn_link(fun() -> inserter(T2, 100*1000, 1, Self) end) || _ <- [1,2,3,4]],
+ [receive {Ipid, running} -> ok end || Ipid <- Inserters],
+
+ ets:delete_all_objects(T2),
+ erlang:yield(),
+ [Ipid ! stop || Ipid <- Inserters],
+ Result = [receive {Ipid, stopped, Highest} -> {Ipid,Highest} end || Ipid <- Inserters],
+
+ %% Verify unbroken sequences of objects inserted _after_ ets:delete_all_objects.
+ Sum = lists:foldl(fun({Ipid, Highest}, AccSum) ->
+ %% ets:fun2ms(fun({{K,Ipid}}) when K =< Highest -> true end),
+ AliveMS = [{{{'$1',Ipid}},[{'=<','$1',{const,Highest}}],[true]}],
+ Alive = ets:select_count(T2, AliveMS),
+ Lowest = Highest - (Alive-1),
+
+ %% ets:fun2ms(fun({{K,Ipid}}) when K < Lowest -> true end)
+ DeletedMS = [{{{'$1',Ipid}},[{'<','$1',{const,Lowest}}],[true]}],
+ 0 = ets:select_count(T2, DeletedMS),
+ AccSum + Alive
+ end,
+ 0,
+ Result),
+ ok = case ets:info(T2, size) of
+ Sum -> ok;
+ Size ->
+ io:format("Sum = ~p\nSize = ~p\n", [Sum, Size]),
+ {Sum,Size}
+ end,
+
+ ets:delete(T2).
+
+inserter(_, 0, _, _) ->
+ ok;
+inserter(T, N, Next, Papa) ->
+ case Next of
+ 10*1000 ->
+ Papa ! {self(), running};
+ _ ->
+ ok
+ end,
+
+ ets:insert(T, {{Next, self()}}),
+ receive
+ stop ->
+ Papa ! {self(), stopped, Next},
+ ok
+ after 0 ->
+ inserter(T, N-1, Next+1, Papa)
+ end.
%% Test ets:delete_object/2.
@@ -6056,40 +6112,11 @@ etsmem() ->
ets:info(T,memory),ets:info(T,type)}
end, ets:all()),
- EtsAllocInfo = erlang:system_info({allocator,ets_alloc}),
+ EtsAllocSize = erts_debug:alloc_blocks_size(ets_alloc),
ErlangMemoryEts = try erlang:memory(ets) catch error:notsup -> notsup end,
- Mem =
- {ErlangMemoryEts,
- case EtsAllocInfo of
- false -> undefined;
- MemInfo ->
- CS = lists:foldl(
- fun ({instance, _, L}, Acc) ->
- {value,{mbcs,MBCS}} = lists:keysearch(mbcs, 1, L),
- {value,{sbcs,SBCS}} = lists:keysearch(sbcs, 1, L),
- NewAcc = [MBCS, SBCS | Acc],
- case lists:keysearch(mbcs_pool, 1, L) of
- {value,{mbcs_pool, MBCS_POOL}} ->
- [MBCS_POOL|NewAcc];
- _ -> NewAcc
- end
- end,
- [],
- MemInfo),
- lists:foldl(
- fun(L, {Bl0,BlSz0}) ->
- {value,BlTup} = lists:keysearch(blocks, 1, L),
- blocks = element(1, BlTup),
- Bl = element(2, BlTup),
- {value,BlSzTup} = lists:keysearch(blocks_size, 1, L),
- blocks_size = element(1, BlSzTup),
- BlSz = element(2, BlSzTup),
- {Bl0+Bl,BlSz0+BlSz}
- end, {0,0}, CS)
- end},
- {Mem,AllTabs}.
-
+ Mem = {ErlangMemoryEts, EtsAllocSize},
+ {Mem, AllTabs}.
verify_etsmem(MI) ->
wait_for_test_procs(),
@@ -6153,20 +6180,23 @@ spawn_logger(Procs) ->
ok;
(Proc) ->
Mon = erlang:monitor(process, Proc),
- receive
+ ok = receive
{'DOWN', Mon, _, _, _} ->
ok
after 0 ->
case Kill of
true -> exit(Proc, kill);
- _ ->
- erlang:display({"Waiting for 'DOWN' from", Proc,
- process_info(Proc),
- pid_status(Proc)})
+ _ -> ok
end,
receive
{'DOWN', Mon, _, _, _} ->
ok
+ after 5000 ->
+ io:format("Waiting for 'DOWN' from ~w, status=~w\n"
+ "info = ~p\n", [Proc,
+ pid_status(Proc),
+ process_info(Proc)]),
+ timeout
end
end
end, Procs),
diff --git a/lib/stdlib/test/id_transform_SUITE.erl b/lib/stdlib/test/id_transform_SUITE.erl
index 186df41d3f..0addf09461 100644
--- a/lib/stdlib/test/id_transform_SUITE.erl
+++ b/lib/stdlib/test/id_transform_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/test/io_SUITE.erl b/lib/stdlib/test/io_SUITE.erl
index 9f48fbf5e3..f097552e8c 100644
--- a/lib/stdlib/test/io_SUITE.erl
+++ b/lib/stdlib/test/io_SUITE.erl
@@ -31,7 +31,8 @@
otp_10836/1, io_lib_width_too_small/1,
io_with_huge_message_queue/1, format_string/1,
maps/1, coverage/1, otp_14178_unicode_atoms/1, otp_14175/1,
- otp_14285/1, limit_term/1, otp_14983/1]).
+ otp_14285/1, limit_term/1, otp_14983/1, otp_15103/1, otp_15076/1,
+ otp_15159/1]).
-export([pretty/2, trf/3]).
@@ -63,7 +64,7 @@ all() ->
io_lib_print_binary_depth_one, otp_10302, otp_10755, otp_10836,
io_lib_width_too_small, io_with_huge_message_queue,
format_string, maps, coverage, otp_14178_unicode_atoms, otp_14175,
- otp_14285, limit_term, otp_14983].
+ otp_14285, limit_term, otp_14983, otp_15103, otp_15076, otp_15159].
%% Error cases for output.
error_1(Config) when is_list(Config) ->
@@ -1808,7 +1809,7 @@ rpc_call_max(Node, M, F, Args) ->
%% Make sure that a bad specification for a printable range is rejected.
bad_printable_range(Config) when is_list(Config) ->
- Cmd = lists:concat([lib:progname()," +pcunnnnnicode -run erlang halt"]),
+ Cmd = ct:get_progname() ++ " +pcunnnnnicode -run erlang halt",
P = open_port({spawn, Cmd}, [stderr_to_stdout, {line, 200}]),
ok = receive
{P, {data, {eol , "bad range of printable characters" ++ _}}} ->
@@ -2615,3 +2616,34 @@ trf(Format, Args, T) ->
trf(Format, Args, T, Opts) ->
lists:flatten(io_lib:format(Format, Args, [{chars_limit, T}|Opts])).
+
+otp_15103(_Config) ->
+ T = lists:duplicate(5, {a,b,c}),
+
+ S1 = io_lib:format("~0p", [T]),
+ "[{a,b,c},{a,b,c},{a,b,c},{a,b,c},{a,b,c}]" = lists:flatten(S1),
+ S2 = io_lib:format("~-0p", [T]),
+ "[{a,b,c},{a,b,c},{a,b,c},{a,b,c},{a,b,c}]" = lists:flatten(S2),
+ S3 = io_lib:format("~1p", [T]),
+ "[{a,\n b,\n c},\n {a,\n b,\n c},\n {a,\n b,\n c},\n {a,\n b,\n"
+ " c},\n {a,\n b,\n c}]" = lists:flatten(S3),
+
+ S4 = io_lib:format("~0P", [T, 5]),
+ "[{a,b,c},{a,b,...},{a,...},{...}|...]" = lists:flatten(S4),
+ S5 = io_lib:format("~1P", [T, 5]),
+ "[{a,\n b,\n c},\n {a,\n b,...},\n {a,...},\n {...}|...]" =
+ lists:flatten(S5),
+ ok.
+
+otp_15159(_Config) ->
+ "[atom]" =
+ lists:flatten(io_lib:format("~p", [[atom]], [{chars_limit,5}])),
+ ok.
+
+otp_15076(_Config) ->
+ {'EXIT', {badarg, _}} = (catch io_lib:format("~c", [a])),
+ L = io_lib:scan_format("~c", [a]),
+ {"~c", [a]} = io_lib:unscan_format(L),
+ {'EXIT', {badarg, _}} = (catch io_lib:build_text(L)),
+ {'EXIT', {badarg, _}} = (catch io_lib:build_text(L, [])),
+ ok.
diff --git a/lib/stdlib/test/lists_SUITE.erl b/lib/stdlib/test/lists_SUITE.erl
index 837ab4e97e..af94fc79bc 100644
--- a/lib/stdlib/test/lists_SUITE.erl
+++ b/lib/stdlib/test/lists_SUITE.erl
@@ -1679,7 +1679,7 @@ make_fun() ->
receive {Pid, Fun} -> Fun end.
make_fun(Pid) ->
- Pid ! {self(), fun make_fun/1}.
+ Pid ! {self(), fun (X) -> {X, Pid} end}.
fun_pid(Fun) ->
erlang:fun_info(Fun, pid).
diff --git a/lib/stdlib/test/maps_SUITE.erl b/lib/stdlib/test/maps_SUITE.erl
index a75751b31d..6f3cd8bf1b 100644
--- a/lib/stdlib/test/maps_SUITE.erl
+++ b/lib/stdlib/test/maps_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -108,6 +108,8 @@ t_without_2(_Config) ->
%% error case
?badmap(a,without,[[a,b],a]) = (catch maps:without([a,b],id(a))),
?badmap(a,without,[{a,b},a]) = (catch maps:without({a,b},id(a))),
+ ?badmap({0,<<>>,97},without,[[],{0,<<>>,97}]) = (catch maps:without([], {0,<<>>,97})),
+ ?badmap({0,<<>>,97},without,[[false, -20, -8],{0,<<>>,97}]) = (catch maps:without([false, -20, -8], {0, <<>>, 97})),
?badarg(without,[a,#{}]) = (catch maps:without(a,#{})),
ok.
@@ -120,6 +122,8 @@ t_with_2(_Config) ->
%% error case
?badmap(a,with,[[a,b],a]) = (catch maps:with([a,b],id(a))),
?badmap(a,with,[{a,b},a]) = (catch maps:with({a,b},id(a))),
+ ?badmap({0,<<>>,97},with,[[],{0,<<>>,97}]) = (catch maps:with([], {0,<<>>,97})),
+ ?badmap({0,<<>>,97},with,[[false, -20, -8],{0,<<>>,97}]) = (catch maps:with([false, -20, -8], {0, <<>>, 97})),
?badarg(with,[a,#{}]) = (catch maps:with(a,#{})),
ok.
diff --git a/lib/stdlib/test/proc_lib_SUITE.erl b/lib/stdlib/test/proc_lib_SUITE.erl
index 81bf9020b8..127b1317e4 100644
--- a/lib/stdlib/test/proc_lib_SUITE.erl
+++ b/lib/stdlib/test/proc_lib_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -542,13 +542,14 @@ system_terminate(Reason,_Parent,_Deb,_State) ->
t_format(_Config) ->
- logger:add_handler_filter(logger_std_h,stop_all,{fun(_,_) -> stop end,ok}),
+ {ok,#{level:=Level}} = logger:get_handler_config(default),
+ logger:set_handler_config(default,level,none),
error_logger:add_report_handler(?MODULE, self()),
try
t_format()
after
error_logger:delete_report_handler(?MODULE),
- logger:remove_handler_filter(logger_std_h,stop_all)
+ logger:set_handler_config(default,level,Level)
end,
ok.
@@ -585,11 +586,12 @@ t_format() ->
ok.
t_format_arbitrary(_Config) ->
- logger:add_handler_filter(logger_std_h,stop_all,{fun(_,_) -> stop end,ok}),
+ {ok,#{level:=Level}} = logger:get_handler_config(default),
+ logger:set_handler_config(default,level,none),
try
t_format_arbitrary()
after
- logger:remove_handler_filter(logger_std_h,stop_all)
+ logger:set_handler_config(default,level,Level)
end,
ok.
diff --git a/lib/stdlib/test/property_test/uri_string_recompose.erl b/lib/stdlib/test/property_test/uri_string_recompose.erl
index e51a671172..39fadf23c2 100644
--- a/lib/stdlib/test/property_test/uri_string_recompose.erl
+++ b/lib/stdlib/test/property_test/uri_string_recompose.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -65,15 +65,29 @@
-define(QUERY, {query, query_map()}).
-define(FRAGMENT, {fragment, fragment_map()}).
+%% Non-unicode
+-define(USER_NU, {userinfo, non_unicode()}).
+-define(HOST_NU, {host, host_map_nu()}).
+-define(PATH_ABE_NU, {path, path_abempty_map_nu()}).
+-define(PATH_ABS_NU, {path, path_absolute_map_nu()}).
+-define(PATH_NOS_NU, {path, path_noscheme_map_nu()}).
+-define(PATH_ROO_NU, {path, path_rootless_map_nu()}).
+-define(QUERY_NU, {query, query_map_nu()}).
+-define(FRAGMENT_NU, {fragment, fragment_map_nu()}).
%%%========================================================================
%%% Properties
%%%========================================================================
prop_recompose() ->
+ ?FORALL(Map, map_no_unicode(),
+ Map =:= uri_string:parse(uri_string:recompose(Map))).
+
+prop_normalize() ->
?FORALL(Map, map(),
- Map =:= uri_string:parse(uri_string:recompose(Map))
- ).
+ uri_string:normalize(Map, [return_map]) =:=
+ uri_string:normalize(uri_string:parse(uri_string:recompose(Map)),
+ [return_map])).
%% Stats
prop_map_key_length_collect() ->
@@ -96,6 +110,9 @@ prop_scheme_collect() ->
map() ->
?LET(Gen, comp_proplist(), proplist_to_map(Gen)).
+map_no_unicode() ->
+ ?LET(Gen, comp_proplist_nu(), proplist_to_map(Gen)).
+
comp_proplist() ->
frequency([
{2, [?SCHEME,?PATH_ABS]},
@@ -166,6 +183,76 @@ comp_proplist() ->
{2, [?USER,?HOST,?PORT,?PATH_ABE,?QUERY,?FRAGMENT]}
]).
+comp_proplist_nu() ->
+ frequency([
+ {2, [?SCHEME,?PATH_ABS_NU]},
+ {2, [?SCHEME,?PATH_ROO_NU]},
+ {2, [?SCHEME,?PATH_EMP]},
+ {2, [?SCHEME,?HOST_NU,?PATH_ABE_NU]},
+ {2, [?SCHEME,?USER_NU,?HOST_NU,?PATH_ABE_NU]},
+ {2, [?SCHEME,?HOST_NU,?PORT,?PATH_ABE_NU]},
+ {2, [?SCHEME,?USER_NU,?HOST_NU,?PORT,?PATH_ABE_NU]},
+
+ {2, [?PATH_ABS_NU]},
+ {2, [?PATH_NOS_NU]},
+ {2, [?PATH_EMP]},
+ {2, [?HOST_NU,?PATH_ABE_NU]},
+ {2, [?USER_NU,?HOST_NU,?PATH_ABE_NU]},
+ {2, [?HOST_NU,?PORT,?PATH_ABE_NU]},
+ {2, [?USER_NU,?HOST_NU,?PORT,?PATH_ABE_NU]},
+
+
+ {2, [?SCHEME,?PATH_ABS_NU,?QUERY_NU]},
+ {2, [?SCHEME,?PATH_ROO_NU,?QUERY_NU]},
+ {2, [?SCHEME,?PATH_EMP,?QUERY_NU]},
+ {2, [?SCHEME,?HOST_NU,?PATH_ABE_NU,?QUERY_NU]},
+ {2, [?SCHEME,?USER_NU,?HOST_NU,?PATH_ABE_NU,?QUERY_NU]},
+ {2, [?SCHEME,?HOST_NU,?PORT,?PATH_ABE_NU,?QUERY_NU]},
+ {2, [?SCHEME,?USER_NU,?HOST_NU,?PORT,?PATH_ABE_NU,?QUERY_NU]},
+
+ {2, [?PATH_ABS_NU,?QUERY_NU]},
+ {2, [?PATH_NOS_NU,?QUERY_NU]},
+ {2, [?PATH_EMP,?QUERY_NU]},
+ {2, [?HOST_NU,?PATH_ABE_NU,?QUERY_NU]},
+ {2, [?USER_NU,?HOST_NU,?PATH_ABE_NU,?QUERY_NU]},
+ {2, [?HOST_NU,?PORT,?PATH_ABE_NU,?QUERY_NU]},
+ {2, [?USER_NU,?HOST_NU,?PORT,?PATH_ABE_NU,?QUERY_NU]},
+
+
+ {2, [?SCHEME,?PATH_ABS_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?PATH_ROO_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?PATH_EMP,?FRAGMENT_NU]},
+ {2, [?SCHEME,?HOST_NU,?PATH_ABE_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?USER_NU,?HOST_NU,?PATH_ABE_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?HOST_NU,?PORT,?PATH_ABE_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?USER_NU,?HOST_NU,?PORT,?PATH_ABE_NU,?FRAGMENT_NU]},
+
+ {2, [?PATH_ABS_NU,?FRAGMENT_NU]},
+ {2, [?PATH_NOS_NU,?FRAGMENT_NU]},
+ {2, [?PATH_EMP,?FRAGMENT_NU]},
+ {2, [?HOST_NU,?PATH_ABE_NU,?FRAGMENT_NU]},
+ {2, [?USER_NU,?HOST_NU,?PATH_ABE_NU,?FRAGMENT_NU]},
+ {2, [?HOST_NU,?PORT,?PATH_ABE_NU,?FRAGMENT_NU]},
+ {2, [?USER_NU,?HOST_NU,?PORT,?PATH_ABE_NU,?FRAGMENT_NU]},
+
+
+ {2, [?SCHEME,?PATH_ABS_NU,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?PATH_ROO_NU,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?PATH_EMP,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?HOST_NU,?PATH_ABE_NU,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?USER_NU,?HOST_NU,?PATH_ABE_NU,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?HOST_NU,?PORT,?PATH_ABE_NU,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?SCHEME,?USER_NU,?HOST_NU,?PORT,?PATH_ABE_NU,?QUERY_NU,?FRAGMENT_NU]},
+
+ {2, [?PATH_ABS_NU,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?PATH_NOS_NU,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?PATH_EMP,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?HOST_NU,?PATH_ABE_NU,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?USER_NU,?HOST_NU,?PATH_ABE_NU,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?HOST_NU,?PORT,?PATH_ABE_NU,?QUERY_NU,?FRAGMENT_NU]},
+ {2, [?USER_NU,?HOST_NU,?PORT,?PATH_ABE_NU,?QUERY_NU,?FRAGMENT_NU]}
+ ]).
+
%%-------------------------------------------------------------------------
%% Path
@@ -174,6 +261,11 @@ path_abempty_map() ->
frequency([{90, path_abe_map()},
{10, path_empty_map()}]).
+path_abempty_map_nu() ->
+ frequency([{90, path_abe_map_nu()},
+ {10, path_empty_map()}]).
+
+
path_abe_map() ->
?SIZED(Length, path_abe_map(Length, [])).
%%
@@ -182,6 +274,14 @@ path_abe_map(0, Segments) ->
path_abe_map(N, Segments) ->
path_abe_map(N-1, [slash(),segment()|Segments]).
+path_abe_map_nu() ->
+ ?SIZED(Length, path_abe_map_nu(Length, [])).
+%%
+path_abe_map_nu(0, Segments) ->
+ ?LET(Gen, Segments, lists:append(Gen));
+path_abe_map_nu(N, Segments) ->
+ path_abe_map_nu(N-1, [slash(),segment_nu()|Segments]).
+
path_absolute_map() ->
?SIZED(Length, path_absolute_map(Length, [])).
@@ -191,6 +291,14 @@ path_absolute_map(0, Segments) ->
path_absolute_map(N, Segments) ->
path_absolute_map(N-1, [slash(),segment()|Segments]).
+path_absolute_map_nu() ->
+ ?SIZED(Length, path_absolute_map_nu(Length, [])).
+%%
+path_absolute_map_nu(0, Segments) ->
+ ?LET(Gen, [slash(),segment_nz_nu()|Segments], lists:append(Gen));
+path_absolute_map_nu(N, Segments) ->
+ path_absolute_map_nu(N-1, [slash(),segment_nu()|Segments]).
+
path_noscheme_map() ->
?SIZED(Length, path_noscheme_map(Length, [])).
@@ -200,6 +308,15 @@ path_noscheme_map(0, Segments) ->
path_noscheme_map(N, Segments) ->
path_noscheme_map(N-1, [slash(),segment()|Segments]).
+path_noscheme_map_nu() ->
+ ?SIZED(Length, path_noscheme_map_nu(Length, [])).
+%%
+path_noscheme_map_nu(0, Segments) ->
+ ?LET(Gen, [segment_nz_nc_nu()|Segments], lists:append(Gen));
+path_noscheme_map_nu(N, Segments) ->
+ path_noscheme_map_nu(N-1, [slash(),segment_nu()|Segments]).
+
+
path_rootless_map() ->
?SIZED(Length, path_rootless_map(Length, [])).
%%
@@ -208,24 +325,59 @@ path_rootless_map(0, Segments) ->
path_rootless_map(N, Segments) ->
path_rootless_map(N-1, [slash(),segment()|Segments]).
+path_rootless_map_nu() ->
+ ?SIZED(Length, path_rootless_map_nu(Length, [])).
+%%
+path_rootless_map_nu(0, Segments) ->
+ ?LET(Gen, [segment_nz_nu()|Segments], lists:append(Gen));
+path_rootless_map_nu(N, Segments) ->
+ path_rootless_map_nu(N-1, [slash(),segment_nu()|Segments]).
+
segment_nz() ->
non_empty(segment()).
-segment_nz_nc() ->
- non_empty(list(frequency([{30, unreserved()},
- {10, sub_delims()},
- {10, unicode_char()},
- {5, oneof([$@])}
- ]))).
+segment_nz_nu() ->
+ non_empty(segment_nu()).
+segment_nz_nc() ->
+ ?LET(Gen,
+ non_empty(list(frequency([{30, unreserved()},
+ {10, ptc_encoded_reserved()},
+ {10, sub_delims()},
+ {10, unicode_char()},
+ {5, oneof([$@])}
+ ]))),
+ lists:flatten(Gen)).
+
+segment_nz_nc_nu() ->
+ ?LET(Gen,
+ non_empty(list(frequency([{30, unreserved()},
+ {10, ptc_encoded_reserved()},
+ {10, sub_delims()},
+ {5, oneof([$@])}
+ ]))),
+ lists:flatten(Gen)).
+
segment() ->
- list(frequency([{30, unreserved()},
- {10, sub_delims()},
- {10, unicode_char()},
- {5, oneof([$:, $@])}
- ])).
+ ?LET(Gen,
+ list(frequency([{30, unreserved()},
+ {10, ptc_encoded_reserved()},
+ {10, sub_delims()},
+ {10, unicode_char()},
+ {5, oneof([$:, $@])}
+ ])),
+ lists:flatten(Gen)).
+
+segment_nu() ->
+ ?LET(Gen,
+ list(frequency([{30, unreserved()},
+ {10, ptc_encoded_reserved()},
+ {10, sub_delims()},
+ {5, oneof([$:, $@])}
+ ])),
+ lists:flatten(Gen)).
slash() ->
"/".
@@ -235,19 +387,35 @@ path_empty_map() ->
%%-------------------------------------------------------------------------
-%% Path
+%% Host
%%-------------------------------------------------------------------------
host_map() ->
frequency([{30, reg_name()},
{30, ip_address()}
]).
+host_map_nu() ->
+ frequency([{30, reg_name_nu()},
+ {30, ip_address()}
+ ]).
reg_name() ->
- list(frequency([{30, alpha()},
- {10, sub_delims()},
- {10, unicode_char()}
- ])).
+ ?LET(Gen,
+ list(frequency([{30, alpha()},
+ {10, sub_delims()},
+ {10, ptc_encoded_reserved()},
+ {10, unicode_char()}
+ ])),
+ lists:flatten(Gen)).
+
+reg_name_nu() ->
+ ?LET(Gen,
+ list(frequency([{30, alpha()},
+ {10, sub_delims()},
+ {10, ptc_encoded_reserved()}
+ ])),
+ lists:flatten(Gen)).
+
ip_address() ->
oneof(["127.0.0.1", "::127.0.0.1",
@@ -258,10 +426,13 @@ ip_address() ->
%% Generating only reg-names
host_uri() ->
- non_empty(list(frequency([{30, unreserved()},
- {10, sub_delims()},
- {10, pct_encoded()}
- ]))).
+ ?LET(Gen,
+ non_empty(list(frequency([{30, unreserved()},
+ {10, sub_delims()},
+ {10, ptc_encoded_reserved()},
+ {10, pct_encoded()}
+ ]))),
+ lists:flatten(Gen)).
%%-------------------------------------------------------------------------
%% Port, Query, Fragment
@@ -274,6 +445,9 @@ port() ->
query_map() ->
unicode().
+query_map_nu() ->
+ non_unicode().
+
query_uri() ->
[$?| non_empty(list(frequency([{20, pchar()},
@@ -283,6 +457,10 @@ query_uri() ->
fragment_map() ->
unicode().
+fragment_map_nu() ->
+ non_unicode().
+
+
fragment_uri() ->
[$?| non_empty(list(frequency([{20, pchar()},
{5, oneof([$/, $?])} % punctuation
@@ -311,9 +489,14 @@ scheme(N, L) ->
%%-------------------------------------------------------------------------
unicode() ->
list(frequency([{20, alpha()}, % alpha
- {10, digit()}, % digit
- {10, unicode_char()} % unicode
- ])).
+ {10, digit()}, % digit
+ {10, unicode_char()} % unicode
+ ])).
+
+non_unicode() ->
+ list(frequency([{20, alpha()}, % alpha
+ {10, digit()} % digit
+ ])).
scheme_char() ->
frequency([{20, alpha()}, % alpha
@@ -327,6 +510,7 @@ sub_delims() ->
pchar() ->
frequency([{20, unreserved()},
+ {5, ptc_encoded_reserved()},
{5, pct_encoded()},
{5, sub_delims()},
{1, oneof([$:, $@])} % punctuation
@@ -351,6 +535,22 @@ digit() ->
pct_encoded() ->
oneof(["%C3%A4", "%C3%A5", "%C3%B6"]).
+%%-------------------------------------------------------------------------
+%% [RFC 3986, Chapter 2.2. Reserved Characters]
+%%
+%% reserved = gen-delims / sub-delims
+%%
+%% gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+%% 3A 2F 3F 23 5B 5D 40
+%% sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+%% 21 24 26 27 28 29
+%% / "*" / "+" / "," / ";" / "="
+%% 2A 2B 2C 3B 3D
+%%-------------------------------------------------------------------------
+ptc_encoded_reserved() ->
+ oneof(["%3A","%2F","%3F","%23","%5B","%5D","%40",
+ "%21","%24","%26","%27","%28","%29",
+ "%2A","%2B","%2C","%3B","3D"]).
%%%========================================================================
%%% Helpers
@@ -359,3 +559,13 @@ proplist_to_map(L) ->
lists:foldl(fun({K,V},M) -> M#{K => V};
(_,M) -> M
end, #{}, L).
+
+map_scheme_host_to_lower(Map) ->
+ Fun = fun (scheme,V) ->
+ string:to_lower(V);
+ (host,V) ->
+ string:to_lower(V);
+ (_,V) ->
+ V
+ end,
+ maps:map(Fun, Map).
diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl
index 8f8a0f6e73..d7354438f9 100644
--- a/lib/stdlib/test/qlc_SUITE.erl
+++ b/lib/stdlib/test/qlc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -7468,7 +7468,7 @@ strip_qlc_call(H) ->
strip_qlc_call2(H) ->
S = qlc:info(H, {flat, false}),
{ok, Tokens, _EndLine} = erl_scan:string(S++".", 1, [text]),
- {ok, [Expr], Bs} = lib:extended_parse_exprs(Tokens),
+ {ok, [Expr], Bs} = erl_eval:extended_parse_exprs(Tokens),
{case Expr of
{call,_,{remote,_,{atom,_,qlc},{atom,_,q}},[LC]} ->
{qlc, lists:flatten([erl_pp:expr(LC), "."]), []};
@@ -7489,7 +7489,7 @@ strip_qlc_call2(H) ->
join_info_count(H) ->
S = qlc:info(H, {flat, false}),
{ok, Tokens, _EndLine} = erl_scan:string(S++".", 1, [text]),
- {ok, [Expr], _Bs} = lib:extended_parse_exprs(Tokens),
+ {ok, [Expr], _Bs} = erl_eval:extended_parse_exprs(Tokens),
#ji{nmerge = Nmerge, nlookup = Nlookup,
nkeysort = NKeysort, nnested_loop = Nnested_loop} =
ji(Expr, #ji{}),
@@ -7533,7 +7533,7 @@ lookup_keys({generate,_,Q}, L) ->
lookup_keys(Q, L);
lookup_keys({table,Chars}, L) when is_list(Chars) ->
{ok, Tokens, _} = erl_scan:string(lists:flatten(Chars++"."), 1, [text]),
- {ok, [Expr], _Bs} = lib:extended_parse_exprs(Tokens),
+ {ok, [Expr], _Bs} = erl_eval:extended_parse_exprs(Tokens),
case Expr of
{call,_,_,[_fun,AKs]} ->
case erl_parse:normalise(AKs) of
diff --git a/lib/stdlib/test/re_SUITE.erl b/lib/stdlib/test/re_SUITE.erl
index 7b82647416..c9ef9da990 100644
--- a/lib/stdlib/test/re_SUITE.erl
+++ b/lib/stdlib/test/re_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/test/sets_SUITE.erl b/lib/stdlib/test/sets_SUITE.erl
index 7066d07e19..2c1b388d52 100644
--- a/lib/stdlib/test/sets_SUITE.erl
+++ b/lib/stdlib/test/sets_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/test/sets_test_lib.erl b/lib/stdlib/test/sets_test_lib.erl
index 93d027704b..e4d476ba54 100644
--- a/lib/stdlib/test/sets_test_lib.erl
+++ b/lib/stdlib/test/sets_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl
index ca85314775..22136d687c 100644
--- a/lib/stdlib/test/shell_SUITE.erl
+++ b/lib/stdlib/test/shell_SUITE.erl
@@ -2780,7 +2780,7 @@ otp_10302(Config) when is_list(Config) ->
rpc:call(Node,shell, prompt_func, [default]),
_ = shell:prompt_func(default),
- %% Test lib:format_exception() (cf. OTP-6554)
+ %% Test erl_error:format_exception() (cf. OTP-6554)
Test6 =
<<"begin
A = <<\"\\xaa\">>,
@@ -2967,10 +2967,10 @@ otp_14296(Config) when is_list(Config) ->
R = t(S)
end(),
- %% Test lib:extended_parse_term/1
+ %% Test erl_eval:extended_parse_term/1
TF = fun(S) ->
{ok, Ts, _} = erl_scan:string(S++".", 1, [text]),
- case lib:extended_parse_term(Ts) of
+ case erl_eval:extended_parse_term(Ts) of
{ok, Term} -> Term;
{error, _}=Error -> Error
end
diff --git a/lib/stdlib/test/stdlib.spec b/lib/stdlib/test/stdlib.spec
index 9c625091a8..4de7c1a0eb 100644
--- a/lib/stdlib/test/stdlib.spec
+++ b/lib/stdlib/test/stdlib.spec
@@ -1,4 +1,4 @@
{suites,"../stdlib_test",all}.
{skip_groups,"../stdlib_test",stdlib_bench_SUITE,
- [base64,gen_server,gen_statem,unicode],
+ [binary,base64,gen_server,gen_statem,unicode],
"Benchmark only"}.
diff --git a/lib/stdlib/test/stdlib_bench_SUITE.erl b/lib/stdlib/test/stdlib_bench_SUITE.erl
index 2364e8376f..b937eeb06a 100644
--- a/lib/stdlib/test/stdlib_bench_SUITE.erl
+++ b/lib/stdlib/test/stdlib_bench_SUITE.erl
@@ -29,7 +29,7 @@ suite() -> [{ct_hooks,[{ts_install_cth,[{nodenames,2}]}]}].
all() ->
- [{group,unicode},{group,base64},
+ [{group,unicode},{group,base64},{group,binary},
{group,gen_server},{group,gen_statem},
{group,gen_server_comparison},{group,gen_statem_comparison}].
@@ -38,6 +38,11 @@ groups() ->
[norm_nfc_list, norm_nfc_deep_l, norm_nfc_binary,
string_lexemes_list, string_lexemes_binary
]},
+ {binary, [{repeat, 5}],
+ [match_single_pattern_no_match,
+ matches_single_pattern_no_match,
+ matches_single_pattern_eventual_match,
+ matches_single_pattern_frequent_match]},
{base64,[{repeat,5}],
[decode_binary, decode_binary_to_string,
decode_list, decode_list_to_string,
@@ -157,41 +162,59 @@ norm_data(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+match_single_pattern_no_match(_Config) ->
+ Binary = binary:copy(<<"ugbcfuysabfuqyfikgfsdalpaskfhgjsdgfjwsalp">>, 1000000),
+ comment(test(binary, match, [Binary, <<"o">>])).
+
+matches_single_pattern_no_match(_Config) ->
+ Binary = binary:copy(<<"ugbcfuysabfuqyfikgfsdalpaskfhgjsdgfjwsalp">>, 1000000),
+ comment(test(binary, matches, [Binary, <<"o">>])).
+
+matches_single_pattern_eventual_match(_Config) ->
+ Binary = binary:copy(<<"ugbcfuysabfuqyfikgfsdalpaskfhgjsdgfjwsal\n">>, 1000000),
+ comment(test(binary, matches, [Binary, <<"\n">>])).
+
+matches_single_pattern_frequent_match(_Config) ->
+ Binary = binary:copy(<<"abc\n">>, 1000000),
+ comment(test(binary, matches, [Binary, <<"abc">>])).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
decode_binary(_Config) ->
- comment(test(decode, encoded_binary())).
+ comment(test(base64, decode, [encoded_binary()])).
decode_binary_to_string(_Config) ->
- comment(test(decode_to_string, encoded_binary())).
+ comment(test(base64, decode_to_string, [encoded_binary()])).
decode_list(_Config) ->
- comment(test(decode, encoded_list())).
+ comment(test(base64, decode, [encoded_list()])).
decode_list_to_string(_Config) ->
- comment(test(decode_to_string, encoded_list())).
+ comment(test(base64, decode_to_string, [encoded_list()])).
encode_binary(_Config) ->
- comment(test(encode, binary())).
+ comment(test(base64, encode, [binary()])).
encode_binary_to_string(_Config) ->
- comment(test(encode_to_string, binary())).
+ comment(test(base64, encode_to_string, [binary()])).
encode_list(_Config) ->
- comment(test(encode, list())).
+ comment(test(base64, encode, [list()])).
encode_list_to_string(_Config) ->
- comment(test(encode_to_string, list())).
+ comment(test(base64, encode_to_string, [list()])).
mime_binary_decode(_Config) ->
- comment(test(mime_decode, encoded_binary())).
+ comment(test(base64, mime_decode, [encoded_binary()])).
mime_binary_decode_to_string(_Config) ->
- comment(test(mime_decode_to_string, encoded_binary())).
+ comment(test(base64, mime_decode_to_string, [encoded_binary()])).
mime_list_decode(_Config) ->
- comment(test(mime_decode, encoded_list())).
+ comment(test(base64, mime_decode, [encoded_list()])).
mime_list_decode_to_string(_Config) ->
- comment(test(mime_decode_to_string, encoded_list())).
+ comment(test(base64, mime_decode_to_string, [encoded_list()])).
-define(SIZE, 10000).
-define(N, 1000).
@@ -209,15 +232,15 @@ binary() ->
list() ->
random_byte_list(?SIZE).
-test(Func, Data) ->
- F = fun() -> loop(?N, Func, Data) end,
+test(Mod, Fun, Args) ->
+ F = fun() -> loop(?N, Mod, Fun, Args) end,
{Time, ok} = timer:tc(fun() -> lspawn(F) end),
- report_base64(Time).
+ report_mfa(Time, Mod).
-loop(0, _F, _D) -> garbage_collect(), ok;
-loop(N, F, D) ->
- _ = base64:F(D),
- loop(N - 1, F, D).
+loop(0, _M, _F, _A) -> garbage_collect(), ok;
+loop(N, M, F, A) ->
+ _ = apply(M, F, A),
+ loop(N - 1, M, F, A).
lspawn(Fun) ->
{Pid, Ref} = spawn_monitor(fun() -> exit(Fun()) end),
@@ -225,10 +248,10 @@ lspawn(Fun) ->
{'DOWN', Ref, process, Pid, Rep} -> Rep
end.
-report_base64(Time) ->
+report_mfa(Time, Mod) ->
Tps = round((?N*1000000)/Time),
ct_event:notify(#event{name = benchmark_data,
- data = [{suite, "stdlib_base64"},
+ data = [{suite, "stdlib_" ++ atom_to_list(Mod)},
{value, Tps}]}),
Tps.
diff --git a/lib/stdlib/test/string_SUITE.erl b/lib/stdlib/test/string_SUITE.erl
index fdff2d24b8..251e09121c 100644
--- a/lib/stdlib/test/string_SUITE.erl
+++ b/lib/stdlib/test/string_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -409,8 +409,8 @@ uppercase(_) ->
?TEST("abc", [], "ABC"),
?TEST("ABC", [], "ABC"),
?TEST("abcdefghiljklmnopqrstvxyzåäö",[], "ABCDEFGHILJKLMNOPQRSTVXYZÅÄÖ"),
- ?TEST("åäö", [], "ÅÄÖ"),
- ?TEST("ÅÄÖ", [], "ÅÄÖ"),
+ ?TEST("åäö ", [], "ÅÄÖ "),
+ ?TEST("ÅÄÖ ", [], "ÅÄÖ "),
?TEST("Michał", [], "MICHAŁ"),
?TEST(["Mic",<<"hał"/utf8>>], [], "MICHAŁ"),
?TEST("ljLJ", [], "LJLJ"),
@@ -423,8 +423,8 @@ lowercase(_) ->
?TEST("123", [], "123"),
?TEST("abc", [], "abc"),
?TEST("ABC", [], "abc"),
- ?TEST("åäö", [], "åäö"),
- ?TEST("ÅÄÖ", [], "åäö"),
+ ?TEST("åäö ", [], "åäö "),
+ ?TEST("ÅÄÖ ", [], "åäö "),
?TEST("MICHAŁ", [], "michał"),
?TEST(["Mic",<<"HAŁ"/utf8>>], [], "michał"),
?TEST("ß SHARP S", [], "ß sharp s"),
@@ -449,8 +449,8 @@ casefold(_) ->
?TEST("123", [], "123"),
?TEST("abc", [], "abc"),
?TEST("ABC", [], "abc"),
- ?TEST("åäö", [], "åäö"),
- ?TEST("ÅÄÖ", [], "åäö"),
+ ?TEST("åäö ", [], "åäö "),
+ ?TEST("ÅÄÖ ", [], "åäö "),
?TEST("MICHAŁ", [], "michał"),
?TEST(["Mic",<<"HAŁ"/utf8>>], [], "michał"),
?TEST("ß SHARP S", [], "ss sharp s"),
@@ -810,6 +810,18 @@ do_measure(DataDir) ->
Do2(slice, repeat(fun() -> string:slice(S0, 20, 15) end), list),
Do2(slice, repeat(fun() -> string:slice(S0B, 20, 15) end), binary),
+ LCase = "areaa reare rerar earea reare reare",
+ LCaseB = unicode:characters_to_binary(LCase),
+ UCase = string:uppercase(LCase),
+ UCaseB = unicode:characters_to_binary(UCase),
+
+ Do2(to_upper_0, repeat(fun() -> string:to_upper(UCase) end), list),
+ Do2(uppercase_0, repeat(fun() -> string:uppercase(UCase) end), list),
+ Do2(uppercase_0, repeat(fun() -> string:uppercase(UCaseB) end), binary),
+ Do2(to_upper_a, repeat(fun() -> string:to_upper(LCase) end), list),
+ Do2(uppercase_a, repeat(fun() -> string:uppercase(LCase) end), list),
+ Do2(uppercase_a, repeat(fun() -> string:uppercase(LCaseB) end), binary),
+
io:format("--~n",[]),
NthTokens = {nth_lexemes, fun(Str) -> string:nth_lexeme(Str, 18000, [$\n,$\r]) end},
[Do(Name,Fun,Mode) || {Name,Fun} <- [NthTokens], Mode <- [list, binary]],
diff --git a/lib/stdlib/test/supervisor_1.erl b/lib/stdlib/test/supervisor_1.erl
index c3ccacc587..0d3dc67d3b 100644
--- a/lib/stdlib/test/supervisor_1.erl
+++ b/lib/stdlib/test/supervisor_1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl
index 761df8eb40..ed7dd04171 100644
--- a/lib/stdlib/test/supervisor_SUITE.erl
+++ b/lib/stdlib/test/supervisor_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/test/sys_SUITE.erl b/lib/stdlib/test/sys_SUITE.erl
index 439a23d82d..3278eb0eb0 100644
--- a/lib/stdlib/test/sys_SUITE.erl
+++ b/lib/stdlib/test/sys_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/test/unicode_util_SUITE.erl b/lib/stdlib/test/unicode_util_SUITE.erl
index 40b1c260a5..962b307b07 100644
--- a/lib/stdlib/test/unicode_util_SUITE.erl
+++ b/lib/stdlib/test/unicode_util_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/test/uri_string_SUITE.erl b/lib/stdlib/test/uri_string_SUITE.erl
index 92f8bb3292..ddaead9c7c 100644
--- a/lib/stdlib/test/uri_string_SUITE.erl
+++ b/lib/stdlib/test/uri_string_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,6 +23,12 @@
-export([all/0, suite/0,groups/0,
normalize/1, normalize_map/1, normalize_return_map/1, normalize_negative/1,
+ normalize_binary_pct_encoded_userinfo/1,
+ normalize_binary_pct_encoded_query/1,
+ normalize_binary_pct_encoded_fragment/1,
+ normalize_pct_encoded_userinfo/1,
+ normalize_pct_encoded_query/1,
+ normalize_pct_encoded_fragment/1,
parse_binary_fragment/1, parse_binary_host/1, parse_binary_host_ipv4/1,
parse_binary_host_ipv6/1,
parse_binary_path/1, parse_binary_pct_encoded_fragment/1, parse_binary_pct_encoded_query/1,
@@ -41,7 +47,8 @@
transcode_basic/1, transcode_options/1, transcode_mixed/1, transcode_negative/1,
compose_query/1, compose_query_latin1/1, compose_query_negative/1,
dissect_query/1, dissect_query_negative/1,
- interop_query_latin1/1, interop_query_utf8/1
+ interop_query_latin1/1, interop_query_utf8/1,
+ regression_parse/1, regression_recompose/1, regression_normalize/1
]).
@@ -71,6 +78,12 @@ all() ->
normalize_map,
normalize_return_map,
normalize_negative,
+ normalize_binary_pct_encoded_userinfo,
+ normalize_binary_pct_encoded_query,
+ normalize_binary_pct_encoded_fragment,
+ normalize_pct_encoded_userinfo,
+ normalize_pct_encoded_query,
+ normalize_pct_encoded_fragment,
parse_binary_scheme,
parse_binary_userinfo,
parse_binary_pct_encoded_userinfo,
@@ -120,7 +133,10 @@ all() ->
dissect_query,
dissect_query_negative,
interop_query_latin1,
- interop_query_utf8
+ interop_query_utf8,
+ regression_parse,
+ regression_recompose,
+ regression_normalize
].
groups() ->
@@ -338,20 +354,23 @@ parse_binary_userinfo(_Config) ->
uri_string:parse(<<"foo://user:password@localhost">>).
parse_binary_pct_encoded_userinfo(_Config) ->
- #{scheme := <<"user">>, path := <<"合@気道"/utf8>>} =
+ #{scheme := <<"user">>, path := <<"%E5%90%88@%E6%B0%97%E9%81%93">>} =
uri_string:parse(<<"user:%E5%90%88@%E6%B0%97%E9%81%93">>),
- #{path := <<"合気道@"/utf8>>} = uri_string:parse(<<"%E5%90%88%E6%B0%97%E9%81%93@">>),
- #{path := <<"/合気道@"/utf8>>} = uri_string:parse(<<"/%E5%90%88%E6%B0%97%E9%81%93@">>),
- #{path := <<"合@気道"/utf8>>} = uri_string:parse(<<"%E5%90%88@%E6%B0%97%E9%81%93">>),
- #{userinfo := <<"合"/utf8>>, host := <<"気道"/utf8>>} =
+ #{path := <<"%E5%90%88%E6%B0%97%E9%81%93@">>} =
+ uri_string:parse(<<"%E5%90%88%E6%B0%97%E9%81%93@">>),
+ #{path := <<"/%E5%90%88%E6%B0%97%E9%81%93@">>} =
+ uri_string:parse(<<"/%E5%90%88%E6%B0%97%E9%81%93@">>),
+ #{path := <<"%E5%90%88@%E6%B0%97%E9%81%93">>} =
+ uri_string:parse(<<"%E5%90%88@%E6%B0%97%E9%81%93">>),
+ #{userinfo := <<"%E5%90%88">>, host := <<"%E6%B0%97%E9%81%93">>} =
uri_string:parse(<<"//%E5%90%88@%E6%B0%97%E9%81%93">>),
- #{userinfo := <<"合:気"/utf8>>, host := <<"道"/utf8>>} =
+ #{userinfo := <<"%E5%90%88:%E6%B0%97">>, host := <<"%E9%81%93">>} =
uri_string:parse(<<"//%E5%90%88:%E6%B0%97@%E9%81%93">>),
- #{scheme := <<"foo">>, path := <<"/合気道@"/utf8>>} =
+ #{scheme := <<"foo">>, path := <<"/%E5%90%88%E6%B0%97%E9%81%93@">>} =
uri_string:parse(<<"foo:/%E5%90%88%E6%B0%97%E9%81%93@">>),
- #{scheme := <<"foo">>, userinfo := <<"合"/utf8>>, host := <<"気道"/utf8>>} =
+ #{scheme := <<"foo">>, userinfo := <<"%E5%90%88">>, host := <<"%E6%B0%97%E9%81%93">>} =
uri_string:parse(<<"foo://%E5%90%88@%E6%B0%97%E9%81%93">>),
- #{scheme := <<"foo">>, userinfo := <<"合:気"/utf8>>, host := <<"道"/utf8>>} =
+ #{scheme := <<"foo">>, userinfo := <<"%E5%90%88:%E6%B0%97">>, host := <<"%E9%81%93">>} =
uri_string:parse(<<"foo://%E5%90%88:%E6%B0%97@%E9%81%93">>),
{error,invalid_uri,"@"} = uri_string:parse(<<"//%E5%90%88@%E6%B0%97%E9%81%93@">>),
{error,invalid_uri,":"} = uri_string:parse(<<"foo://%E5%90%88@%E6%B0%97%E9%81%93@">>).
@@ -369,8 +388,8 @@ parse_binary_host_ipv4(_Config) ->
#{host := <<"127.0.0.1">>, query := <<"name=ferret">>} =
uri_string:parse(<<"//127.0.0.1?name=ferret">>),
#{host := <<"127.0.0.1">>, fragment := <<"nose">>} = uri_string:parse(<<"//127.0.0.1#nose">>),
- {error,invalid_uri,"x"} = uri_string:parse(<<"//127.0.0.x">>),
- {error,invalid_uri,"1227.0.0.1"} = uri_string:parse(<<"//1227.0.0.1">>).
+ #{host := <<"127.0.0.x">>,path := <<>>} = uri_string:parse(<<"//127.0.0.x">>),
+ #{host := <<"1227.0.0.1">>,path := <<>>} = uri_string:parse(<<"//1227.0.0.1">>).
parse_binary_host_ipv6(_Config) ->
#{host := <<"::127.0.0.1">>} = uri_string:parse(<<"//[::127.0.0.1]">>),
@@ -439,9 +458,9 @@ parse_binary_query(_Config) ->
parse_binary_pct_encoded_query(_Config) ->
#{scheme := <<"foo">>, host := <<"example.com">>, path := <<"/">>,
- query := <<"name=合気道"/utf8>>} =
+ query := <<"name=%E5%90%88%E6%B0%97%E9%81%93">>} =
uri_string:parse(<<"foo://example.com/?name=%E5%90%88%E6%B0%97%E9%81%93">>),
- #{host := <<"example.com">>, path := <<"/">>, query := <<"name=合気道"/utf8>>} =
+ #{host := <<"example.com">>, path := <<"/">>, query := <<"name=%E5%90%88%E6%B0%97%E9%81%93">>} =
uri_string:parse(<<"//example.com/?name=%E5%90%88%E6%B0%97%E9%81%93">>).
parse_binary_fragment(_Config) ->
@@ -472,9 +491,11 @@ parse_binary_fragment(_Config) ->
uri_string:parse(<<"//example.com/#nose">>).
parse_binary_pct_encoded_fragment(_Config) ->
- #{scheme := <<"foo">>, host := <<"example.com">>, fragment := <<"合気道"/utf8>>} =
+ #{scheme := <<"foo">>, host := <<"example.com">>,
+ fragment := <<"%E5%90%88%E6%B0%97%E9%81%93">>} =
uri_string:parse(<<"foo://example.com#%E5%90%88%E6%B0%97%E9%81%93">>),
- #{host := <<"example.com">>, path := <<"/">>, fragment := <<"合気道"/utf8>>} =
+ #{host := <<"example.com">>, path := <<"/">>,
+ fragment := <<"%E5%90%88%E6%B0%97%E9%81%93">>} =
uri_string:parse(<<"//example.com/#%E5%90%88%E6%B0%97%E9%81%93">>).
parse_scheme(_Config) ->
@@ -506,25 +527,27 @@ parse_userinfo(_Config) ->
uri_string:parse("foo://user:password@localhost").
parse_pct_encoded_userinfo(_Config) ->
- #{scheme := "user", path := "合@気道"} =
+ #{scheme := "user", path := "%E5%90%88@%E6%B0%97%E9%81%93"} =
uri_string:parse("user:%E5%90%88@%E6%B0%97%E9%81%93"),
- #{path := "合気道@"} = uri_string:parse("%E5%90%88%E6%B0%97%E9%81%93@"),
- #{path := "/合気道@"} = uri_string:parse("/%E5%90%88%E6%B0%97%E9%81%93@"),
- #{path := "合@気道"} = uri_string:parse("%E5%90%88@%E6%B0%97%E9%81%93"),
- #{userinfo := "合", host := "気道"} =
+ #{path := "%E5%90%88%E6%B0%97%E9%81%93@"} =
+ uri_string:parse("%E5%90%88%E6%B0%97%E9%81%93@"),
+ #{path := "/%E5%90%88%E6%B0%97%E9%81%93@"} =
+ uri_string:parse("/%E5%90%88%E6%B0%97%E9%81%93@"),
+ #{path := "%E5%90%88@%E6%B0%97%E9%81%93"} =
+ uri_string:parse("%E5%90%88@%E6%B0%97%E9%81%93"),
+ #{userinfo := "%E5%90%88", host := "%E6%B0%97%E9%81%93"} =
uri_string:parse("//%E5%90%88@%E6%B0%97%E9%81%93"),
- #{userinfo := "合:気", host := "道"} =
+ #{userinfo := "%E5%90%88:%E6%B0%97", host := "%E9%81%93"} =
uri_string:parse("//%E5%90%88:%E6%B0%97@%E9%81%93"),
- #{scheme := "foo", path := "/合気道@"} =
+ #{scheme := "foo", path := "/%E5%90%88%E6%B0%97%E9%81%93@"} =
uri_string:parse("foo:/%E5%90%88%E6%B0%97%E9%81%93@"),
- #{scheme := "foo", userinfo := "合", host := "気道"} =
+ #{scheme := "foo", userinfo := "%E5%90%88", host := "%E6%B0%97%E9%81%93"} =
uri_string:parse("foo://%E5%90%88@%E6%B0%97%E9%81%93"),
- #{scheme := "foo", userinfo := "合:気", host := "道"} =
+ #{scheme := "foo", userinfo := "%E5%90%88:%E6%B0%97", host := "%E9%81%93"} =
uri_string:parse("foo://%E5%90%88:%E6%B0%97@%E9%81%93"),
{error,invalid_uri,"@"} = uri_string:parse("//%E5%90%88@%E6%B0%97%E9%81%93@"),
{error,invalid_uri,":"} = uri_string:parse("foo://%E5%90%88@%E6%B0%97%E9%81%93@").
-
parse_host(_Config) ->
#{host := "hostname"} = uri_string:parse("//hostname"),
#{host := "hostname",scheme := "foo"} = uri_string:parse("foo://hostname"),
@@ -538,8 +561,8 @@ parse_host_ipv4(_Config) ->
#{host := "127.0.0.1", path := "/over/there"} = uri_string:parse("//127.0.0.1/over/there"),
#{host := "127.0.0.1", query := "name=ferret"} = uri_string:parse("//127.0.0.1?name=ferret"),
#{host := "127.0.0.1", fragment := "nose"} = uri_string:parse("//127.0.0.1#nose"),
- {error,invalid_uri,"x"} = uri_string:parse("//127.0.0.x"),
- {error,invalid_uri,"1227.0.0.1"} = uri_string:parse("//1227.0.0.1").
+ #{host := "127.0.0.x",path := []} = uri_string:parse("//127.0.0.x"),
+ #{host := "1227.0.0.1",path := []} = uri_string:parse("//1227.0.0.1").
parse_host_ipv6(_Config) ->
#{host := "::127.0.0.1"} = uri_string:parse("//[::127.0.0.1]"),
@@ -602,9 +625,9 @@ parse_query(_Config) ->
parse_pct_encoded_query(_Config) ->
#{scheme := "foo", host := "example.com", path := "/",
- query := "name=合気道"} =
+ query := "name=%E5%90%88%E6%B0%97%E9%81%93"} =
uri_string:parse("foo://example.com/?name=%E5%90%88%E6%B0%97%E9%81%93"),
- #{host := "example.com", path := "/", query := "name=合気道"} =
+ #{host := "example.com", path := "/", query := "name=%E5%90%88%E6%B0%97%E9%81%93"} =
uri_string:parse("//example.com/?name=%E5%90%88%E6%B0%97%E9%81%93").
parse_fragment(_Config) ->
@@ -635,9 +658,11 @@ parse_fragment(_Config) ->
uri_string:parse("//example.com/#nose").
parse_pct_encoded_fragment(_Config) ->
- #{scheme := "foo", host := "example.com", fragment := "合気道"} =
+ #{scheme := "foo", host := "example.com",
+ fragment := "%E5%90%88%E6%B0%97%E9%81%93"} =
uri_string:parse("foo://example.com#%E5%90%88%E6%B0%97%E9%81%93"),
- #{host := "example.com", path := "/", fragment := "合気道"} =
+ #{host := "example.com", path := "/",
+ fragment := "%E5%90%88%E6%B0%97%E9%81%93"} =
uri_string:parse("//example.com/#%E5%90%88%E6%B0%97%E9%81%93").
parse_list(_Config) ->
@@ -711,9 +736,7 @@ parse_negative(_Config) ->
{error,invalid_uri,":"} = uri_string:parse("foo://usär@host"),
{error,invalid_uri,"ö"} = uri_string:parse("//host/path?foö=bar"),
{error,invalid_uri,"ö"} = uri_string:parse("//host/path#foö"),
- {error,invalid_uri,"127.256.0.1"} = uri_string:parse("//127.256.0.1"),
{error,invalid_uri,":::127.0.0.1"} = uri_string:parse("//[:::127.0.0.1]"),
- {error,invalid_utf8,<<0,0,0,246>>} = uri_string:parse("//%00%00%00%F6"),
{error,invalid_uri,"A"} = uri_string:parse("//localhost:A8").
@@ -839,9 +862,11 @@ transcode_negative(_Config) ->
compose_query(_Config) ->
[] = uri_string:compose_query([]),
"foo=1&bar=2" = uri_string:compose_query([{<<"foo">>,"1"}, {"bar", "2"}]),
+ "foo=1&bar" = uri_string:compose_query([{<<"foo">>,"1"}, {"bar", true}]),
"foo=1&b%C3%A4r=2" = uri_string:compose_query([{"foo","1"}, {"bär", "2"}],[{encoding,utf8}]),
"foo=1&b%C3%A4r=2" = uri_string:compose_query([{"foo","1"}, {"bär", "2"}],[{encoding,unicode}]),
"foo=1&b%E4r=2" = uri_string:compose_query([{"foo","1"}, {"bär", "2"}],[{encoding,latin1}]),
+ "foo&b%E4r=2" = uri_string:compose_query([{"foo",true}, {"bär", "2"}],[{encoding,latin1}]),
"foo+bar=1&%E5%90%88=2" = uri_string:compose_query([{"foo bar","1"}, {"合", "2"}]),
"foo+bar=1&%26%2321512%3B=2" =
uri_string:compose_query([{"foo bar","1"}, {"合", "2"}],[{encoding,latin1}]),
@@ -883,11 +908,13 @@ dissect_query(_Config) ->
[{"föo bar","1"},{"ö","2"}] =
uri_string:dissect_query("föo+bar=1&%C3%B6=2"),
[{<<"föo bar"/utf8>>,<<"1">>},{<<"ö"/utf8>>,<<"2">>}] =
- uri_string:dissect_query(<<"föo+bar=1&%C3%B6=2"/utf8>>).
+ uri_string:dissect_query(<<"föo+bar=1&%C3%B6=2"/utf8>>),
+ [{"foo1",true},{"bar","2"}] =
+ uri_string:dissect_query("foo1&bar=2"),
+ [{<<"foo1">>,<<"1">>},{<<"bar">>,true}] =
+ uri_string:dissect_query(<<"foo1=1&bar">>).
dissect_query_negative(_Config) ->
- {error,missing_value,"&"} =
- uri_string:dissect_query("foo1&bar=2"),
{error,invalid_percent_encoding,"%XX%B6"} = uri_string:dissect_query("foo=%XX%B6&amp;bar=2"),
{error,invalid_input,[153]} =
uri_string:dissect_query("foo=%99%B6&amp;bar=2"),
@@ -913,7 +940,9 @@ normalize(_Config) ->
<<"sftp://localhost">> =
uri_string:normalize(<<"sftp://localhost:22">>),
<<"tftp://localhost">> =
- uri_string:normalize(<<"tftp://localhost:69">>).
+ uri_string:normalize(<<"tftp://localhost:69">>),
+ <<"/foo/%2F/bar">> =
+ uri_string:normalize(<<"/foo/%2f/%62ar">>).
normalize_map(_Config) ->
"/a/g" = uri_string:normalize(#{path => "/a/b/c/./../../g"}),
@@ -942,7 +971,9 @@ normalize_map(_Config) ->
host => <<"localhost">>}),
<<"tftp://localhost">> =
uri_string:normalize(#{scheme => <<"tftp">>,port => 69,path => <<>>,
- host => <<"localhost">>}).
+ host => <<"localhost">>}),
+ "/foo/%2F/bar" =
+ uri_string:normalize(#{path => "/foo/%2f/%62ar"}).
normalize_return_map(_Config) ->
#{scheme := "http",path := "/a/g",host := "localhost-örebro"} =
@@ -963,7 +994,82 @@ normalize_negative(_Config) ->
{error,invalid_uri,":"} =
uri_string:normalize("http://[192.168.0.1]", [return_map]),
{error,invalid_uri,":"} =
- uri_string:normalize(<<"http://[192.168.0.1]">>, [return_map]).
+ uri_string:normalize(<<"http://[192.168.0.1]">>, [return_map]),
+ {error,invalid_utf8,<<0,0,0,246>>} = uri_string:normalize("//%00%00%00%F6").
+
+normalize_binary_pct_encoded_userinfo(_Config) ->
+ #{scheme := <<"user">>, path := <<"合@気道"/utf8>>} =
+ uri_string:normalize(<<"user:%E5%90%88@%E6%B0%97%E9%81%93">>, [return_map]),
+ #{path := <<"合気道@"/utf8>>} =
+ uri_string:normalize(<<"%E5%90%88%E6%B0%97%E9%81%93@">>, [return_map]),
+ #{path := <<"/合気道@"/utf8>>} =
+ uri_string:normalize(<<"/%E5%90%88%E6%B0%97%E9%81%93@">>, [return_map]),
+ #{path := <<"合@気道"/utf8>>} =
+ uri_string:normalize(<<"%E5%90%88@%E6%B0%97%E9%81%93">>, [return_map]),
+ #{userinfo := <<"合"/utf8>>, host := <<"気道"/utf8>>} =
+ uri_string:normalize(<<"//%E5%90%88@%E6%B0%97%E9%81%93">>, [return_map]),
+ #{userinfo := <<"合:気"/utf8>>, host := <<"道"/utf8>>} =
+ uri_string:normalize(<<"//%E5%90%88:%E6%B0%97@%E9%81%93">>, [return_map]),
+ #{scheme := <<"foo">>, path := <<"/合気道@"/utf8>>} =
+ uri_string:normalize(<<"foo:/%E5%90%88%E6%B0%97%E9%81%93@">>, [return_map]),
+ #{scheme := <<"foo">>, userinfo := <<"合"/utf8>>, host := <<"気道"/utf8>>} =
+ uri_string:normalize(<<"foo://%E5%90%88@%E6%B0%97%E9%81%93">>, [return_map]),
+ #{scheme := <<"foo">>, userinfo := <<"合:気"/utf8>>, host := <<"道"/utf8>>} =
+ uri_string:normalize(<<"foo://%E5%90%88:%E6%B0%97@%E9%81%93">>, [return_map]),
+ {error,invalid_uri,"@"} =
+ uri_string:normalize(<<"//%E5%90%88@%E6%B0%97%E9%81%93@">>, [return_map]),
+ {error,invalid_uri,":"} =
+ uri_string:normalize(<<"foo://%E5%90%88@%E6%B0%97%E9%81%93@">>, [return_map]).
+
+normalize_binary_pct_encoded_query(_Config) ->
+ #{scheme := <<"foo">>, host := <<"example.com">>, path := <<"/">>,
+ query := <<"name=合気道"/utf8>>} =
+ uri_string:normalize(<<"foo://example.com/?name=%E5%90%88%E6%B0%97%E9%81%93">>, [return_map]),
+ #{host := <<"example.com">>, path := <<"/">>, query := <<"name=合気道"/utf8>>} =
+ uri_string:normalize(<<"//example.com/?name=%E5%90%88%E6%B0%97%E9%81%93">>, [return_map]).
+
+normalize_binary_pct_encoded_fragment(_Config) ->
+ #{scheme := <<"foo">>, host := <<"example.com">>, fragment := <<"合気道"/utf8>>} =
+ uri_string:normalize(<<"foo://example.com#%E5%90%88%E6%B0%97%E9%81%93">>, [return_map]),
+ #{host := <<"example.com">>, path := <<"/">>, fragment := <<"合気道"/utf8>>} =
+ uri_string:normalize(<<"//example.com/#%E5%90%88%E6%B0%97%E9%81%93">>, [return_map]).
+
+normalize_pct_encoded_userinfo(_Config) ->
+ #{scheme := "user", path := "合@気道"} =
+ uri_string:normalize("user:%E5%90%88@%E6%B0%97%E9%81%93", [return_map]),
+ #{path := "合気道@"} =
+ uri_string:normalize("%E5%90%88%E6%B0%97%E9%81%93@", [return_map]),
+ #{path := "/合気道@"} =
+ uri_string:normalize("/%E5%90%88%E6%B0%97%E9%81%93@", [return_map]),
+ #{path := "合@気道"} =
+ uri_string:normalize("%E5%90%88@%E6%B0%97%E9%81%93", [return_map]),
+ #{userinfo := "合", host := "気道"} =
+ uri_string:normalize("//%E5%90%88@%E6%B0%97%E9%81%93", [return_map]),
+ #{userinfo := "合:気", host := "道"} =
+ uri_string:normalize("//%E5%90%88:%E6%B0%97@%E9%81%93", [return_map]),
+ #{scheme := "foo", path := "/合気道@"} =
+ uri_string:normalize("foo:/%E5%90%88%E6%B0%97%E9%81%93@", [return_map]),
+ #{scheme := "foo", userinfo := "合", host := "気道"} =
+ uri_string:normalize("foo://%E5%90%88@%E6%B0%97%E9%81%93", [return_map]),
+ #{scheme := "foo", userinfo := "合:気", host := "道"} =
+ uri_string:normalize("foo://%E5%90%88:%E6%B0%97@%E9%81%93", [return_map]),
+ {error,invalid_uri,"@"} =
+ uri_string:normalize("//%E5%90%88@%E6%B0%97%E9%81%93@", [return_map]),
+ {error,invalid_uri,":"} =
+ uri_string:normalize("foo://%E5%90%88@%E6%B0%97%E9%81%93@", [return_map]).
+
+normalize_pct_encoded_query(_Config) ->
+ #{scheme := "foo", host := "example.com", path := "/",
+ query := "name=合気道"} =
+ uri_string:normalize("foo://example.com/?name=%E5%90%88%E6%B0%97%E9%81%93", [return_map]),
+ #{host := "example.com", path := "/", query := "name=合気道"} =
+ uri_string:normalize("//example.com/?name=%E5%90%88%E6%B0%97%E9%81%93", [return_map]).
+
+normalize_pct_encoded_fragment(_Config) ->
+ #{scheme := "foo", host := "example.com", fragment := "合気道"} =
+ uri_string:normalize("foo://example.com#%E5%90%88%E6%B0%97%E9%81%93", [return_map]),
+ #{host := "example.com", path := "/", fragment := "合気道"} =
+ uri_string:normalize("//example.com/#%E5%90%88%E6%B0%97%E9%81%93", [return_map]).
interop_query_utf8(_Config) ->
Q = uri_string:compose_query([{"foo bar","1"}, {"合", "2"}]),
@@ -977,3 +1083,86 @@ interop_query_latin1(_Config) ->
Uri1 = uri_string:transcode(Uri, [{in_encoding, latin1}]),
#{query := Q1} = uri_string:parse(Uri1),
[{"foo bar","1"}, {"合", "2"}] = uri_string:dissect_query(Q1).
+
+regression_parse(_Config) ->
+ #{host := "Bar",path := [],scheme := "FOo"} =
+ uri_string:parse("FOo://Bar"),
+ #{host := "bar",path := [],scheme := "foo"} =
+ uri_string:parse("foo://bar"),
+ #{host := "A%2f",path := "/%62ar",scheme := "foo"} =
+ uri_string:parse("foo://A%2f/%62ar"),
+ #{host := "a%2F",path := "/bar",scheme := "foo"} =
+ uri_string:parse("foo://a%2F/bar"),
+ #{host := "%C3%B6",path := [],scheme := "FOo"} =
+ uri_string:parse("FOo://%C3%B6").
+
+regression_recompose(_Config) ->
+ "FOo://Bar" =
+ uri_string:recompose(#{host => "Bar",path => [],scheme => "FOo"}),
+ "foo://bar" =
+ uri_string:recompose(#{host => "bar",path => [],scheme => "foo"}),
+ "foo://A%2f/%62ar" =
+ uri_string:recompose(#{host => "A%2f",path => "/%62ar",scheme => "foo"}),
+ "foo://a%2F/bar" =
+ uri_string:recompose(#{host => "a%2F",path => "/bar",scheme => "foo"}),
+ "FOo://%C3%B6" =
+ uri_string:recompose(#{host => "%C3%B6",path => [],scheme => "FOo"}),
+ "FOo://%C3%B6" =
+ uri_string:recompose(#{host => "ö",path => [],scheme => "FOo"}).
+
+regression_normalize(_Config) ->
+ "foo://bar" =
+ uri_string:normalize("FOo://Bar"),
+ #{host := "bar",path := [],scheme := "foo"} =
+ uri_string:normalize("FOo://Bar", [return_map]),
+
+ "foo://bar" =
+ uri_string:normalize("foo://bar"),
+ #{host := "bar",path := [],scheme := "foo"} =
+ uri_string:normalize("foo://bar", [return_map]),
+
+ "foo://a%2F/bar" =
+ uri_string:normalize("foo://A%2f/%62ar"),
+ #{host := "a%2F",path := "/bar",scheme := "foo"} =
+ uri_string:normalize("foo://A%2f/%62ar", [return_map]),
+
+ "foo://a%2F/bar" =
+ uri_string:normalize("foo://a%2F/bar"),
+ #{host := "a%2F",path := "/bar",scheme := "foo"} =
+ uri_string:normalize("foo://a%2F/bar", [return_map]),
+
+ "foo://%C3%B6" =
+ uri_string:normalize("FOo://%C3%B6"),
+ #{host := "ö",path := [],scheme := "foo"} =
+ uri_string:normalize("FOo://%C3%B6", [return_map]),
+
+
+ "foo://bar" =
+ uri_string:normalize(#{host => "Bar",path => [],scheme => "FOo"}),
+ #{host := "bar",path := [],scheme := "foo"} =
+ uri_string:normalize(#{host => "Bar",path => [],scheme => "FOo"}, [return_map]),
+
+ "foo://bar" =
+ uri_string:normalize(#{host => "bar",path => [],scheme => "foo"}),
+ #{host := "bar",path := [],scheme := "foo"} =
+ uri_string:normalize(#{host => "bar",path => [],scheme => "foo"}, [return_map]),
+
+ "foo://a%2F/bar" =
+ uri_string:normalize(#{host => "A%2f",path => "/%62ar",scheme => "foo"}),
+ #{host := "a%2F",path := "/bar",scheme := "foo"} =
+ uri_string:normalize(#{host => "A%2f",path => "/%62ar",scheme => "foo"}, [return_map]),
+
+ "foo://a%2F/bar" =
+ uri_string:normalize(#{host => "a%2F",path => "/bar",scheme => "foo"}),
+ #{host := "a%2F",path := "/bar",scheme := "foo"} =
+ uri_string:normalize(#{host => "a%2F",path => "/bar",scheme => "foo"}, [return_map]),
+
+ "foo://%C3%B6" =
+ uri_string:normalize(#{host => "%C3%B6",path => [],scheme => "FOo"}),
+ #{host := "ö",path := [],scheme := "foo"} =
+ uri_string:normalize(#{host => "%C3%B6",path => [],scheme => "FOo"}, [return_map]),
+
+ "foo://%C3%B6" =
+ uri_string:normalize(#{host => "ö",path => [],scheme => "FOo"}),
+ #{host := "ö",path := [],scheme := "foo"} =
+ uri_string:normalize(#{host => "ö",path => [],scheme => "FOo"}, [return_map]).
diff --git a/lib/stdlib/test/uri_string_property_test_SUITE.erl b/lib/stdlib/test/uri_string_property_test_SUITE.erl
index ae2c61c7aa..f1d27924db 100644
--- a/lib/stdlib/test/uri_string_property_test_SUITE.erl
+++ b/lib/stdlib/test/uri_string_property_test_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@
-include_lib("common_test/include/ct.hrl").
-compile(export_all).
-all() -> [recompose].
+all() -> [recompose, normalize].
init_per_suite(Config) ->
ct_property_test:init_per_suite(Config).
@@ -37,3 +37,8 @@ recompose(Config) ->
ct_property_test:quickcheck(
uri_string_recompose:prop_recompose(),
Config).
+
+normalize(Config) ->
+ ct_property_test:quickcheck(
+ uri_string_recompose:prop_normalize(),
+ Config).
diff --git a/lib/stdlib/test/zip_SUITE.erl b/lib/stdlib/test/zip_SUITE.erl
index e5ba629c55..081bffa7cb 100644
--- a/lib/stdlib/test/zip_SUITE.erl
+++ b/lib/stdlib/test/zip_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index 09a4d6fb50..1d833430f1 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 3.4.5
+STDLIB_VSN = 3.5.1
diff --git a/lib/syntax_tools/doc/src/Makefile b/lib/syntax_tools/doc/src/Makefile
index a346b9a0bd..d953287bad 100644
--- a/lib/syntax_tools/doc/src/Makefile
+++ b/lib/syntax_tools/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2006-2017. All Rights Reserved.
+# Copyright Ericsson AB 2006-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -125,6 +125,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(XML_REF3_FILES) $(XML_CHAPTER_FILES) *.html
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
diff --git a/lib/syntax_tools/doc/src/notes.xml b/lib/syntax_tools/doc/src/notes.xml
index bd2bcde2c2..44944e57c3 100644
--- a/lib/syntax_tools/doc/src/notes.xml
+++ b/lib/syntax_tools/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2007</year><year>2017</year>
+ <year>2007</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,31 @@
<p>This document describes the changes made to the Syntax_Tools
application.</p>
+<section><title>Syntax_Tools 2.1.5</title>
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Update to use the new string api instead of the old.</p>
+ <p>
+ Own Id: OTP-15036</p>
+ </item>
+ </list>
+ </section>
+</section>
+
+<section><title>Syntax_Tools 2.1.4.1</title>
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug regarding reverting map types. </p>
+ <p>
+ Own Id: OTP-15098 Aux Id: ERIERL-177 </p>
+ </item>
+ </list>
+ </section>
+</section>
+
<section><title>Syntax_Tools 2.1.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -83,6 +108,20 @@
</section>
+<section><title>Syntax_Tools 2.1.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug regarding reverting map types. </p>
+ <p>
+ Own Id: OTP-15098 Aux Id: ERIERL-177 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Syntax_Tools 2.1.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/syntax_tools/src/epp_dodger.erl b/lib/syntax_tools/src/epp_dodger.erl
index 0a12e8fd8b..7e741cc649 100644
--- a/lib/syntax_tools/src/epp_dodger.erl
+++ b/lib/syntax_tools/src/epp_dodger.erl
@@ -502,6 +502,10 @@ quickscan_form([{'-', _L}, {atom, La, ifdef} | _Ts]) ->
kill_form(La);
quickscan_form([{'-', _L}, {atom, La, ifndef} | _Ts]) ->
kill_form(La);
+quickscan_form([{'-', _L}, {'if', La} | _Ts]) ->
+ kill_form(La);
+quickscan_form([{'-', _L}, {atom, La, elif} | _Ts]) ->
+ kill_form(La);
quickscan_form([{'-', _L}, {atom, La, else} | _Ts]) ->
kill_form(La);
quickscan_form([{'-', _L}, {atom, La, endif} | _Ts]) ->
@@ -615,8 +619,13 @@ filter_form(T) ->
%% ---------------------------------------------------------------------
%% Normal parsing - try to preserve all information
-normal_parser(Ts, Opt) ->
- rewrite_form(parse_tokens(scan_form(Ts, Opt))).
+normal_parser(Ts0, Opt) ->
+ case scan_form(Ts0, Opt) of
+ Ts when is_list(Ts) ->
+ rewrite_form(parse_tokens(Ts));
+ Node ->
+ Node
+ end.
scan_form([{'-', _L}, {atom, La, define} | Ts], Opt) ->
[{atom, La, ?pp_form}, {'(', La}, {')', La}, {'->', La},
@@ -636,12 +645,26 @@ scan_form([{'-', _L}, {atom, La, ifdef} | Ts], Opt) ->
scan_form([{'-', _L}, {atom, La, ifndef} | Ts], Opt) ->
[{atom, La, ?pp_form}, {'(', La}, {')', La}, {'->', La},
{atom, La, ifndef} | scan_macros(Ts, Opt)];
+scan_form([{'-', _L}, {'if', La} | Ts], Opt) ->
+ [{atom, La, ?pp_form}, {'(', La}, {')', La}, {'->', La},
+ {atom, La, 'if'} | scan_macros(Ts, Opt)];
+scan_form([{'-', _L}, {atom, La, elif} | Ts], Opt) ->
+ [{atom, La, ?pp_form}, {'(', La}, {')', La}, {'->', La},
+ {atom, La, 'elif'} | scan_macros(Ts, Opt)];
scan_form([{'-', _L}, {atom, La, else} | Ts], Opt) ->
[{atom, La, ?pp_form}, {'(', La}, {')', La}, {'->', La},
{atom, La, else} | scan_macros(Ts, Opt)];
scan_form([{'-', _L}, {atom, La, endif} | Ts], Opt) ->
[{atom, La, ?pp_form}, {'(', La}, {')', La}, {'->', La},
{atom, La, endif} | scan_macros(Ts, Opt)];
+scan_form([{'-', _L}, {atom, La, error} | Ts], _Opt) ->
+ Desc = build_info_string("-error", Ts),
+ ErrorInfo = {La, ?MODULE, {error, Desc}},
+ erl_syntax:error_marker(ErrorInfo);
+scan_form([{'-', _L}, {atom, La, warning} | Ts], _Opt) ->
+ Desc = build_info_string("-warning", Ts),
+ ErrorInfo = {La, ?MODULE, {warning, Desc}},
+ erl_syntax:error_marker(ErrorInfo);
scan_form([{'-', L}, {'?', L1}, {Type, _, _}=N | [{'(', _} | _]=Ts], Opt)
when Type =:= atom; Type =:= var ->
%% minus, macro and open parenthesis at start of form - assume that
@@ -657,6 +680,11 @@ scan_form([{'?', L}, {Type, _, _}=N | [{'(', _} | _]=Ts], Opt)
scan_form(Ts, Opt) ->
scan_macros(Ts, Opt).
+build_info_string(Prefix, Ts0) ->
+ Ts = lists:droplast(Ts0),
+ String = lists:droplast(tokens_to_string(Ts)),
+ Prefix ++ " " ++ String ++ ".".
+
scan_macros(Ts, Opt) ->
scan_macros(Ts, [], Opt).
@@ -865,6 +893,10 @@ tokens_to_string([]) ->
format_error(macro_args) ->
errormsg("macro call missing end parenthesis");
+format_error({error, Error}) ->
+ Error;
+format_error({warning, Error}) ->
+ Error;
format_error({unknown, Reason}) ->
errormsg(io_lib:format("unknown error: ~tP", [Reason, 15])).
diff --git a/lib/syntax_tools/src/erl_prettypr.erl b/lib/syntax_tools/src/erl_prettypr.erl
index 60a15c8e3f..6906ef1553 100644
--- a/lib/syntax_tools/src/erl_prettypr.erl
+++ b/lib/syntax_tools/src/erl_prettypr.erl
@@ -675,7 +675,12 @@ lay_2(Node, Ctxt) ->
%% attribute name, without following parentheses.
Ctxt1 = reset_prec(Ctxt),
Args = erl_syntax:attribute_arguments(Node),
- N = erl_syntax:attribute_name(Node),
+ N = case erl_syntax:attribute_name(Node) of
+ {atom, _, 'if'} ->
+ erl_syntax:variable('if');
+ N0 ->
+ N0
+ end,
D = case attribute_type(Node) of
spec ->
[SpecTuple] = Args,
diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl
index b816c0699c..758aff32fd 100644
--- a/lib/syntax_tools/src/erl_syntax.erl
+++ b/lib/syntax_tools/src/erl_syntax.erl
@@ -5328,7 +5328,7 @@ revert_map_type_assoc(Node) ->
Pos = get_pos(Node),
Name = map_type_assoc_name(Node),
Value = map_type_assoc_value(Node),
- {type, Pos, map_type_assoc, [Name, Value]}.
+ {type, Pos, map_field_assoc, [Name, Value]}.
%% =====================================================================
@@ -5386,7 +5386,7 @@ revert_map_type_exact(Node) ->
Pos = get_pos(Node),
Name = map_type_exact_name(Node),
Value = map_type_exact_value(Node),
- {type, Pos, map_type_exact, [Name, Value]}.
+ {type, Pos, map_field_exact, [Name, Value]}.
%% =====================================================================
@@ -7223,7 +7223,7 @@ macro_arguments(Node) ->
%% @doc Returns the syntax tree corresponding to an Erlang term.
%% `Term' must be a literal term, i.e., one that can be
%% represented as a source code literal. Thus, it may not contain a
-%% process identifier, port, reference, binary or function value as a
+%% process identifier, port, reference or function value as a
%% subterm. The function recognises printable strings, in order to get a
%% compact and readable representation. Evaluation fails with reason
%% `badarg' if `Term' is not a literal term.
@@ -7257,6 +7257,13 @@ abstract(T) when is_map(T) ->
|| {Key,Value} <- maps:to_list(T)]);
abstract(T) when is_binary(T) ->
binary([binary_field(integer(B)) || B <- binary_to_list(T)]);
+abstract(T) when is_bitstring(T) ->
+ S = bit_size(T),
+ ByteS = S div 8,
+ BitS = S rem 8,
+ <<Bin:ByteS/binary, I:BitS>> = T,
+ binary([binary_field(integer(B)) || B <- binary_to_list(Bin)]
+ ++ [binary_field(integer(I), integer(BitS), [])]);
abstract(T) ->
erlang:error({badarg, T}).
@@ -7332,15 +7339,20 @@ concrete(Node) ->
Node0 -> maps:merge(concrete(Node0),M0)
end;
binary ->
- Fs = [revert_binary_field(
- binary_field(binary_field_body(F),
- case binary_field_size(F) of
- none -> none;
- S ->
- revert(S)
- end,
- binary_field_types(F)))
- || F <- binary_fields(Node)],
+ Fs = [begin
+ B = binary_field_body(F),
+ {Body, Size} =
+ case type(B) of
+ size_qualifier ->
+ {size_qualifier_body(B),
+ size_qualifier_argument(B)};
+ _ ->
+ {B, none}
+ end,
+ revert_binary_field(
+ binary_field(Body, Size, binary_field_types(F)))
+ end
+ || F <- binary_fields(Node)],
{value, B, _} =
eval_bits:expr_grp(Fs, [],
fun(F, _) ->
@@ -7413,7 +7425,14 @@ is_literal(T) ->
is_literal_binary_field(F) ->
case binary_field_types(F) of
- [] -> is_literal(binary_field_body(F));
+ [] -> B = binary_field_body(F),
+ case type(B) of
+ size_qualifier ->
+ is_literal(size_qualifier_body(B)) andalso
+ is_literal(size_qualifier_argument(B));
+ _ ->
+ is_literal(B)
+ end;
_ -> false
end.
diff --git a/lib/syntax_tools/src/erl_syntax_lib.erl b/lib/syntax_tools/src/erl_syntax_lib.erl
index c7f477c4d2..352165893f 100644
--- a/lib/syntax_tools/src/erl_syntax_lib.erl
+++ b/lib/syntax_tools/src/erl_syntax_lib.erl
@@ -1317,6 +1317,8 @@ analyze_attribute(Node) ->
include_lib -> preprocessor;
ifdef -> preprocessor;
ifndef -> preprocessor;
+ 'if' -> preprocessor;
+ elif -> preprocessor;
else -> preprocessor;
endif -> preprocessor;
A ->
@@ -1979,7 +1981,7 @@ analyze_application(Node) ->
%%
%% @see analyze_type_name/1
--type typeName() :: atom() | {module(), atom(), arity()} | {atom(), arity()}.
+-type typeName() :: atom() | {module(), {atom(), arity()}} | {atom(), arity()}.
-spec analyze_type_application(erl_syntax:syntaxTree()) -> typeName().
diff --git a/lib/syntax_tools/src/igor.erl b/lib/syntax_tools/src/igor.erl
index 16e3511734..b712b77e9f 100644
--- a/lib/syntax_tools/src/igor.erl
+++ b/lib/syntax_tools/src/igor.erl
@@ -660,7 +660,7 @@ merge_files1(Files, Opts) ->
%% transitions), code replacement is expected to be detected. Then, if
%% we in the merged code do not check at these points if the
%% <em>target</em> module (the result of the merge) has been replaced,
-%% we can not be sure in general that we will be able to do code
+%% we cannot be sure in general that we will be able to do code
%% replacement of the merged state machine - it could run forever
%% without detecting the code change. Therefore, all such calls must
%% remain remote-calls (detecting code changes), but may call the target
diff --git a/lib/syntax_tools/test/syntax_tools_SUITE.erl b/lib/syntax_tools/test/syntax_tools_SUITE.erl
index ae2c67c03e..4cddf8f0c3 100644
--- a/lib/syntax_tools/test/syntax_tools_SUITE.erl
+++ b/lib/syntax_tools/test/syntax_tools_SUITE.erl
@@ -24,13 +24,14 @@
%% Test cases
-export([app_test/1,appup_test/1,smoke_test/1,revert/1,revert_map/1,
+ revert_map_type/1,
t_abstract_type/1,t_erl_parse_type/1,t_epp_dodger/1,
t_comment_scan/1,t_igor/1,t_erl_tidy/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [app_test,appup_test,smoke_test,revert,revert_map,
+ [app_test,appup_test,smoke_test,revert,revert_map,revert_map_type,
t_abstract_type,t_erl_parse_type,t_epp_dodger,
t_comment_scan,t_igor,t_erl_tidy].
@@ -121,7 +122,26 @@ revert_map(Config) when is_list(Config) ->
{map_field_assoc,{atom,17,name},{var,18,'Value'}}}]),
?t:timetrap_cancel(Dog).
-
+%% Testing bug fix for reverting map_field_assoc in types
+revert_map_type(Config) when is_list(Config) ->
+ Dog = ?t:timetrap(?t:minutes(1)),
+ Form1 = {attribute,4,record,
+ {state,
+ [{typed_record_field,
+ {record_field,5,{atom,5,x}},
+ {type,5,map,
+ [{type,5,map_field_exact,[{atom,5,y},{atom,5,z}]}]}}]}},
+ Mapped1 = erl_syntax_lib:map(fun(X) -> X end, Form1),
+ Form1 = erl_syntax:revert(Mapped1),
+ Form2 = {attribute,4,record,
+ {state,
+ [{typed_record_field,
+ {record_field,5,{atom,5,x}},
+ {type,5,map,
+ [{type,5,map_field_assoc,[{atom,5,y},{atom,5,z}]}]}}]}},
+ Mapped2 = erl_syntax_lib:map(fun(X) -> X end, Form2),
+ Form2 = erl_syntax:revert(Mapped2),
+ ?t:timetrap_cancel(Dog).
%% api tests
@@ -137,6 +157,7 @@ t_abstract_type(Config) when is_list(Config) ->
{[$a,$b,$c],string},
{"hello world",string},
{<<1,2,3>>,binary},
+ {<<1,2,3:4>>,binary},
{#{a=>1,"b"=>2},map_expr},
{#{#{i=>1}=>1,"b"=>#{v=>2}},map_expr},
{{a,b,c},tuple}]),
diff --git a/lib/syntax_tools/vsn.mk b/lib/syntax_tools/vsn.mk
index 8d37c40742..4d13267f16 100644
--- a/lib/syntax_tools/vsn.mk
+++ b/lib/syntax_tools/vsn.mk
@@ -1 +1 @@
-SYNTAX_TOOLS_VSN = 2.1.4
+SYNTAX_TOOLS_VSN = 2.1.5
diff --git a/lib/tftp/Makefile b/lib/tftp/Makefile
index 5c3ed52b28..a4559fbc2e 100644
--- a/lib/tftp/Makefile
+++ b/lib/tftp/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2016. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/tftp/doc/src/Makefile b/lib/tftp/doc/src/Makefile
index a2fdcf6325..5d76799e41 100644
--- a/lib/tftp/doc/src/Makefile
+++ b/lib/tftp/doc/src/Makefile
@@ -103,6 +103,7 @@ pdf: $(TOP_PDF_FILE)
html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs: clean_html clean_man clean_pdf
+ rm -rf $(XMLDIR)
rm -f errs core *~
man: $(MAN3_FILES)
diff --git a/lib/tftp/doc/src/tftp.xml b/lib/tftp/doc/src/tftp.xml
index 481e5446ad..4ed54bc462 100644
--- a/lib/tftp/doc/src/tftp.xml
+++ b/lib/tftp/doc/src/tftp.xml
@@ -150,7 +150,7 @@
<tag><c>{logger, Module}</c></tag>
<item>
- <p><c>Module = module()()</c></p>
+ <p><c>Module = module()</c></p>
<p>Callback module for customized logging of errors, warnings, and
info messages. The callback module must implement the
@@ -220,7 +220,7 @@
<name>info(daemons) -> [{Pid, Options}]</name>
<fsummary>Returns information about all daemons.</fsummary>
<type>
- <v>Pid = [pid()()]</v>
+ <v>Pid = [pid()]</v>
<v>Options = [option()]</v>
<v>Reason = term()</v>
</type>
@@ -233,7 +233,7 @@
<name>info(servers) -> [{Pid, Options}]</name>
<fsummary>Returns information about all servers.</fsummary>
<type>
- <v>Pid = [pid()()]</v>
+ <v>Pid = [pid()]</v>
<v>Options = [option()]</v>
<v>Reason = term()</v>
</type>
diff --git a/lib/tftp/src/Makefile b/lib/tftp/src/Makefile
index ed1551ba04..602ae845a4 100644
--- a/lib/tftp/src/Makefile
+++ b/lib/tftp/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2005-2016. All Rights Reserved.
+# Copyright Ericsson AB 2005-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/tftp/src/tftp.erl b/lib/tftp/src/tftp.erl
index 27ed13694b..31e4c651e8 100644
--- a/lib/tftp/src/tftp.erl
+++ b/lib/tftp/src/tftp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/tftp/src/tftp.hrl b/lib/tftp/src/tftp.hrl
index 25543e0b9e..a26aeee389 100644
--- a/lib/tftp/src/tftp.hrl
+++ b/lib/tftp/src/tftp.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/tftp/src/tftp_binary.erl b/lib/tftp/src/tftp_binary.erl
index 09adcfc41f..3438ba235b 100644
--- a/lib/tftp/src/tftp_binary.erl
+++ b/lib/tftp/src/tftp_binary.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/tftp/src/tftp_engine.erl b/lib/tftp/src/tftp_engine.erl
index f14354ad6a..78a105bcc8 100644
--- a/lib/tftp/src/tftp_engine.erl
+++ b/lib/tftp/src/tftp_engine.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/tftp/src/tftp_file.erl b/lib/tftp/src/tftp_file.erl
index 43b588f71a..5922fc9418 100644
--- a/lib/tftp/src/tftp_file.erl
+++ b/lib/tftp/src/tftp_file.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/tftp/src/tftp_lib.erl b/lib/tftp/src/tftp_lib.erl
index 454754f0a3..407a273f58 100644
--- a/lib/tftp/src/tftp_lib.erl
+++ b/lib/tftp/src/tftp_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/tftp/src/tftp_logger.erl b/lib/tftp/src/tftp_logger.erl
index a869958484..548ed509dc 100644
--- a/lib/tftp/src/tftp_logger.erl
+++ b/lib/tftp/src/tftp_logger.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/tftp/src/tftp_sup.erl b/lib/tftp/src/tftp_sup.erl
index 0475e53e42..13b753612b 100644
--- a/lib/tftp/src/tftp_sup.erl
+++ b/lib/tftp/src/tftp_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/tftp/test/tftp_SUITE.erl b/lib/tftp/test/tftp_SUITE.erl
index fd1d209c25..a0f6cb1ca4 100644
--- a/lib/tftp/test/tftp_SUITE.erl
+++ b/lib/tftp/test/tftp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/tftp/test/tftp_test_lib.erl b/lib/tftp/test/tftp_test_lib.erl
index 45386389cb..04534228c2 100644
--- a/lib/tftp/test/tftp_test_lib.erl
+++ b/lib/tftp/test/tftp_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/tftp/test/tftp_test_lib.hrl b/lib/tftp/test/tftp_test_lib.hrl
index e7a5a37d2c..eb8ed77fc1 100644
--- a/lib/tftp/test/tftp_test_lib.hrl
+++ b/lib/tftp/test/tftp_test_lib.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/tools/doc/src/Makefile b/lib/tools/doc/src/Makefile
index 4b663106a0..5ff4fe3113 100644
--- a/lib/tools/doc/src/Makefile
+++ b/lib/tools/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2017. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -120,6 +120,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f $(SPECDIR)/*
diff --git a/lib/tools/doc/src/cover.xml b/lib/tools/doc/src/cover.xml
index 15cd784253..6c6b20aad8 100644
--- a/lib/tools/doc/src/cover.xml
+++ b/lib/tools/doc/src/cover.xml
@@ -234,7 +234,7 @@
<c>{already_cover_compiled,no_beam_found,Module}</c> is
returned.</p>
<p><c>{error,BeamFile}</c> is returned if the compiled code
- can not be loaded on the node.</p>
+ cannot be loaded on the node.</p>
<p>If a list of <c>ModFiles</c> is given as input, a list
of <c>Result</c> will be returned. The order of the returned
list is undefined.</p>
@@ -470,7 +470,7 @@
<p>Exports the current coverage data for <c>Module</c> to the
file <c>ExportFile</c>. It is recommended to name the
<c>ExportFile</c> with the extension <c>.coverdata</c>, since
- other filenames can not be read by the web based interface to
+ other filenames cannot be read by the web based interface to
cover.</p>
<p>If <c>Module</c> is not given, data for all Cover compiled
or earlier imported modules is exported.</p>
@@ -496,7 +496,7 @@
<p>Coverage data from several export files can be imported
into one system. The coverage data is then added up when
analysing.</p>
- <p>Coverage data for a module can not be imported from the
+ <p>Coverage data for a module cannot be imported from the
same file twice unless the module is first reset or
compiled. The check is based on the filename, so you can
easily fool the system by renaming your export file.</p>
diff --git a/lib/tools/doc/src/fprof.xml b/lib/tools/doc/src/fprof.xml
index 4c9e48045e..1fd828d127 100644
--- a/lib/tools/doc/src/fprof.xml
+++ b/lib/tools/doc/src/fprof.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2001</year><year>2016</year>
+ <year>2001</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -328,10 +328,16 @@
purposes. This option is only
allowed with the <c>start</c> option.</item>
<tag><c>cpu_time</c>| <c>{cpu_time, bool()}</c></tag>
- <item>The options <c>cpu_time</c> or <c>{cpu_time, true></c>
+ <item>The options <c>cpu_time</c> or <c>{cpu_time, true}</c>
makes the timestamps in the trace be in CPU time instead
of wallclock time which is the default. This option is
- only allowed with the <c>start</c> option.</item>
+ only allowed with the <c>start</c> option.
+ <warning><p>Getting correct values out of cpu_time can be difficult.
+ The best way to get correct values is to run using a single
+ scheduler and bind that scheduler to a specific CPU,
+ i.e. <c>erl +S 1 +sbt db</c>.</p>
+ </warning>
+ </item>
<tag><c>{procs, PidSpec}</c>| <c>{procs, [PidSpec]}</c></tag>
<item>Specifies which processes that shall be traced. If
this option is not given, the calling process is
diff --git a/lib/tools/doc/src/instrument.xml b/lib/tools/doc/src/instrument.xml
index 9fd9332373..79bacb2927 100644
--- a/lib/tools/doc/src/instrument.xml
+++ b/lib/tools/doc/src/instrument.xml
@@ -111,15 +111,18 @@
default, but this can be configured an a per-allocator basis with the
<seealso marker="erts:erts_alloc#M_atags"><c>+M&lt;S&gt;atags</c>
</seealso> emulator option.</p>
- <p>If tagged allocations are not enabled on any of the specified
- allocator types, the call will fail with
- <c>{error, not_enabled}</c>.</p>
+ <p>If the specified allocator types are not enabled, the call will fail
+ with <c>{error, not_enabled}</c>.</p>
<p>The following options can be used:</p>
<taglist>
<tag><c>allocator_types</c></tag>
<item>
- <p>The allocator types that will be searched. Defaults to all
- <c>alloc_util</c> allocators.</p>
+ <p>The allocator types that will be searched. Note that blocks can
+ move freely between allocator types, so restricting the search to
+ certain allocators may return unexpected types (e.g. process
+ heaps when searching binary_alloc), or hide blocks that were
+ migrated out.</p>
+ <p>Defaults to all <c>alloc_util</c> allocators.</p>
</item>
<tag><c>scheduler_ids</c></tag>
<item>
diff --git a/lib/tools/doc/src/lcnt.xml b/lib/tools/doc/src/lcnt.xml
index 0c24375b91..d2595cdb60 100644
--- a/lib/tools/doc/src/lcnt.xml
+++ b/lib/tools/doc/src/lcnt.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2009</year>
- <year>2017</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/tools/doc/src/notes.xml b/lib/tools/doc/src/notes.xml
index 45f276c09e..8b0a2ca283 100644
--- a/lib/tools/doc/src/notes.xml
+++ b/lib/tools/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,27 @@
</header>
<p>This document describes the changes made to the Tools application.</p>
+<section><title>Tools 3.0</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>Added <c>instrument:allocations</c> and
+ <c>instrument:carriers</c> for retrieving information
+ about memory utilization and fragmentation.</p>
+ <p>The old <c>instrument</c> interface has been removed,
+ as have the related options <c>+Mim</c> and
+ <c>+Mis</c>.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14961</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Tools 2.11.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index e08db0ea79..242a5abe72 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -9,7 +9,7 @@
;; %CopyrightBegin%
;;
-;; Copyright Ericsson AB 1996-2017. All Rights Reserved.
+;; Copyright Ericsson AB 1996-2018. All Rights Reserved.
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
@@ -77,6 +77,7 @@
;;; Code:
(eval-when-compile (require 'cl))
+(eval-when-compile (require 'align))
;; Variables:
@@ -1405,6 +1406,19 @@ Other commands:
(add-function :before-until (local 'eldoc-documentation-function)
#'erldoc-eldoc-function))
(run-hooks 'erlang-mode-hook)
+
+ ;; Align maps.
+ (add-to-list 'align-rules-list
+ '(erlang-maps
+ (regexp . "\\(\\s-*\\)\\(=>\\)\\s-*")
+ (modes . '(erlang-mode))
+ (repeat . t)))
+ ;; Align records and :: specs
+ (add-to-list 'align-rules-list
+ '(erlang-record-specs
+ (regexp . "\\(\\s-*\\)\\(=\\).*\\(::\\)*\\s-*")
+ (modes . '(erlang-mode))
+ (repeat . t)))
(if (zerop (buffer-size))
(run-hooks 'erlang-new-file-hook)))
diff --git a/lib/tools/priv/styles.css b/lib/tools/priv/styles.css
new file mode 100644
index 0000000000..e10e94e3ad
--- /dev/null
+++ b/lib/tools/priv/styles.css
@@ -0,0 +1,91 @@
+body {
+ font: 14px/1.6 "Helvetica Neue", Helvetica, Arial, sans-serif;
+ margin: 0;
+ padding: 0;
+ color: #000;
+ border-top: 2px solid #ddd;
+ background-color: #fff;
+
+ min-height: 100%;
+ display: flex;
+ flex-direction: column;
+}
+
+h1 {
+ width: 100%;
+ border-bottom: 1px solid #eee;
+ margin-bottom: 0;
+ font-weight: 100;
+ font-size: 1.1em;
+ letter-spacing: 1px;
+}
+
+h1 code {
+ font-size: 0.96em;
+}
+
+code {
+ font: 12px monospace;
+}
+
+footer {
+ background: #eee;
+ width: 100%;
+ padding: 10px 0;
+ text-align: right;
+ border-top: 1px solid #ddd;
+ display: flex;
+ flex: 1;
+ order: 2;
+ justify-content: center;
+}
+
+table {
+ width: 100%;
+ margin-top: 10px;
+ border-collapse: collapse;
+ border: 1px solid #cbcbcb;
+ color: #000;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+}
+table thead {
+ display: none;
+}
+table td.line,
+table td.hits {
+ width: 20px;
+ background: #eaeaea;
+ text-align: center;
+ font-size: 11px;
+ padding: 0 10px;
+ color: #949494;
+}
+table td.hits {
+ width: 10px;
+ padding: 2px 5px;
+ color: rgba(0, 0, 0, 0.6);
+ background-color: #f0f0f0;
+}
+tr.miss td.line,
+tr.miss td.hits {
+ background-color: #ffdce0;
+ border-color: #fdaeb7;
+}
+tr.miss td {
+ background-color: #ffeef0;
+}
+tr.hit td.line,
+tr.hit td.hits {
+ background-color: #cdffd8;
+ border-color: #bef5cb;
+}
+tr.hit td {
+ background-color: #e6ffed;
+}
+td.source {
+ padding-left: 15px;
+ line-height: 15px;
+ white-space: pre;
+ font: 12px monospace;
+}
diff --git a/lib/tools/src/Makefile b/lib/tools/src/Makefile
index 032bd612db..a869ae6a00 100644
--- a/lib/tools/src/Makefile
+++ b/lib/tools/src/Makefile
@@ -72,6 +72,9 @@ APP_TARGET = $(EBIN)/$(APP_FILE)
APPUP_SRC = $(APPUP_FILE).src
APPUP_TARGET = $(EBIN)/$(APPUP_FILE)
+PRIVDIR = ../priv
+CSS = $(PRIVDIR)/styles.css
+
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -110,5 +113,7 @@ release_spec: opt
$(INSTALL_DIR) "$(RELSYSDIR)/ebin"
$(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) \
"$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv"
+ $(INSTALL_DATA) $(CSS) "$(RELSYSDIR)/priv"
release_docs_spec:
diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl
index bf5faa165d..337d9d637a 100644
--- a/lib/tools/src/cover.erl
+++ b/lib/tools/src/cover.erl
@@ -144,6 +144,8 @@
end).
-define(SPAWN_DBG(Tag,Value),put(Tag,Value)).
+-define(STYLESHEET, "styles.css").
+-define(TOOLS_APP, tools).
-include_lib("stdlib/include/ms_transform.hrl").
@@ -2415,20 +2417,8 @@ do_analyse_to_file1(Module, OutFile, ErlFile, HTML) ->
case file:open(OutFile, [write,raw,delayed_write]) of
{ok, OutFd} ->
Enc = encoding(ErlFile),
- if HTML ->
- Header =
- ["<!DOCTYPE HTML PUBLIC "
- "\"-//W3C//DTD HTML 3.2 Final//EN\">\n"
- "<html>\n"
- "<head>\n"
- "<meta http-equiv=\"Content-Type\""
- " content=\"text/html; charset=",
- html_encoding(Enc),"\"/>\n"
- "<title>",OutFile,"</title>\n"
- "</head>"
- "<body style='background-color: white;"
- " color: black'>\n"
- "<pre>\n"],
+ if HTML ->
+ Header = create_header(OutFile, Enc),
H1Bin = unicode:characters_to_binary(Header,Enc,Enc),
ok = file:write(OutFd,H1Bin);
true -> ok
@@ -2445,14 +2435,19 @@ do_analyse_to_file1(Module, OutFile, ErlFile, HTML) ->
string:pad(integer_to_list(Mi), 2, leading, $0),
string:pad(integer_to_list(S), 2, leading, $0)]),
- H2Bin = unicode:characters_to_binary(
- ["File generated from ",ErlFile," by COVER ",
- Timestamp,"\n\n"
- "**************************************"
- "**************************************"
- "\n\n"],
- Enc, Enc),
- ok = file:write(OutFd, H2Bin),
+ OutFileInfo =
+ if HTML ->
+ create_footer(ErlFile, Timestamp);
+ true ->
+ ["File generated from ",ErlFile," by COVER ",
+ Timestamp, "\n\n",
+ "**************************************"
+ "**************************************"
+ "\n\n"]
+ end,
+
+ H2Bin = unicode:characters_to_binary(OutFileInfo,Enc,Enc),
+ ok = file:write(OutFd, H2Bin),
Pattern = {#bump{module=Module,line='$1',_='_'},'$2'},
MS = [{Pattern,[{is_integer,'$1'},{'>','$1',0}],[{{'$1','$2'}}]}],
@@ -2462,7 +2457,7 @@ do_analyse_to_file1(Module, OutFile, ErlFile, HTML) ->
print_lines(Module, CovLines, InFd, OutFd, 1, HTML),
if HTML ->
- ok = file:write(OutFd, "</pre>\n</body>\n</html>\n");
+ ok = file:write(OutFd, close_html());
true -> ok
end,
@@ -2497,12 +2492,11 @@ print_lines(Module, CovLines, InFd, OutFd, L, HTML) ->
case CovLines of
[{L,N}|CovLines1] ->
if N=:=0, HTML=:=true ->
- LineNoNL = Line -- "\n",
- Str = " 0",
- %%Str = string:pad("0", 6, leading, $\s),
- RedLine = ["<font color=red>",Str,fill1(),
- LineNoNL,"</font>\n"],
- ok = file:write(OutFd, RedLine);
+ MissedLine = table_row("miss", Line, L, N),
+ ok = file:write(OutFd, MissedLine);
+ HTML=:=true ->
+ HitLine = table_row("hit", Line, L, N),
+ ok = file:write(OutFd, HitLine);
N < 1000000 ->
Str = string:pad(integer_to_list(N), 6, leading, $\s),
ok = file:write(OutFd, [Str,fill1(),Line]);
@@ -2515,7 +2509,11 @@ print_lines(Module, CovLines, InFd, OutFd, L, HTML) ->
end,
print_lines(Module, CovLines1, InFd, OutFd, L+1, HTML);
_ -> %Including comment lines
- ok = file:write(OutFd, [tab(),Line]),
+ NonCoveredContent =
+ if HTML -> table_row(Line, L);
+ true -> [tab(),Line]
+ end,
+ ok = file:write(OutFd, NonCoveredContent),
print_lines(Module, CovLines, InFd, OutFd, L+1, HTML)
end
end.
@@ -2525,6 +2523,59 @@ fill1() -> "..| ".
fill2() -> ".| ".
fill3() -> "| ".
+%% HTML sections
+create_header(OutFile, Enc) ->
+ ["<!doctype html>\n"
+ "<html>\n"
+ "<head>\n"
+ "<meta charset=\"",html_encoding(Enc),"\">\n"
+ "<title>",OutFile,"</title>\n"
+ "<style>"] ++
+ read_stylesheet() ++
+ ["</style>\n",
+ "</head>\n"
+ "<body>\n"
+ "<h1><code>",OutFile,"</code></h1>\n"].
+
+create_footer(ErlFile, Timestamp) ->
+ ["<footer><p>File generated from <code>",ErlFile,
+ "</code> by <a href=\"http://erlang.org/doc/man/cover.html\">cover</a> at ",
+ Timestamp,"</p></footer>\n<table>\n<tbody>\n"].
+
+close_html() ->
+ ["</tbody>\n",
+ "<thead>\n",
+ "<tr>\n",
+ "<th>Line</th>\n",
+ "<th>Hits</th>\n",
+ "<th>Source</th>\n",
+ "</tr>\n",
+ "</thead>\n",
+ "</table>\n",
+ "</body>\n"
+ "</html>\n"].
+
+table_row(CssClass, Line, L, N) ->
+ ["<tr class=\"",CssClass,"\">\n", table_data(Line, L, N)].
+table_row(Line, L) ->
+ ["<tr>\n", table_data(Line, L, "")].
+
+table_data(Line, L, N) ->
+ LineNoNL = Line -- "\n",
+ ["<td class=\"line\" id=\"L",integer_to_list(L),"\">",
+ integer_to_list(L),
+ "</td>\n",
+ "<td class=\"hits\">",maybe_integer_to_list(N),"</td>\n",
+ "<td class=\"source\"><code>",LineNoNL,"</code></td>\n</tr>\n"].
+
+maybe_integer_to_list(N) when is_integer(N) -> integer_to_list(N);
+maybe_integer_to_list(_) -> "".
+
+read_stylesheet() ->
+ PrivDir = code:priv_dir(?TOOLS_APP),
+ {ok, Css} = file:read_file(filename:join(PrivDir, ?STYLESHEET)),
+ [Css].
+
%%%--Export--------------------------------------------------------------
do_export(Module, OutFile, From, State) ->
case file:open(OutFile,[write,binary,raw,delayed_write]) of
diff --git a/lib/tools/src/fprof.erl b/lib/tools/src/fprof.erl
index a3b4bfdddf..36d4828861 100644
--- a/lib/tools/src/fprof.erl
+++ b/lib/tools/src/fprof.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/tools/src/lcnt.erl b/lib/tools/src/lcnt.erl
index 1db90c1d86..ee6057e4f5 100644
--- a/lib/tools/src/lcnt.erl
+++ b/lib/tools/src/lcnt.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/tools/test/emacs_SUITE.erl b/lib/tools/test/emacs_SUITE.erl
index f4e78da667..5839f9ce5b 100644
--- a/lib/tools/test/emacs_SUITE.erl
+++ b/lib/tools/test/emacs_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/tools/test/eprof_SUITE_data/eed.erl b/lib/tools/test/eprof_SUITE_data/eed.erl
index 5f2a21aa60..9fe49c6f5c 100644
--- a/lib/tools/test/eprof_SUITE_data/eed.erl
+++ b/lib/tools/test/eprof_SUITE_data/eed.erl
@@ -54,7 +54,7 @@ edit(Name) ->
loop(St0) ->
{ok, St1, Cmd} = get_line(St0),
- case catch command(lib:nonl(Cmd), St1) of
+ case catch command(nonl(Cmd), St1) of
{'EXIT', Reason} ->
%% XXX Should clear outstanding global command here.
loop(print_error({'EXIT', Reason}, St1));
@@ -66,6 +66,10 @@ loop(St0) ->
loop(St2)
end.
+nonl([$\n]) -> [];
+nonl([]) -> [];
+nonl([H|T]) -> [H|nonl(T)].
+
command(Cmd, St) ->
case parse_command(Cmd, St) of
quit ->
diff --git a/lib/tools/test/instrument_SUITE.erl b/lib/tools/test/instrument_SUITE.erl
index 8c521b2e1a..33259df58f 100644
--- a/lib/tools/test/instrument_SUITE.erl
+++ b/lib/tools/test/instrument_SUITE.erl
@@ -77,6 +77,8 @@ allocations_ramv(Config) when is_list(Config) ->
verify_allocations_disabled(_AllocType, Result) ->
verify_allocations_disabled(Result).
+verify_allocations_disabled({ok, {_HistStart, _UnscannedBytes, Allocs}}) ->
+ true = Allocs =:= #{};
verify_allocations_disabled({error, not_enabled}) ->
ok.
@@ -91,6 +93,13 @@ verify_allocations_enabled(_AllocType, Result) ->
verify_allocations_enabled({ok, {_HistStart, _UnscannedBytes, Allocs}}) ->
true = Allocs =/= #{}.
+verify_allocations_output(#{}, {ok, {_, _, Allocs}}) when Allocs =:= #{} ->
+ %% This happens when the allocator is enabled but tagging is disabled. If
+ %% there's an error that causes Allocs to always be empty when enabled it
+ %% will be caught by verify_allocations_enabled.
+ ok;
+verify_allocations_output(#{}, {error, not_enabled}) ->
+ ok;
verify_allocations_output(#{ histogram_start := HistStart,
histogram_width := HistWidth },
{ok, {HistStart, _UnscannedBytes, ByOrigin}}) ->
@@ -124,8 +133,6 @@ verify_allocations_output(#{ histogram_start := HistStart,
[BlockCount, GenTotalBlockCount])
end,
- ok;
-verify_allocations_output(#{}, {error, not_enabled}) ->
ok.
%% %% %% %% %% %%
@@ -214,7 +221,8 @@ verify_carriers_output(#{ histogram_start := HistStart,
ct:fail("Carrier count is ~p, expected at least ~p (SBC).",
[CarrierCount, GenSBCCount]);
CarrierCount >= GenSBCCount ->
- ok
+ ct:pal("Found ~p carriers, required at least ~p (SBC)." ,
+ [CarrierCount, GenSBCCount])
end,
ok;
@@ -292,9 +300,19 @@ start_slave(Args) ->
MicroSecs = erlang:monotonic_time(),
Name = "instr" ++ integer_to_list(MicroSecs),
Pa = filename:dirname(code:which(?MODULE)),
- {ok, Node} = test_server:start_node(list_to_atom(Name),
- slave,
- [{args, "-pa " ++ Pa ++ " " ++ Args}]),
+
+ %% We pass arguments through ZFLAGS as the nightly tests rotate
+ %% +Meamax/+Meamin which breaks the _enabled and _disabled tests unless
+ %% overridden.
+ ZFlags = os:getenv("ERL_ZFLAGS", ""),
+ {ok, Node} = try
+ os:putenv("ERL_ZFLAGS", ZFlags ++ [" " | Args]),
+ test_server:start_node(list_to_atom(Name),
+ slave,
+ [{args, "-pa " ++ Pa}])
+ after
+ os:putenv("ERL_ZFLAGS", ZFlags)
+ end,
Node.
generate_test_blocks() ->
@@ -309,8 +327,9 @@ generate_test_blocks() ->
MBCs = [<<I, 0:64/unit:8>> ||
I <- lists:seq(1, ?GENERATED_MBC_BLOCK_COUNT)],
Runner ! Ref,
- receive after infinity -> ok end,
- unreachable ! {SBCs, MBCs}
+ receive
+ gurka -> gaffel ! {SBCs, MBCs}
+ end
end),
receive
Ref -> ok
diff --git a/lib/tools/test/lcnt_SUITE.erl b/lib/tools/test/lcnt_SUITE.erl
index a79572a742..8a2f6bfc89 100644
--- a/lib/tools/test/lcnt_SUITE.erl
+++ b/lib/tools/test/lcnt_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/tools/test/xref_SUITE.erl b/lib/tools/test/xref_SUITE.erl
index 018f632948..4ec75f7962 100644
--- a/lib/tools/test/xref_SUITE.erl
+++ b/lib/tools/test/xref_SUITE.erl
@@ -2233,18 +2233,18 @@ variables(Conf) when is_list(Conf) ->
{{error, _, _}, _} = xref_base:variables(S108, [{verbose,false}]),
{ok, S109} = xref_base:set_library_path(S108, [], [{verbose,false}]),
- Tabs = length(ets:all()),
+ NoOfTables = erlang:system_info(ets_count),
{ok, S110} = eval("Eplus := closure E, TT := Eplus",
'closure()', S109),
{{ok, [{user, ['Eplus','TT']}]}, S111} = xref_base:variables(S110),
{ok, S112} = xref_base:forget(S111, ['TT','Eplus']),
- true = Tabs =:= length(ets:all()),
+ true = NoOfTables =:= erlang:system_info(ets_count),
{ok, NS0} = eval("Eplus := closure E", 'closure()', S112),
{{ok, [{user, ['Eplus']}]}, NS} = xref_base:variables(NS0),
ok = xref_base:delete(NS),
- true = Tabs =:= length(ets:all()),
+ true = NoOfTables =:= erlang:system_info(ets_count),
ok = file:delete(Beam),
ok.
diff --git a/lib/tools/vsn.mk b/lib/tools/vsn.mk
index f9723c0f9b..bb3f4c66c0 100644
--- a/lib/tools/vsn.mk
+++ b/lib/tools/vsn.mk
@@ -1 +1 @@
-TOOLS_VSN = 2.11.2
+TOOLS_VSN = 3.0
diff --git a/lib/wx/api_gen/gen_util.erl b/lib/wx/api_gen/gen_util.erl
index 3068a2f4ea..d27a9ae548 100644
--- a/lib/wx/api_gen/gen_util.erl
+++ b/lib/wx/api_gen/gen_util.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/api_gen/gl_gen.erl b/lib/wx/api_gen/gl_gen.erl
index 6f68517c16..c0509ed802 100644
--- a/lib/wx/api_gen/gl_gen.erl
+++ b/lib/wx/api_gen/gl_gen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/api_gen/gl_gen_erl.erl b/lib/wx/api_gen/gl_gen_erl.erl
index 7e673c2987..e62d182a37 100644
--- a/lib/wx/api_gen/gl_gen_erl.erl
+++ b/lib/wx/api_gen/gl_gen_erl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/api_gen/gl_scan_doc.erl b/lib/wx/api_gen/gl_scan_doc.erl
index 6ed5438608..c793d4940e 100644
--- a/lib/wx/api_gen/gl_scan_doc.erl
+++ b/lib/wx/api_gen/gl_scan_doc.erl
@@ -2,7 +2,7 @@
%%--------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/api_gen/wx_gen.erl b/lib/wx/api_gen/wx_gen.erl
index 4ba57501a5..cec6ac9ccf 100644
--- a/lib/wx/api_gen/wx_gen.erl
+++ b/lib/wx/api_gen/wx_gen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/api_gen/wx_gen_cpp.erl b/lib/wx/api_gen/wx_gen_cpp.erl
index cc4e1b5301..70a3530526 100644
--- a/lib/wx/api_gen/wx_gen_cpp.erl
+++ b/lib/wx/api_gen/wx_gen_cpp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/api_gen/wx_gen_erl.erl b/lib/wx/api_gen/wx_gen_erl.erl
index dfee7270b4..797533309b 100644
--- a/lib/wx/api_gen/wx_gen_erl.erl
+++ b/lib/wx/api_gen/wx_gen_erl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/api_gen/wxapi.conf b/lib/wx/api_gen/wxapi.conf
index e2ef2d890a..c1b55b6875 100644
--- a/lib/wx/api_gen/wxapi.conf
+++ b/lib/wx/api_gen/wxapi.conf
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/c_src/wxe_driver.c b/lib/wx/c_src/wxe_driver.c
index 26ae3564e7..c9d299e0df 100644
--- a/lib/wx/c_src/wxe_driver.c
+++ b/lib/wx/c_src/wxe_driver.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -38,10 +38,8 @@
#define TEMP_BINARY_SIZE 512
-static ErlDrvData wxe_driver_start(ErlDrvPort port, char *buff);
-static int wxe_driver_load(void);
+static ErlDrvData wxe_driver_start(ErlDrvPort port, char *command);
static void wxe_driver_stop(ErlDrvData handle);
-static void wxe_driver_unload(void);
static ErlDrvSSizeT wxe_driver_control(ErlDrvData handle,
unsigned int command,
char* buf, ErlDrvSizeT count,
@@ -63,30 +61,30 @@ char * erl_wx_privdir;
** The driver struct
*/
static ErlDrvEntry wxe_driver_entry = {
- wxe_driver_load, /* F_PTR init, called at loading */
- wxe_driver_start, /* L_PTR start, called when port is opened */
- wxe_driver_stop, /* F_PTR stop, called when port is closed */
- NULL, /* F_PTR output, called when erlang has sent */
- NULL, /* F_PTR ready_input, called when input descriptor
- ready */
- NULL, /* F_PTR ready_output, called when output
- descriptor ready */
- "wxe_driver", /* char *driver_name, the argument to open_port */
- wxe_driver_unload, /* F_PTR finish, called when unloaded */
- NULL, /* void * that is not used (BC) */
- wxe_driver_control, /* F_PTR control, port_control callback */
- NULL, /* F_PTR timeout, reserved */
- standard_outputv, /* F_PTR outputv, reserved */
- NULL, /* async */
- NULL, /* flush */
- wxe_driver_call, /* call */
- NULL, /* Event */
+ NULL, /* F_PTR init, called at loading */
+ wxe_driver_start, /* L_PTR start, called when port is opened */
+ wxe_driver_stop, /* F_PTR stop, called when port is closed */
+ NULL, /* F_PTR output, called when erlang has sent */
+ NULL, /* F_PTR ready_input, called when
+ input descriptor ready */
+ NULL, /* F_PTR ready_output, called when
+ output descriptor ready */
+ "wxe_driver", /* char *driver_name, the argument to open_port */
+ NULL, /* F_PTR finish, called when unloaded */
+ NULL, /* void * that is not used (BC) */
+ wxe_driver_control, /* F_PTR control, port_control callback */
+ NULL, /* F_PTR timeout, reserved */
+ standard_outputv, /* F_PTR outputv, reserved */
+ NULL, /* async */
+ NULL, /* flush */
+ wxe_driver_call, /* call */
+ NULL, /* Event */
ERL_DRV_EXTENDED_MARKER,
ERL_DRV_EXTENDED_MAJOR_VERSION,
ERL_DRV_EXTENDED_MINOR_VERSION,
- ERL_DRV_FLAG_USE_PORT_LOCKING, /* Port lock */
- NULL, /* Reserved Handle */
- wxe_process_died, /* Process Exited */
+ ERL_DRV_FLAG_USE_PORT_LOCKING, /* Port lock */
+ NULL, /* Reserved Handle */
+ wxe_process_died, /* Process Exited */
};
DRIVER_INIT(wxe_driver)
@@ -94,60 +92,56 @@ DRIVER_INIT(wxe_driver)
return &wxe_driver_entry;
}
-int wxe_driver_load()
-{
- if(load_native_gui())
- return 0;
- else
- return -1;
-}
-
ErlDrvPort WXE_DRV_PORT_HANDLE = 0;
ErlDrvTermData WXE_DRV_PORT = 0;
static ErlDrvData
-wxe_driver_start(ErlDrvPort port, char *buff)
-{
- wxe_data *data;
-
- data = (wxe_data *) malloc(sizeof(wxe_data));
- wxe_debug = 0;
-
- if (data == NULL) {
- fprintf(stderr, " Couldn't alloc mem\r\n");
- return(ERL_DRV_ERROR_GENERAL); /* ENOMEM */
- } else {
- ErlDrvTermData term_port = driver_mk_port(port);
- set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
- data->driver_data = NULL;
- data->bin = (WXEBinRef*) driver_alloc(sizeof(WXEBinRef)*DEF_BINS);
- data->bin[0].from = 0;
- data->bin[1].from = 0;
- data->bin[2].from = 0;
- data->max_bins = DEF_BINS;
- data->port_handle = port;
- data->port = term_port;
- data->pdl = driver_pdl_create(port);
- if(WXE_DRV_PORT_HANDLE == 0) {
- for(; *buff != 32; buff++);
- buff++;
- erl_wx_privdir = strdup(buff);
-
- WXE_DRV_PORT_HANDLE = port;
- WXE_DRV_PORT = term_port;
- wxe_master = data;
- if(!(start_native_gui(data) == 1))
- return(ERL_DRV_ERROR_GENERAL); /* ENOMEM */
- } else {
- meta_command(CREATE_PORT,data);
- }
- return (ErlDrvData) data;
- }
+wxe_driver_start(ErlDrvPort port, char *command)
+{
+ wxe_data *data;
+
+ data = (wxe_data *) malloc(sizeof(wxe_data));
+ wxe_debug = 0;
+
+ if (data == NULL) {
+ fprintf(stderr, " Couldn't alloc mem\r\n");
+ return(ERL_DRV_ERROR_GENERAL); /* ENOMEM */
+ } else {
+ ErlDrvTermData term_port = driver_mk_port(port);
+ set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
+ data->driver_data = NULL;
+ data->bin = (WXEBinRef*) driver_alloc(sizeof(WXEBinRef)*DEF_BINS);
+ data->bin[0].from = 0;
+ data->bin[1].from = 0;
+ data->bin[2].from = 0;
+ data->max_bins = DEF_BINS;
+ data->port_handle = port;
+ data->port = term_port;
+ data->pdl = driver_pdl_create(port);
+ if(WXE_DRV_PORT_HANDLE == 0) {
+ char *first_space = strchr(command, ' ');
+ if (first_space) {
+ char *priv_dir = first_space + 1;
+ erl_wx_privdir = strdup(priv_dir);
+
+ WXE_DRV_PORT_HANDLE = port;
+ WXE_DRV_PORT = term_port;
+ wxe_master = data;
+ if(start_native_gui(data) != 1)
+ return ERL_DRV_ERROR_GENERAL; /* ENOMEM */
+ } else {
+ return ERL_DRV_ERROR_BADARG;
+ }
+ } else {
+ meta_command(CREATE_PORT, data);
+ }
+ return (ErlDrvData) data;
+ }
}
static void
wxe_driver_stop(ErlDrvData handle)
-{
+{
wxe_data *sd = ((wxe_data *)handle);
if(sd->port_handle != WXE_DRV_PORT_HANDLE) {
// fprintf(stderr, "%s:%d: STOP \r\n", __FILE__,__LINE__);
@@ -155,18 +149,11 @@ wxe_driver_stop(ErlDrvData handle)
} else {
// fprintf(stderr, "%s:%d: STOP \r\n", __FILE__,__LINE__);
stop_native_gui(wxe_master);
- unload_native_gui();
free(wxe_master);
wxe_master = NULL;
}
}
-static void
-wxe_driver_unload(void)
-{
- // fprintf(stderr, "%s:%d: UNLOAD \r\n", __FILE__,__LINE__);
-}
-
static ErlDrvSSizeT
wxe_driver_control(ErlDrvData handle, unsigned op,
char* buf, ErlDrvSizeT count,
@@ -194,7 +181,7 @@ wxe_driver_call(ErlDrvData handle, unsigned int command,
if (len > rlen)
*res = driver_alloc(len);
memcpy((void *) *res, (void *) buf, len);
- return len;
+ return len;
}
@@ -219,20 +206,20 @@ standard_outputv(ErlDrvData drv_data, ErlIOVec* ev)
int i, max;
for(i = 0; i < sd->max_bins; i++) {
- if(sd->bin[i].from == 0) {
- binref = &sd->bin[i];
- break;
- }
+ if(sd->bin[i].from == 0) {
+ binref = &sd->bin[i];
+ break;
+ }
}
if(binref == NULL) { /* realloc */
- max = sd->max_bins + DEF_BINS;
- driver_realloc(sd->bin, sizeof(WXEBinRef)*max);
- for(i=sd->max_bins; i < max; i++) {
- sd->bin[i].from = 0;
- }
- binref = &sd->bin[sd->max_bins];
- sd->max_bins = max;
+ max = sd->max_bins + DEF_BINS;
+ driver_realloc(sd->bin, sizeof(WXEBinRef)*max);
+ for(i=sd->max_bins; i < max; i++) {
+ sd->bin[i].from = 0;
+ }
+ binref = &sd->bin[sd->max_bins];
+ sd->max_bins = max;
}
if(ev->size > 0) {
diff --git a/lib/wx/c_src/wxe_driver.h b/lib/wx/c_src/wxe_driver.h
index f9bca049c8..8b4ce2b804 100644
--- a/lib/wx/c_src/wxe_driver.h
+++ b/lib/wx/c_src/wxe_driver.h
@@ -56,10 +56,8 @@ typedef struct wxe_data_def {
void init_glexts(wxe_data*);
-int load_native_gui();
int start_native_gui(wxe_data *sd);
void stop_native_gui(wxe_data *sd);
-void unload_native_gui();
#define FUNC_CALL 13
#define CREATE_PORT 14
diff --git a/lib/wx/c_src/wxe_main.cpp b/lib/wx/c_src/wxe_main.cpp
index c7565e33bd..5b65d8a59b 100644
--- a/lib/wx/c_src/wxe_main.cpp
+++ b/lib/wx/c_src/wxe_main.cpp
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2014-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2014-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -59,15 +59,9 @@ void *wxe_main_loop(void * );
* START AND STOP of driver thread
* ************************************************************/
-int load_native_gui()
-{
- return 1;
-}
-
int start_native_gui(wxe_data *sd)
{
int res;
- ErlDrvThreadOpts *opts = NULL;
wxe_status_m = erl_drv_mutex_create((char *) "wxe_status_m");
wxe_status_c = erl_drv_cond_create((char *)"wxe_status_c");
@@ -79,7 +73,7 @@ int start_native_gui(wxe_data *sd)
res = erl_drv_steal_main_thread((char *)"wxwidgets",
&wxe_thread,wxe_main_loop,(void *) sd->pdl,NULL);
#else
- opts = erl_drv_thread_opts_create((char *)"wx thread");
+ ErlDrvThreadOpts *opts = erl_drv_thread_opts_create((char *)"wx thread");
opts->suggested_stack_size = 8192;
res = erl_drv_thread_create((char *)"wxwidgets",
&wxe_thread,wxe_main_loop,(void *) sd->pdl,opts);
@@ -116,11 +110,6 @@ void stop_native_gui(wxe_data *sd)
erl_drv_cond_destroy(wxe_batch_locker_c);
}
-void unload_native_gui()
-{
-
-}
-
/* ************************************************************
* wxWidgets Thread
* ************************************************************/
diff --git a/lib/wx/c_src/wxe_ps_init.c b/lib/wx/c_src/wxe_ps_init.c
index 277f3ac25f..4b3b47a80b 100644
--- a/lib/wx/c_src/wxe_ps_init.c
+++ b/lib/wx/c_src/wxe_ps_init.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/lib/wx/doc/overview.edoc b/lib/wx/doc/overview.edoc
index 054016f515..843a9c1320 100644
--- a/lib/wx/doc/overview.edoc
+++ b/lib/wx/doc/overview.edoc
@@ -218,7 +218,7 @@ the <em>fun</em> returns.
The callbacks are always invoked by another process and have
exclusive usage of the GUI when invoked. This means that a callback <em>fun</em>
-can not use the process dictionary and should not make calls to other
+cannot use the process dictionary and should not make calls to other
processes. Calls to another process inside a callback <em>fun</em> may cause a
deadlock if the other process is waiting on completion of his call to
the GUI.
diff --git a/lib/wx/doc/src/Makefile b/lib/wx/doc/src/Makefile
index c132c628f7..f66d63f63b 100644
--- a/lib/wx/doc/src/Makefile
+++ b/lib/wx/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2008-2017. All Rights Reserved.
+# Copyright Ericsson AB 2008-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -121,7 +121,8 @@ $(XML_CHAPTER_FILES:%=$(XMLDIR)/%): ../overview.edoc
debug opt:
clean clean_docs:
- rm -rf $(HTMLDIR)/*
+ rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f $(SPECDIR)/*
diff --git a/lib/wx/doc/src/notes.xml b/lib/wx/doc/src/notes.xml
index 69ea906ec0..45638dff35 100644
--- a/lib/wx/doc/src/notes.xml
+++ b/lib/wx/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2009</year><year>2017</year>
+ <year>2009</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,22 @@
<p>This document describes the changes made to the wxErlang
application.</p>
+<section><title>Wx 1.8.4</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Changed implementation so wx can now be built towards
+ wxWidgets-3.1.1.</p>
+ <p>
+ Own Id: OTP-15027</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Wx 1.8.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/wx/examples/demo/ex_aui.erl b/lib/wx/examples/demo/ex_aui.erl
index 97805621ed..49fa86f630 100644
--- a/lib/wx/examples/demo/ex_aui.erl
+++ b/lib/wx/examples/demo/ex_aui.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/examples/demo/ex_graphicsContext.erl b/lib/wx/examples/demo/ex_graphicsContext.erl
index 1193578037..1e6ffce18d 100644
--- a/lib/wx/examples/demo/ex_graphicsContext.erl
+++ b/lib/wx/examples/demo/ex_graphicsContext.erl
@@ -74,7 +74,7 @@ do_init(Config) ->
pen = Pen, brush = Brush, font = Font}}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Sync events i.e. from callbacks must return ok, it can not return a new state.
+%% Sync events i.e. from callbacks must return ok, it cannot return a new state.
%% Do the redrawing here.
handle_sync_event(#wx{event = #wxPaint{}},_,
#state{win=Win, pen = Pen, brush = Brush, font = Font}) ->
diff --git a/lib/wx/examples/simple/hello.erl b/lib/wx/examples/simple/hello.erl
index bf870c6f3e..8491a20af5 100644
--- a/lib/wx/examples/simple/hello.erl
+++ b/lib/wx/examples/simple/hello.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/examples/simple/hello2.erl b/lib/wx/examples/simple/hello2.erl
index b9da622b6b..656c056d9a 100644
--- a/lib/wx/examples/simple/hello2.erl
+++ b/lib/wx/examples/simple/hello2.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/examples/simple/menu.erl b/lib/wx/examples/simple/menu.erl
index 93573fb97d..7c0400bd1e 100644
--- a/lib/wx/examples/simple/menu.erl
+++ b/lib/wx/examples/simple/menu.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/examples/simple/minimal.erl b/lib/wx/examples/simple/minimal.erl
index 346f86433a..45efc06462 100644
--- a/lib/wx/examples/simple/minimal.erl
+++ b/lib/wx/examples/simple/minimal.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/examples/sudoku/sudoku.erl b/lib/wx/examples/sudoku/sudoku.erl
index 353f90d86f..a6a8d07e57 100644
--- a/lib/wx/examples/sudoku/sudoku.erl
+++ b/lib/wx/examples/sudoku/sudoku.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/examples/sudoku/sudoku_game.erl b/lib/wx/examples/sudoku/sudoku_game.erl
index aa15c05653..6463583e0f 100644
--- a/lib/wx/examples/sudoku/sudoku_game.erl
+++ b/lib/wx/examples/sudoku/sudoku_game.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/examples/sudoku/sudoku_gui.erl b/lib/wx/examples/sudoku/sudoku_gui.erl
index 4c4ad83cd7..e436bf2909 100644
--- a/lib/wx/examples/sudoku/sudoku_gui.erl
+++ b/lib/wx/examples/sudoku/sudoku_gui.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/examples/xrc/xrc.erl b/lib/wx/examples/xrc/xrc.erl
index 7e967777d2..a64e1f33ef 100644
--- a/lib/wx/examples/xrc/xrc.erl
+++ b/lib/wx/examples/xrc/xrc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/src/wx.erl b/lib/wx/src/wx.erl
index 6dd3c148db..a20758c826 100644
--- a/lib/wx/src/wx.erl
+++ b/lib/wx/src/wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/src/wxe_master.erl b/lib/wx/src/wxe_master.erl
index a55917f0aa..edef6b3613 100644
--- a/lib/wx/src/wxe_master.erl
+++ b/lib/wx/src/wxe_master.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/src/wxe_server.erl b/lib/wx/src/wxe_server.erl
index d6d9dbd629..e241a11e8b 100644
--- a/lib/wx/src/wxe_server.erl
+++ b/lib/wx/src/wxe_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/test/wx_app_SUITE.erl b/lib/wx/test/wx_app_SUITE.erl
index a5202d8448..99c8ef0416 100644
--- a/lib/wx/test/wx_app_SUITE.erl
+++ b/lib/wx/test/wx_app_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/test/wx_class_SUITE.erl b/lib/wx/test/wx_class_SUITE.erl
index c610b9c4f4..56749ba72b 100644
--- a/lib/wx/test/wx_class_SUITE.erl
+++ b/lib/wx/test/wx_class_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/test/wx_event_SUITE.erl b/lib/wx/test/wx_event_SUITE.erl
index a564f89e58..1cc194d569 100644
--- a/lib/wx/test/wx_event_SUITE.erl
+++ b/lib/wx/test/wx_event_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -347,9 +347,9 @@ connect_in_callback(Config) ->
%% such that new events are not fired until the previous
%% callback have returned.
- %% That means that a callback can not wait for other events
+ %% That means that a callback cannot wait for other events
%% in receive since they will not come.
- %% It also means that you can not attach a new callback directly from
+ %% It also means that you cannot attach a new callback directly from
%% the callback since that callback will be removed when the temporary
%% process that executes the outer callback (may) die(s) before the callback
%% is invoked
diff --git a/lib/wx/test/wx_opengl_SUITE.erl b/lib/wx/test/wx_opengl_SUITE.erl
index 19ea731dfb..053740ed8b 100644
--- a/lib/wx/test/wx_opengl_SUITE.erl
+++ b/lib/wx/test/wx_opengl_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/test/wx_test_lib.erl b/lib/wx/test/wx_test_lib.erl
index af508ff490..7bf2bb11bb 100644
--- a/lib/wx/test/wx_test_lib.erl
+++ b/lib/wx/test/wx_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/test/wx_xtra_SUITE.erl b/lib/wx/test/wx_xtra_SUITE.erl
index 486843ec63..8142d9566f 100644
--- a/lib/wx/test/wx_xtra_SUITE.erl
+++ b/lib/wx/test/wx_xtra_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/test/wxt b/lib/wx/test/wxt
index e720ed94f4..1343542366 100755
--- a/lib/wx/test/wxt
+++ b/lib/wx/test/wxt
@@ -18,7 +18,7 @@
#
# %CopyrightEnd%
#
-# Usage: mt <args to erlang startup script>
+# Usage: wxt <args to erlang startup script>
log=test_log_$$
latest=test_log_latest
@@ -27,7 +27,7 @@ erlcmd="erl -sname test_server -smp -pa ../ebin $p $args -wx_test_verbose true -
echo "Give the following command in order to see the outcome:"
echo ""
-echo " less test_log$$"
+echo " less $log"
rm "$latest" 2>/dev/null
ln -s "$log" "$latest"
diff --git a/lib/wx/test/wxt.erl b/lib/wx/test/wxt.erl
index 2b380606d5..280443404f 100644
--- a/lib/wx/test/wxt.erl
+++ b/lib/wx/test/wxt.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/wx/vsn.mk b/lib/wx/vsn.mk
index 7da4529c98..37a5477631 100644
--- a/lib/wx/vsn.mk
+++ b/lib/wx/vsn.mk
@@ -1 +1 @@
-WX_VSN = 1.8.3
+WX_VSN = 1.8.4
diff --git a/lib/xmerl/doc/src/Makefile b/lib/xmerl/doc/src/Makefile
index 94100910ef..0def492246 100644
--- a/lib/xmerl/doc/src/Makefile
+++ b/lib/xmerl/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2017. All Rights Reserved.
+# Copyright Ericsson AB 2004-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -140,6 +140,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)/*
+ rm -rf $(XMLDIR)
rm -f $(MAN3DIR)/*
rm -f $(MAN6DIR)/*
rm -f $(XMERL_XML_FILES)
diff --git a/lib/xmerl/doc/src/notes.xml b/lib/xmerl/doc/src/notes.xml
index f62a8dc53d..b7d1db7dfc 100644
--- a/lib/xmerl/doc/src/notes.xml
+++ b/lib/xmerl/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2017</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,21 @@
<p>This document describes the changes made to the Xmerl application.</p>
+<section><title>Xmerl 1.3.17</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix typos in documentation.</p>
+ <p>
+ Own Id: OTP-15039</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Xmerl 1.3.16</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/xmerl/src/xmerl_scan.erl b/lib/xmerl/src/xmerl_scan.erl
index a1f6ad4e2c..a7538180e6 100644
--- a/lib/xmerl/src/xmerl_scan.erl
+++ b/lib/xmerl/src/xmerl_scan.erl
@@ -279,7 +279,7 @@ int_file_decl(F, Options,_ExtCharset) ->
%% @spec string(Text::list()) -> {xmlElement(),Rest}
%% Rest = list()
-%% @equiv string(Test, [])
+%% @equiv string(Text, [])
string(Str) ->
string(Str, []).
diff --git a/lib/xmerl/src/xmerl_xsd.erl b/lib/xmerl/src/xmerl_xsd.erl
index d727084175..2836bb0e5b 100644
--- a/lib/xmerl/src/xmerl_xsd.erl
+++ b/lib/xmerl/src/xmerl_xsd.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/xmerl/test/xmerl_SUITE_data/eventp/CMOM.xml b/lib/xmerl/test/xmerl_SUITE_data/eventp/CMOM.xml
index c2533248d1..0379c18214 100644
--- a/lib/xmerl/test/xmerl_SUITE_data/eventp/CMOM.xml
+++ b/lib/xmerl/test/xmerl_SUITE_data/eventp/CMOM.xml
@@ -276,7 +276,7 @@
</exception>
<exception name="UpgradeNotPossibleException">
- <description>Before an upgrade is started it was found that the upgrade can not take place. A possible reason is that the upgrade package that is running in the node is not in the upgrade window of this upgrade package. </description>
+ <description>Before an upgrade is started it was found that the upgrade cannot take place. A possible reason is that the upgrade package that is running in the node is not in the upgrade window of this upgrade package. </description>
<exceptionParameter name="message">
<dataType>
<string/>
@@ -1703,7 +1703,7 @@ Example:
<exception name="NoSuchAttributeException">
<description>Exception thrown when an MO attribute is requested to be accessed but the access
-method for the is not defined (the attribute can not be accessed)</description>
+method for the is not defined (the attribute cannot be accessed)</description>
</exception>
<exception name="MoCardinalityViolationException">
@@ -3125,7 +3125,7 @@ active = Synchronization is used in system clock generation.
<description>RefState can have the following values:
failed = synchronization reference is not capable to perform its required tasks.
degraded = capability of synchronization reference to perform its required tasks is degraded e.g. because of signal level degradation. This value is only applicable for traffic carrying (ET physical path termination) synchronization references. Note: attribute degradationIsFault controls whether synchronization reference degradation is interpreted as a synchronization reference fault or not.
-lossOfTracking = system clock regulation algorithm on TU board can not follow the 8kHz synchronization reference signal either because of the poor quality of the signal or because of a HW fault at TU board. If all synchronization references repeatedly end up to state lossOfTracking, fault is likely in TU HW.
+lossOfTracking = system clock regulation algorithm on TU board cannot follow the 8kHz synchronization reference signal either because of the poor quality of the signal or because of a HW fault at TU board. If all synchronization references repeatedly end up to state lossOfTracking, fault is likely in TU HW.
ok = synchronization reference is capable of performing its required tasks.
</description>
<enumMember name="failed">
@@ -11270,7 +11270,7 @@ Note! This action requires a transaction.</description>
The changing of the IP address with operation assignIpAddress might cause interruption of the communication if the network management tool is connected via the ethernet link.
-Note: The EthernetLink MO can not be deleted!
+Note: The EthernetLink MO cannot be deleted!
Note: The performance monitoring counters in the EthernetLink MO has a "Wrap-around time" of approximately 2 hours.
</description>
@@ -11532,8 +11532,8 @@ Note! This action requires a transaction.</description>
<description>This MO holds the IP routing table.
The IpRoutingTable MO is automatically created when the Ip MO is created.
-The IpRoutingTable MO can not be created manually.
-The IpRoutingTable MO can not be deleted.
+The IpRoutingTable MO cannot be created manually.
+The IpRoutingTable MO cannot be deleted.
</description>
<systemCreated/>
<attribute name="userLabel">
@@ -12967,7 +12967,7 @@ Note! When using fractional atm, timeslot 1 must be a part of the fraction.
Note! ETM1 does not support EPD and PPD
-Note! ETM1 does not have a proper buffer management. Thus fairness of UBR+ traffic can not be guaranteed and shaping on UBR+ traffic is not possible.
+Note! ETM1 does not have a proper buffer management. Thus fairness of UBR+ traffic cannot be guaranteed and shaping on UBR+ traffic is not possible.
Note! The number of VCC TP+VPC TP with performance monitoring enabled (i.e. PM mode &lt;&gt; off) is restricted to 1 per port.
</description>
@@ -13371,7 +13371,7 @@ Struct element description :
-Date is in string format, max length is 40. Format for date is: weekday month date hour:min:seconds year.
-Status is in string format, max length is 40.
-Note! The identity can not be the same as name. Identity should contain the product identity.
+Note! The identity cannot be the same as name. Identity should contain the product identity.
</description>
@@ -13562,7 +13562,7 @@ Note! For comment and operatorName spaces (' ') are also allowed within the stri
This action does not require a transaction.
-Note! The configurationVersionName and identity can not be the same. The identity should be the product identity.
+Note! The configurationVersionName and identity cannot be the same. The identity should be the product identity.
</description>
<returnType>
<void/>
@@ -17367,7 +17367,7 @@ NOTE: There is a restriction of a maximum of 32 Mtp2Tp's per MP.</description>
<attribute name="mtp2ProfileItuId">
<description>Reference to a Mtp2ProfileItu MO.
-Note: The bitRate can not be changed.</description>
+Note: The bitRate cannot be changed.</description>
<mandatory/>
<noNotification/>
<dataType>
@@ -17566,7 +17566,7 @@ NOTE: There is a restriction of a maximum of 32 Mtp2Tp's per MP.</description>
<attribute name="mtp2ProfileAnsiId">
<description>Reference to a Mtp2ProfileAnsi MO.
-Note: The bitRate can not be changed.</description>
+Note: The bitRate cannot be changed.</description>
<mandatory/>
<noNotification/>
<dataType>
@@ -21777,7 +21777,7 @@ Each E1/DS1/J1 channel can suport up to 2 VP connections.
The ET-MC41 board support one biderectional F4/F5 PM flow per E1 channel.
-Note! The ETMC41 supports IMA. However the E1 ports being part of the same IMA group can not be selected randomly.
+Note! The ETMC41 supports IMA. However the E1 ports being part of the same IMA group cannot be selected randomly.
Note! The number of VCC TP+VPC TP with performance monitoring enabled (i.e. PM mode &lt;&gt; off) is restricted to 1 / port
@@ -21883,7 +21883,7 @@ NOTE: There is a restriction of a maximum of 32 Mtp2Tp's per MP.
<attribute name="mtp2ProfileChinaId">
<description>Reference to a Mtp2ProfileChina MO.
-Note: The bitRate can not be changed.</description>
+Note: The bitRate cannot be changed.</description>
<mandatory/>
<noNotification/>
<dataType>
diff --git a/lib/xmerl/test/xmerl_SUITE_data/eventp/CelloMOM.xml b/lib/xmerl/test/xmerl_SUITE_data/eventp/CelloMOM.xml
index 3b5d8ae2ad..3b9ccac0f4 100644
--- a/lib/xmerl/test/xmerl_SUITE_data/eventp/CelloMOM.xml
+++ b/lib/xmerl/test/xmerl_SUITE_data/eventp/CelloMOM.xml
@@ -276,7 +276,7 @@
</exception>
<exception name="UpgradeNotPossibleException">
- <description>Before an upgrade is started it was found that the upgrade can not take place. A possible reason is that the upgrade package that is running in the node is not in the upgrade window of this upgrade package. </description>
+ <description>Before an upgrade is started it was found that the upgrade cannot take place. A possible reason is that the upgrade package that is running in the node is not in the upgrade window of this upgrade package. </description>
<exceptionParameter name="message">
<dataType>
<string/>
@@ -1703,7 +1703,7 @@ Example:
<exception name="NoSuchAttributeException">
<description>Exception thrown when an MO attribute is requested to be accessed but the access
-method for the is not defined (the attribute can not be accessed)</description>
+method for the is not defined (the attribute cannot be accessed)</description>
</exception>
<exception name="MoCardinalityViolationException">
@@ -3125,7 +3125,7 @@ active = Synchronization is used in system clock generation.
<description>RefState can have the following values:
failed = synchronization reference is not capable to perform its required tasks.
degraded = capability of synchronization reference to perform its required tasks is degraded e.g. because of signal level degradation. This value is only applicable for traffic carrying (ET physical path termination) synchronization references. Note: attribute degradationIsFault controls whether synchronization reference degradation is interpreted as a synchronization reference fault or not.
-lossOfTracking = system clock regulation algorithm on TU board can not follow the 8kHz synchronization reference signal either because of the poor quality of the signal or because of a HW fault at TU board. If all synchronization references repeatedly end up to state lossOfTracking, fault is likely in TU HW.
+lossOfTracking = system clock regulation algorithm on TU board cannot follow the 8kHz synchronization reference signal either because of the poor quality of the signal or because of a HW fault at TU board. If all synchronization references repeatedly end up to state lossOfTracking, fault is likely in TU HW.
ok = synchronization reference is capable of performing its required tasks.
</description>
<enumMember name="failed">
@@ -11270,7 +11270,7 @@ Note! This action requires a transaction.</description>
The changing of the IP address with operation assignIpAddress might cause interruption of the communication if the network management tool is connected via the ethernet link.
-Note: The EthernetLink MO can not be deleted!
+Note: The EthernetLink MO cannot be deleted!
Note: The performance monitoring counters in the EthernetLink MO has a "Wrap-around time" of approximately 2 hours.
</description>
@@ -11532,8 +11532,8 @@ Note! This action requires a transaction.</description>
<description>This MO holds the IP routing table.
The IpRoutingTable MO is automatically created when the Ip MO is created.
-The IpRoutingTable MO can not be created manually.
-The IpRoutingTable MO can not be deleted.
+The IpRoutingTable MO cannot be created manually.
+The IpRoutingTable MO cannot be deleted.
</description>
<systemCreated/>
<attribute name="userLabel">
@@ -12967,7 +12967,7 @@ Note! When using fractional atm, timeslot 1 must be a part of the fraction.
Note! ETM1 does not support EPD and PPD
-Note! ETM1 does not have a proper buffer management. Thus fairness of UBR+ traffic can not be guaranteed and shaping on UBR+ traffic is not possible.
+Note! ETM1 does not have a proper buffer management. Thus fairness of UBR+ traffic cannot be guaranteed and shaping on UBR+ traffic is not possible.
Note! The number of VCC TP+VPC TP with performance monitoring enabled (i.e. PM mode &lt;&gt; off) is restricted to 1 per port.
</description>
@@ -13371,7 +13371,7 @@ Struct element description :
-Date is in string format, max length is 40. Format for date is: weekday month date hour:min:seconds year.
-Status is in string format, max length is 40.
-Note! The identity can not be the same as name. Identity should contain the product identity.
+Note! The identity cannot be the same as name. Identity should contain the product identity.
</description>
@@ -13562,7 +13562,7 @@ Note! For comment and operatorName spaces (' ') are also allowed within the stri
This action does not require a transaction.
-Note! The configurationVersionName and identity can not be the same. The identity should be the product identity.
+Note! The configurationVersionName and identity cannot be the same. The identity should be the product identity.
</description>
<returnType>
<void/>
@@ -17367,7 +17367,7 @@ NOTE: There is a restriction of a maximum of 32 Mtp2Tp's per MP.</description>
<attribute name="mtp2ProfileItuId">
<description>Reference to a Mtp2ProfileItu MO.
-Note: The bitRate can not be changed.</description>
+Note: The bitRate cannot be changed.</description>
<mandatory/>
<noNotification/>
<dataType>
@@ -17566,7 +17566,7 @@ NOTE: There is a restriction of a maximum of 32 Mtp2Tp's per MP.</description>
<attribute name="mtp2ProfileAnsiId">
<description>Reference to a Mtp2ProfileAnsi MO.
-Note: The bitRate can not be changed.</description>
+Note: The bitRate cannot be changed.</description>
<mandatory/>
<noNotification/>
<dataType>
@@ -21777,7 +21777,7 @@ Each E1/DS1/J1 channel can suport up to 2 VP connections.
The ET-MC41 board support one biderectional F4/F5 PM flow per E1 channel.
-Note! The ETMC41 supports IMA. However the E1 ports being part of the same IMA group can not be selected randomly.
+Note! The ETMC41 supports IMA. However the E1 ports being part of the same IMA group cannot be selected randomly.
Note! The number of VCC TP+VPC TP with performance monitoring enabled (i.e. PM mode &lt;&gt; off) is restricted to 1 / port
@@ -21883,7 +21883,7 @@ NOTE: There is a restriction of a maximum of 32 Mtp2Tp's per MP.
<attribute name="mtp2ProfileChinaId">
<description>Reference to a Mtp2ProfileChina MO.
-Note: The bitRate can not be changed.</description>
+Note: The bitRate cannot be changed.</description>
<mandatory/>
<noNotification/>
<dataType>
diff --git a/lib/xmerl/vsn.mk b/lib/xmerl/vsn.mk
index ddff0c8894..be11935f2f 100644
--- a/lib/xmerl/vsn.mk
+++ b/lib/xmerl/vsn.mk
@@ -1 +1 @@
-XMERL_VSN = 1.3.16
+XMERL_VSN = 1.3.17
diff --git a/make/cross_check_erl b/make/cross_check_erl
index f8ba73023a..524514a63f 100755
--- a/make/cross_check_erl
+++ b/make/cross_check_erl
@@ -90,7 +90,7 @@ start() ->
EOF
erlc cross_check_erl.erl 2>/dev/null \
- && used_otp=`erl -noshell -noinput -pa . -run cross_check_erl 2>/dev/null`
+ && used_otp=`erl -noshell -noinput -boot start_clean -pa . -run cross_check_erl 2>/dev/null`
res=$?
diff --git a/make/emd2exml.in b/make/emd2exml.in
index 57bcaba24d..24837696f4 100755
--- a/make/emd2exml.in
+++ b/make/emd2exml.in
@@ -1214,7 +1214,7 @@ complete_output(#state{out = Out} = S) ->
complete_output(S, [], Out) ->
S#state{delayed_array = [],
- out = ["<?xml version=\"1.0\" encoding=\"utf8\" ?>", nl(),
+ out = ["<?xml version=\"1.0\" encoding=\"utf-8\" ?>", nl(),
"<!DOCTYPE chapter SYSTEM \"chapter.dtd\">", nl(),
Out]};
complete_output(S, [{delayed, IX}|Rest], Out) ->
diff --git a/make/make_emakefile.in b/make/make_emakefile.in
index fbca77887a..e0740d1013 100755
--- a/make/make_emakefile.in
+++ b/make/make_emakefile.in
@@ -1,4 +1,4 @@
-#!@PERL@
+#!/usr/bin/env @PERL@
# -*- cperl -*-
use strict;
diff --git a/make/otp.mk.in b/make/otp.mk.in
index c514a150ca..df29d26833 100644
--- a/make/otp.mk.in
+++ b/make/otp.mk.in
@@ -87,6 +87,13 @@ AR = @AR@
PERL = @PERL@
LLVM_PROFDATA = @LLVM_PROFDATA@
+MIXED_CYGWIN_VC = @MIXED_CYGWIN_VC@
+MIXED_MSYS_VC = @MIXED_MSYS_VC@
+MIXED_VC = @MIXED_VC@
+MIXED_CYGWIN_MINGW = @MIXED_CYGWIN_MINGW@
+MIXED_CYGWIN = @MIXED_CYGWIN@
+MIXED_MSYS = @MIXED_MSYS@
+
BITS64 = @BITS64@
OTP_RELEASE = @OTP_RELEASE@
diff --git a/make/otp_release_targets.mk b/make/otp_release_targets.mk
index 779aaa1a1e..d1fbf6c58f 100644
--- a/make/otp_release_targets.mk
+++ b/make/otp_release_targets.mk
@@ -36,9 +36,13 @@ endif
# -------------------------------------------------------
# Take the XML files and add the github link info to them
# -------------------------------------------------------
+ifneq ($(strip $(XMLDIR)),)
_create_xml_dirs := $(shell mkdir -p $(XMLDIR))
+endif
XML_GEN_FILES+=$(patsubst %.xml,$(XMLDIR)/%.xml,$(XML_FILES))
+
+ifeq ($(strip $(NO_GITHUB_DOC_LINKS)),)
$(XMLDIR)/%.xml: %.xml
$(gen_verbose)escript $(DOCGEN)/priv/bin/github_link.escript $< \
"$(subst $(ERL_TOP)/,,$(CURDIR)/$^)" "NA" $@
@@ -46,6 +50,13 @@ $(XMLDIR)/%.xml: %.xml
$(XMLDIR)/%.xmlsrc: %.xmlsrc
$(gen_verbose)escript $(DOCGEN)/priv/bin/github_link.escript $< \
"$(subst $(ERL_TOP)/,,$(CURDIR)/$^)" "NA" $@
+else
+## Just copy the files if the application does not want github edit links
+$(XMLDIR)/%.xml: %.xml
+ $(gen_verbose)$(CP) $< $@
+$(XMLDIR)/%.xmlsrc: %.xmlsrc
+ $(gen_verbose)$(CP) $< $@
+endif
ifeq ($(TOPDOC),)
diff --git a/otp_versions.table b/otp_versions.table
index c66a390f21..e329240e4e 100644
--- a/otp_versions.table
+++ b/otp_versions.table
@@ -1,3 +1,17 @@
+OTP-21.0.5 : compiler-7.2.3 crypto-4.3.1 erts-10.0.5 # asn1-5.0.6 common_test-1.16 debugger-4.2.5 dialyzer-3.3 diameter-2.1.5 edoc-0.9.3 eldap-1.2.4 erl_docgen-0.8 erl_interface-3.10.3 et-1.6.2 eunit-2.3.6 ftp-1.0 hipe-3.18 inets-7.0 jinterface-1.9 kernel-6.0 megaco-3.18.3 mnesia-4.15.4 observer-2.8 odbc-2.12.1 os_mon-2.4.5 otp_mibs-1.2 parsetools-2.1.7 public_key-1.6.1 reltool-0.7.6 runtime_tools-1.13 sasl-3.2 snmp-5.2.11 ssh-4.7 ssl-9.0 stdlib-3.5.1 syntax_tools-2.1.5 tftp-1.0 tools-3.0 wx-1.8.4 xmerl-1.3.17 :
+OTP-21.0.4 : erts-10.0.4 # asn1-5.0.6 common_test-1.16 compiler-7.2.2 crypto-4.3 debugger-4.2.5 dialyzer-3.3 diameter-2.1.5 edoc-0.9.3 eldap-1.2.4 erl_docgen-0.8 erl_interface-3.10.3 et-1.6.2 eunit-2.3.6 ftp-1.0 hipe-3.18 inets-7.0 jinterface-1.9 kernel-6.0 megaco-3.18.3 mnesia-4.15.4 observer-2.8 odbc-2.12.1 os_mon-2.4.5 otp_mibs-1.2 parsetools-2.1.7 public_key-1.6.1 reltool-0.7.6 runtime_tools-1.13 sasl-3.2 snmp-5.2.11 ssh-4.7 ssl-9.0 stdlib-3.5.1 syntax_tools-2.1.5 tftp-1.0 tools-3.0 wx-1.8.4 xmerl-1.3.17 :
+OTP-21.0.3 : erts-10.0.3 # asn1-5.0.6 common_test-1.16 compiler-7.2.2 crypto-4.3 debugger-4.2.5 dialyzer-3.3 diameter-2.1.5 edoc-0.9.3 eldap-1.2.4 erl_docgen-0.8 erl_interface-3.10.3 et-1.6.2 eunit-2.3.6 ftp-1.0 hipe-3.18 inets-7.0 jinterface-1.9 kernel-6.0 megaco-3.18.3 mnesia-4.15.4 observer-2.8 odbc-2.12.1 os_mon-2.4.5 otp_mibs-1.2 parsetools-2.1.7 public_key-1.6.1 reltool-0.7.6 runtime_tools-1.13 sasl-3.2 snmp-5.2.11 ssh-4.7 ssl-9.0 stdlib-3.5.1 syntax_tools-2.1.5 tftp-1.0 tools-3.0 wx-1.8.4 xmerl-1.3.17 :
+OTP-21.0.2 : compiler-7.2.2 erts-10.0.2 public_key-1.6.1 stdlib-3.5.1 # asn1-5.0.6 common_test-1.16 crypto-4.3 debugger-4.2.5 dialyzer-3.3 diameter-2.1.5 edoc-0.9.3 eldap-1.2.4 erl_docgen-0.8 erl_interface-3.10.3 et-1.6.2 eunit-2.3.6 ftp-1.0 hipe-3.18 inets-7.0 jinterface-1.9 kernel-6.0 megaco-3.18.3 mnesia-4.15.4 observer-2.8 odbc-2.12.1 os_mon-2.4.5 otp_mibs-1.2 parsetools-2.1.7 reltool-0.7.6 runtime_tools-1.13 sasl-3.2 snmp-5.2.11 ssh-4.7 ssl-9.0 syntax_tools-2.1.5 tftp-1.0 tools-3.0 wx-1.8.4 xmerl-1.3.17 :
+OTP-21.0.1 : compiler-7.2.1 erts-10.0.1 # asn1-5.0.6 common_test-1.16 crypto-4.3 debugger-4.2.5 dialyzer-3.3 diameter-2.1.5 edoc-0.9.3 eldap-1.2.4 erl_docgen-0.8 erl_interface-3.10.3 et-1.6.2 eunit-2.3.6 ftp-1.0 hipe-3.18 inets-7.0 jinterface-1.9 kernel-6.0 megaco-3.18.3 mnesia-4.15.4 observer-2.8 odbc-2.12.1 os_mon-2.4.5 otp_mibs-1.2 parsetools-2.1.7 public_key-1.6 reltool-0.7.6 runtime_tools-1.13 sasl-3.2 snmp-5.2.11 ssh-4.7 ssl-9.0 stdlib-3.5 syntax_tools-2.1.5 tftp-1.0 tools-3.0 wx-1.8.4 xmerl-1.3.17 :
+OTP-21.0 : asn1-5.0.6 common_test-1.16 compiler-7.2 crypto-4.3 debugger-4.2.5 dialyzer-3.3 diameter-2.1.5 edoc-0.9.3 eldap-1.2.4 erl_docgen-0.8 erl_interface-3.10.3 erts-10.0 et-1.6.2 eunit-2.3.6 ftp-1.0 hipe-3.18 inets-7.0 jinterface-1.9 kernel-6.0 mnesia-4.15.4 observer-2.8 os_mon-2.4.5 otp_mibs-1.2 parsetools-2.1.7 public_key-1.6 reltool-0.7.6 runtime_tools-1.13 sasl-3.2 ssh-4.7 ssl-9.0 stdlib-3.5 syntax_tools-2.1.5 tftp-1.0 tools-3.0 wx-1.8.4 xmerl-1.3.17 # megaco-3.18.3 odbc-2.12.1 snmp-5.2.11 :
+OTP-20.3.8.6 : inets-6.5.2.3 # asn1-5.0.5.1 common_test-1.15.4 compiler-7.1.5.1 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2.1 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.3 erl_interface-3.10.2.1 erts-9.3.3.3 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4.2 jinterface-1.8.1 kernel-5.4.3.2 megaco-3.18.3 mnesia-4.15.3.1 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11 ssh-4.6.9.1 ssl-8.2.6.2 stdlib-3.4.5 syntax_tools-2.1.4.1 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
+OTP-20.3.8.5 : compiler-7.1.5.1 crypto-4.2.2.1 erts-9.3.3.3 mnesia-4.15.3.1 ssl-8.2.6.2 # asn1-5.0.5.1 common_test-1.15.4 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.3 erl_interface-3.10.2.1 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4.2 inets-6.5.2.2 jinterface-1.8.1 kernel-5.4.3.2 megaco-3.18.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11 ssh-4.6.9.1 stdlib-3.4.5 syntax_tools-2.1.4.1 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
+OTP-20.3.8.4 : asn1-5.0.5.1 # common_test-1.15.4 compiler-7.1.5 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.3 erl_interface-3.10.2.1 erts-9.3.3.2 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4.2 inets-6.5.2.2 jinterface-1.8.1 kernel-5.4.3.2 megaco-3.18.3 mnesia-4.15.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11 ssh-4.6.9.1 ssl-8.2.6.1 stdlib-3.4.5 syntax_tools-2.1.4.1 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
+OTP-20.3.8.3 : erts-9.3.3.2 ic-4.4.4.2 inets-6.5.2.2 kernel-5.4.3.2 ssl-8.2.6.1 # asn1-5.0.5 common_test-1.15.4 compiler-7.1.5 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.3 erl_interface-3.10.2.1 et-1.6.1 eunit-2.3.5 hipe-3.17.1 jinterface-1.8.1 megaco-3.18.3 mnesia-4.15.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11 ssh-4.6.9.1 stdlib-3.4.5 syntax_tools-2.1.4.1 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
+OTP-20.3.8.2 : erl_interface-3.10.2.1 erts-9.3.3.1 ic-4.4.4.1 kernel-5.4.3.1 # asn1-5.0.5 common_test-1.15.4 compiler-7.1.5 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.3 et-1.6.1 eunit-2.3.5 hipe-3.17.1 inets-6.5.2.1 jinterface-1.8.1 megaco-3.18.3 mnesia-4.15.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11 ssh-4.6.9.1 ssl-8.2.6 stdlib-3.4.5 syntax_tools-2.1.4.1 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
+OTP-20.3.8.1 : inets-6.5.2.1 ssh-4.6.9.1 syntax_tools-2.1.4.1 # asn1-5.0.5 common_test-1.15.4 compiler-7.1.5 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.3 erl_interface-3.10.2 erts-9.3.3 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4 jinterface-1.8.1 kernel-5.4.3 megaco-3.18.3 mnesia-4.15.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11 ssl-8.2.6 stdlib-3.4.5 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
+OTP-20.3.8 : erts-9.3.3 snmp-5.2.11 # asn1-5.0.5 common_test-1.15.4 compiler-7.1.5 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.3 erl_interface-3.10.2 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4 inets-6.5.2 jinterface-1.8.1 kernel-5.4.3 megaco-3.18.3 mnesia-4.15.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 ssh-4.6.9 ssl-8.2.6 stdlib-3.4.5 syntax_tools-2.1.4 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
+OTP-20.3.7 : erl_docgen-0.7.3 erts-9.3.2 inets-6.5.2 # asn1-5.0.5 common_test-1.15.4 compiler-7.1.5 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_interface-3.10.2 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4 jinterface-1.8.1 kernel-5.4.3 megaco-3.18.3 mnesia-4.15.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.10 ssh-4.6.9 ssl-8.2.6 stdlib-3.4.5 syntax_tools-2.1.4 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
OTP-20.3.6 : crypto-4.2.2 ssh-4.6.9 # asn1-5.0.5 common_test-1.15.4 compiler-7.1.5 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.2 erl_interface-3.10.2 erts-9.3.1 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4 inets-6.5.1 jinterface-1.8.1 kernel-5.4.3 megaco-3.18.3 mnesia-4.15.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.10 ssl-8.2.6 stdlib-3.4.5 syntax_tools-2.1.4 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
OTP-20.3.5 : erts-9.3.1 ssl-8.2.6 # asn1-5.0.5 common_test-1.15.4 compiler-7.1.5 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.1 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.2 erl_interface-3.10.2 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4 inets-6.5.1 jinterface-1.8.1 kernel-5.4.3 megaco-3.18.3 mnesia-4.15.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.10 ssh-4.6.8 stdlib-3.4.5 syntax_tools-2.1.4 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
OTP-20.3.4 : erl_interface-3.10.2 ic-4.4.4 inets-6.5.1 ssh-4.6.8 # asn1-5.0.5 common_test-1.15.4 compiler-7.1.5 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.1 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.2 erts-9.3 et-1.6.1 eunit-2.3.5 hipe-3.17.1 jinterface-1.8.1 kernel-5.4.3 megaco-3.18.3 mnesia-4.15.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.10 ssl-8.2.5 stdlib-3.4.5 syntax_tools-2.1.4 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
@@ -25,6 +39,7 @@ OTP-20.0.3 : asn1-5.0.2 compiler-7.1.1 erts-9.0.3 ssh-4.5.1 # common_test-1.15.1
OTP-20.0.2 : asn1-5.0.1 erts-9.0.2 kernel-5.3.1 # common_test-1.15.1 compiler-7.1 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.2 cosTime-1.2.2 cosTransactions-1.3.2 crypto-4.0 debugger-4.2.2 dialyzer-3.2 diameter-2.0 edoc-0.9 eldap-1.2.2 erl_docgen-0.7 erl_interface-3.10 et-1.6 eunit-2.3.3 hipe-3.16 ic-4.4.2 inets-6.4 jinterface-1.8 megaco-3.18.2 mnesia-4.15 observer-2.4 odbc-2.12 orber-3.8.3 os_mon-2.4.2 otp_mibs-1.1.1 parsetools-2.1.5 public_key-1.4.1 reltool-0.7.4 runtime_tools-1.12.1 sasl-3.0.4 snmp-5.2.6 ssh-4.5 ssl-8.2 stdlib-3.4.1 syntax_tools-2.1.2 tools-2.10.1 wx-1.8.1 xmerl-1.3.15 :
OTP-20.0.1 : common_test-1.15.1 erts-9.0.1 runtime_tools-1.12.1 stdlib-3.4.1 tools-2.10.1 # asn1-5.0 compiler-7.1 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.2 cosTime-1.2.2 cosTransactions-1.3.2 crypto-4.0 debugger-4.2.2 dialyzer-3.2 diameter-2.0 edoc-0.9 eldap-1.2.2 erl_docgen-0.7 erl_interface-3.10 et-1.6 eunit-2.3.3 hipe-3.16 ic-4.4.2 inets-6.4 jinterface-1.8 kernel-5.3 megaco-3.18.2 mnesia-4.15 observer-2.4 odbc-2.12 orber-3.8.3 os_mon-2.4.2 otp_mibs-1.1.1 parsetools-2.1.5 public_key-1.4.1 reltool-0.7.4 sasl-3.0.4 snmp-5.2.6 ssh-4.5 ssl-8.2 syntax_tools-2.1.2 wx-1.8.1 xmerl-1.3.15 :
OTP-20.0 : asn1-5.0 common_test-1.15 compiler-7.1 cosProperty-1.2.2 crypto-4.0 debugger-4.2.2 dialyzer-3.2 diameter-2.0 edoc-0.9 erl_docgen-0.7 erl_interface-3.10 erts-9.0 eunit-2.3.3 hipe-3.16 inets-6.4 jinterface-1.8 kernel-5.3 megaco-3.18.2 mnesia-4.15 observer-2.4 orber-3.8.3 parsetools-2.1.5 public_key-1.4.1 reltool-0.7.4 runtime_tools-1.12 sasl-3.0.4 snmp-5.2.6 ssh-4.5 ssl-8.2 stdlib-3.4 syntax_tools-2.1.2 tools-2.10 wx-1.8.1 xmerl-1.3.15 # cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosTime-1.2.2 cosTransactions-1.3.2 eldap-1.2.2 et-1.6 ic-4.4.2 odbc-2.12 os_mon-2.4.2 otp_mibs-1.1.1 :
+OTP-19.3.6.10 : erts-8.3.5.5 syntax_tools-2.1.1.1 # asn1-4.0.4 common_test-1.14 compiler-7.0.4.1 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 crypto-3.7.4 debugger-4.2.1 dialyzer-3.1.1 diameter-1.12.2 edoc-0.8.1 eldap-1.2.2 erl_docgen-0.6.1 erl_interface-3.9.3 et-1.6 eunit-2.3.2 gs-1.6.2 hipe-3.15.4 ic-4.4.2 inets-6.3.9 jinterface-1.7.1 kernel-5.2.0.1 megaco-3.18.1 mnesia-4.14.3.1 observer-2.3.1 odbc-2.12 orber-3.8.2 os_mon-2.4.2 otp_mibs-1.1.1 parsetools-2.1.4 percept-0.9 public_key-1.4 reltool-0.7.3 runtime_tools-1.11.1 sasl-3.0.3 snmp-5.2.5 ssh-4.4.2.4 ssl-8.1.3.1.1 stdlib-3.3 tools-2.9.1 typer-0.9.12 wx-1.8 xmerl-1.3.14 :
OTP-19.3.6.9 : ssh-4.4.2.4 # asn1-4.0.4 common_test-1.14 compiler-7.0.4.1 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 crypto-3.7.4 debugger-4.2.1 dialyzer-3.1.1 diameter-1.12.2 edoc-0.8.1 eldap-1.2.2 erl_docgen-0.6.1 erl_interface-3.9.3 erts-8.3.5.4 et-1.6 eunit-2.3.2 gs-1.6.2 hipe-3.15.4 ic-4.4.2 inets-6.3.9 jinterface-1.7.1 kernel-5.2.0.1 megaco-3.18.1 mnesia-4.14.3.1 observer-2.3.1 odbc-2.12 orber-3.8.2 os_mon-2.4.2 otp_mibs-1.1.1 parsetools-2.1.4 percept-0.9 public_key-1.4 reltool-0.7.3 runtime_tools-1.11.1 sasl-3.0.3 snmp-5.2.5 ssl-8.1.3.1.1 stdlib-3.3 syntax_tools-2.1.1 tools-2.9.1 typer-0.9.12 wx-1.8 xmerl-1.3.14 :
OTP-19.3.6.8 : ssh-4.4.2.3 # asn1-4.0.4 common_test-1.14 compiler-7.0.4.1 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 crypto-3.7.4 debugger-4.2.1 dialyzer-3.1.1 diameter-1.12.2 edoc-0.8.1 eldap-1.2.2 erl_docgen-0.6.1 erl_interface-3.9.3 erts-8.3.5.4 et-1.6 eunit-2.3.2 gs-1.6.2 hipe-3.15.4 ic-4.4.2 inets-6.3.9 jinterface-1.7.1 kernel-5.2.0.1 megaco-3.18.1 mnesia-4.14.3.1 observer-2.3.1 odbc-2.12 orber-3.8.2 os_mon-2.4.2 otp_mibs-1.1.1 parsetools-2.1.4 percept-0.9 public_key-1.4 reltool-0.7.3 runtime_tools-1.11.1 sasl-3.0.3 snmp-5.2.5 ssl-8.1.3.1.1 stdlib-3.3 syntax_tools-2.1.1 tools-2.9.1 typer-0.9.12 wx-1.8 xmerl-1.3.14 :
OTP-19.3.6.7 : kernel-5.2.0.1 # asn1-4.0.4 common_test-1.14 compiler-7.0.4.1 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 crypto-3.7.4 debugger-4.2.1 dialyzer-3.1.1 diameter-1.12.2 edoc-0.8.1 eldap-1.2.2 erl_docgen-0.6.1 erl_interface-3.9.3 erts-8.3.5.4 et-1.6 eunit-2.3.2 gs-1.6.2 hipe-3.15.4 ic-4.4.2 inets-6.3.9 jinterface-1.7.1 megaco-3.18.1 mnesia-4.14.3.1 observer-2.3.1 odbc-2.12 orber-3.8.2 os_mon-2.4.2 otp_mibs-1.1.1 parsetools-2.1.4 percept-0.9 public_key-1.4 reltool-0.7.3 runtime_tools-1.11.1 sasl-3.0.3 snmp-5.2.5 ssh-4.4.2.2 ssl-8.1.3.1.1 stdlib-3.3 syntax_tools-2.1.1 tools-2.9.1 typer-0.9.12 wx-1.8 xmerl-1.3.14 :
diff --git a/scripts/build-otp b/scripts/build-otp
index 92031c79c8..abf8d5d67f 100755
--- a/scripts/build-otp
+++ b/scripts/build-otp
@@ -1,5 +1,7 @@
#!/bin/bash
+set -e
+
function progress {
local file=$1
ls=$(ls -l $file)
@@ -14,15 +16,19 @@ function progress {
}
function do_and_log {
+ start_time=`date +%s`
log="logs/latest-log.$$"
echo "" >$log
echo -n "$1..."
(progress $log) &
pid=$!
disown
- if ./otp_build $2 $3 >$log 2>&1; then
+ shift
+ if $* >$log 2>&1; then
kill $pid >/dev/null 2>&1
- echo " done."
+ stop_time=`date +%s`
+ diff_time=$((stop_time-start_time))
+ echo " done, took $diff_time seconds"
else
kill $pid >/dev/null 2>&1
echo " failed."
@@ -36,8 +42,38 @@ if [ ! -d "logs" ]; then
mkdir logs
fi
-do_and_log "Autoconfing" autoconf
-do_and_log "Configuring" configure
-do_and_log "Building OTP" boot -a
+do_and_log "Autoconfing" ./otp_build autoconf
+do_and_log "Configuring" ./otp_build configure
+do_and_log "Building OTP" ./otp_build boot -a
+
+if [ "$1" = "release" ]; then
+ do_and_log "Releasing OTP" ./otp_build release -a
+fi
+
+if [ "$1" = "docs" ]; then
+ DOC_TARGET=${TRAVIS_BRANCH:-release/`erts/autoconf/config.guess`}
+ DOC_TARGET=${TRAVIS_TAG:-$DOC_TARGET}
+ TESTROOT=$PWD/$DOC_TARGET do_and_log "Building documentation" make release_docs
+ do_and_log "Linting documentation" make xmllint
+ # The code below prepares this build to be used as a deploy to
+ # github pages for documentation.
+ if [ "$TRAVIS_PULL_REQUEST" = "false" -a "$TRAVIS_TAG" = "" -a "$TRAVIS_REPO_SLUG" = "erlang/otp" ]; then
+ set -x
+ rm -rf logs
+ SHA=`git rev-parse --verify HEAD`
+ DATE=`git show -s --format=%ci`
+ git clean -xfdq -e $DOC_TARGET
+ git fetch https://github.com/erlang/cd master
+ git checkout -f FETCH_HEAD
+ rm -rf _docs/$DOC_TARGET
+ mv $DOC_TARGET _docs/$DOC_TARGET
+ echo "---" > _docs/$DOC_TARGET.md
+ echo "title: $DOC_TARGET" >> _docs/$DOC_TARGET.md
+ echo "sha: $SHA" >> _docs/$DOC_TARGET.md
+ echo "generated: $DATE" >> _docs/$DOC_TARGET.md
+ echo "---" >> _docs/$DOC_TARGET.md
+ set +x
+ fi
+fi
exit 0
diff --git a/scripts/bundle-otp b/scripts/bundle-otp
new file mode 100755
index 0000000000..aa1f166732
--- /dev/null
+++ b/scripts/bundle-otp
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+set -e
+
+if [ "$TRAVIS_PULL_REQUEST" = "false" -a "$TRAVIS_REPO_SLUG" != "erlang/otp" ]; then
+ exit 0
+fi
+
+OTP_META_FILE=$ERL_TOP/${TRAVIS_TAG}-bundle.txt
+OTP_FILE=$ERL_TOP/${TRAVIS_TAG}-bundle.tar.gz
+
+REPOSITORIES="otp,$TRAVIS_TAG corba,.*"
+
+mkdir bundle
+
+## Turn off * expansion, needed for the .* regexp to work
+set -f
+
+for repo in $REPOSITORIES; do
+ OLD_IFS=$IFS
+ IFS=','
+ set -- $repo
+ IFS=$OLD_IFS
+ cd $ERL_TOP/bundle/
+ git clone https://github.com/erlang/$1 $1
+ cd $1
+ echo $1 $2
+ TAG=`git tag -l | grep -P "^$2$" | sort -V | tail -1`
+ git checkout $TAG
+ SHA=`git rev-parse --verify HEAD`
+ rm -rf .git
+ echo "$1 $TAG $SHA" >> $OTP_META_FILE
+done
+
+## Turn on * expansion
+set +f
+
+cd $ERL_TOP/bundle/
+tar czf $OTP_FILE *
+
+exit 0
diff --git a/scripts/diffable b/scripts/diffable
index 08d2d5cb35..6a9792e857 100755
--- a/scripts/diffable
+++ b/scripts/diffable
@@ -117,16 +117,25 @@ get_files(Apps, #{}=Opts) ->
{Files,Opts}.
add_opts([F|Fs], Opts0) ->
- Opts = case filename:basename(F) of
- "group_history.erl" ->
+ Opts = case vsn_is_harmful(F) of
+ true ->
Opts0 -- [{d,'VSN',1}];
- _ ->
+ false ->
Opts0
end,
[{F,Opts}|add_opts(Fs, Opts0)];
add_opts([], _Opts) ->
[].
+vsn_is_harmful(F) ->
+ case filename:basename(F) of
+ "group_history.erl" ->
+ true;
+ _ ->
+ App = filename:basename(filename:dirname(filename:dirname(F))),
+ App =:= "ssl"
+ end.
+
get_src(["preloaded"|Apps]) ->
WC = filename:join(code:root_dir(), "erts/preloaded/src/*.erl"),
filelib:wildcard(WC) ++ get_src(Apps);
diff --git a/scripts/pre-push b/scripts/pre-push
index 0349378056..71e9fd1e75 100755
--- a/scripts/pre-push
+++ b/scripts/pre-push
@@ -22,15 +22,30 @@
# <local ref> <local sha1> <remote ref> <remote sha1>
#
-RELEASES="20 19 18 17 r16 r15 r14 r13"
+NEW_RELEASES="21 20 19 18 17"
+OLD_RELEASES="r16 r15 r14 r13"
+RELEASES="$NEW_RELEASES $OLD_RELEASES"
# First commit on master, not allowed in other branches
-MASTER_ONLY=f52748254f17ba42e344798e8c787a1e3361fa33
+MASTER_ONLY=aea2a053e28a11497796879715be29ab0c3cd1a0
# Number of commits and files allowed in one push by this script
NCOMMITS_MAX=100
NFILES_MAX=100
+
+# Example testing this script for "git push upstream OTP-20.3.8.2":
+#
+#> null=0000000000000000000000000000000000000000
+#> echo "refs/tags/OTP-20.3.8.2 dummysha refs/tags/OTP-20.3.8.2 $null" | scripts/pre-push upstream https://github.com/erlang/otp.git
+
+# Example to test "git push upstream master"
+#
+#> local_sha=`git rev-parse master`
+#> remote_sha=`git rev-parse upstream/master`
+#> echo "refs/heads/master $local_sha refs/heads/master $remote_sha" | scripts/pre-push upstream https://github.com/erlang/otp.git
+
+
remote="$1"
url="$2"
@@ -158,8 +173,24 @@ then
exit 1
fi
;;
- refs/tags/OTP-20.* | refs/tags/OTP-19.* | refs/tags/OTP-18.* | refs/tags/OTP-17.*)
+ refs/tags/OTP-*)
tag=${remote_ref#refs/tags/}
+ REL="UNKNOWN"
+ for x in $NEW_RELEASES; do
+ if [ ${tag#OTP-$x.} != $tag ]
+ then
+ REL=$x
+ break
+ fi
+ done
+ if [ $REL = "UNKNOWN" ]
+ then
+ echo "$0 says:"
+ echo "***"
+ echo "*** Unknown OTP release number in tag '$tag'"
+ echo "***"
+ exit 1
+ fi
if [ "$remote_sha" != $null ]
then
echo "$0 says:"
diff --git a/scripts/run-dialyzer b/scripts/run-dialyzer
index c9da647952..621de3fa65 100755
--- a/scripts/run-dialyzer
+++ b/scripts/run-dialyzer
@@ -1,16 +1,17 @@
#!/bin/bash
set -e
+set -x
$ERL_TOP/bin/dialyzer --build_plt --apps asn1 compiler crypto dialyzer edoc erts et ftp hipe inets kernel mnesia observer public_key runtime_tools snmp ssh ssl stdlib syntax_tools tftp wx xmerl --statistics
$ERL_TOP/bin/dialyzer -n -Wunknown -Wunmatched_returns --apps compiler erts ftp tftp kernel stdlib asn1 crypto dialyzer hipe parsetools public_key runtime_tools sasl tools --statistics
$ERL_TOP/bin/dialyzer -n --apps common_test debugger edoc ftp inets mnesia observer ssh ssl syntax_tools tftp wx xmerl --statistics
# In travis we don't dialyze everything as it takes too much time
-if [ "X$DIALYZE_ALL_APPLICATIONS" = "Xtrue" ]; then
+if [ "X$TRAVIS" != "Xtrue" ]; then
$ERL_TOP/bin/dialyzer -n -Wunknown -Wunmatched_returns --apps eldap erl_docgen et odbc --statistics
$ERL_TOP/bin/dialyzer -n --apps eunit reltool os_mon --statistics
# These application are not run always as the currently have dialyzer warnings
- # $ERL_TOP/bin/dialyzer -n --apps cosEvent cosEventDomain cosFileTransfer cosNotification cosProperty cosTime cosTransactions diameter megaco orber snmp --statistics
+ # $ERL_TOP/bin/dialyzer -n --apps diameter megaco snmp --statistics
fi
diff --git a/system/doc/design_principles/Makefile b/system/doc/design_principles/Makefile
index 41d2d1208f..242bf1c9a4 100644
--- a/system/doc/design_principles/Makefile
+++ b/system/doc/design_principles/Makefile
@@ -108,6 +108,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)
+ rm -rf $(XMLDIR)
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/design_principles/applications.xml b/system/doc/design_principles/applications.xml
index c673fde07e..3b7b8fdaee 100644
--- a/system/doc/design_principles/applications.xml
+++ b/system/doc/design_principles/applications.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -363,9 +363,13 @@ ok
application are running.</p>
<marker id="application_master"></marker>
<p>The application controller then creates an
- <em>application master</em> for the application. The application master
- is the group leader of all the processes in the application.
- The application master starts the application by calling
+ <em>application master</em> for the application. The application
+ master becomes the group leader of all the processes in the
+ application. I/O is forwarded to the previous group leader,
+ though, this is just a way to identify processes that belong to
+ the application. Used for example to find itself from any process,
+ or, reciprocally, to kill them all when it terminates.</p>
+ <p>The application master starts the application by calling
the application callback function <c>start/2</c> in the module,
and with the start argument, defined by the <c>mod</c> key in
the <c>.app</c> file.</p>
diff --git a/system/doc/design_principles/gen_server_concepts.xml b/system/doc/design_principles/gen_server_concepts.xml
index 3a1f876646..06413a3d93 100644
--- a/system/doc/design_principles/gen_server_concepts.xml
+++ b/system/doc/design_principles/gen_server_concepts.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/system/doc/design_principles/release_structure.xml b/system/doc/design_principles/release_structure.xml
index 8e62ba845f..e8dfcad805 100644
--- a/system/doc/design_principles/release_structure.xml
+++ b/system/doc/design_principles/release_structure.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2016</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/system/doc/design_principles/spec_proc.xml b/system/doc/design_principles/spec_proc.xml
index f910c3dba3..65f5492bdd 100644
--- a/system/doc/design_principles/spec_proc.xml
+++ b/system/doc/design_principles/spec_proc.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml
index 80ee9c992f..98fd1fd69d 100644
--- a/system/doc/design_principles/statem.xml
+++ b/system/doc/design_principles/statem.xml
@@ -956,14 +956,14 @@ callback_mode() ->
<seealso marker="stdlib:gen_statem#cast/2"><c>gen_statem:cast/2</c></seealso>:
</p>
<code type="erl"><![CDATA[
-button(Digit) ->
- gen_statem:cast(?NAME, {button,Digit}).
+button(Button) ->
+ gen_statem:cast(?NAME, {button,Button}).
]]></code>
<p>
The first argument is the name of the <c>gen_statem</c> and must
agree with the name used to start it. So, we use the
same macro <c>?NAME</c> as when starting.
- <c>{button,Digit}</c> is the event content.
+ <c>{button,Button}</c> is the event content.
</p>
<p>
The event is sent to the <c>gen_statem</c>.
@@ -1171,7 +1171,7 @@ open(...) -> ... ;
callback_mode() ->
handle_event_function.
-handle_event(cast, {button,Digit}, State, #{code := Code} = Data) ->
+handle_event(cast, {button,Button}, State, #{code := Code} = Data) ->
case State of
locked ->
#{length := Length, buttons := Buttons} = Data,
@@ -1305,7 +1305,7 @@ stop() ->
locked(timeout, _, Data) ->
{next_state, locked, Data#{buttons := []}};
locked(
- cast, {button,Digit},
+ cast, {button,Button},
#{code := Code, length := Length, buttons := Buttons} = Data) ->
...
true -> % Incomplete | Incorrect
@@ -1364,7 +1364,7 @@ locked(
<code type="erl"><![CDATA[
...
locked(
- cast, {button,Digit},
+ cast, {button,Button},
#{code := Code, length := Length, buttons := Buttons} = Data) ->
...
if
@@ -1410,7 +1410,7 @@ open(cast, {button,_}, Data) ->
<seealso marker="erts:erlang#start_timer/4"><c>erlang:start_timer/3,4</c></seealso>.
Most time-out tasks can be performed with the
time-out features in <c>gen_statem</c>,
- but an example of one that can not is if you should need
+ but an example of one that cannot is if you should need
the return value from
<seealso marker="erts:erlang#cancel_timer/2"><c>erlang:cancel_timer(Tref)</c></seealso>, that is; the remaining time of the timer.
</p>
@@ -1421,7 +1421,7 @@ open(cast, {button,_}, Data) ->
<code type="erl"><![CDATA[
...
locked(
- cast, {button,Digit},
+ cast, {button,Button},
#{code := Code, length := Length, buttons := Buttons} = Data) ->
...
if
@@ -1662,7 +1662,7 @@ locked(enter, _OldState, Data) ->
do_lock(),
{keep_state,Data#{buttons => []}};
locked(
- cast, {button,Digit},
+ cast, {button,Button},
#{code := Code, length := Length, buttons := Buttons} = Data) ->
...
if
@@ -1747,7 +1747,7 @@ open(state_timeout, lock, Data) ->
</p>
<code type="erl"><![CDATA[
...
--export(down/1, up/1).
+-export([down/1, up/1]).
...
down(Button) ->
gen_statem:cast(?NAME, {down,Button}).
@@ -1759,15 +1759,15 @@ up(Button) ->
locked(enter, _OldState, Data) ->
do_lock(),
- {keep_state,Data#{remaining => Code, buf => []}};
+ {keep_state,Data#{buttons => []}};
locked(
- internal, {button,Digit},
+ internal, {button,Button},
#{code := Code, length := Length, buttons := Buttons} = Data) ->
...
]]></code>
<code type="erl"><![CDATA[
handle_common(cast, {down,Button}, Data) ->
- {keep_state, Data#{button := Button}};
+ {keep_state, Data#{button => Button}};
handle_common(cast, {up,Button}, Data) ->
case Data of
#{button := Button} ->
@@ -1833,10 +1833,10 @@ start_link(Code) ->
stop() ->
gen_statem:stop(?NAME).
-down(Digit) ->
- gen_statem:cast(?NAME, {down,Digit}).
-up(Digit) ->
- gen_statem:cast(?NAME, {up,Digit}).
+down(Button) ->
+ gen_statem:cast(?NAME, {down,Button}).
+up(Button) ->
+ gen_statem:cast(?NAME, {up,Button}).
code_length() ->
gen_statem:call(?NAME, code_length).
]]></code>
@@ -1873,7 +1873,7 @@ locked(enter, _OldState, Data) ->
locked(state_timeout, button, Data) ->
{keep_state, Data#{buttons := []}};
locked(
- internal, {button,Digit},
+ internal, {button,Button},
#{code := Code, length := Length, buttons := Buttons} = Data) ->
NewButtons =
if
@@ -1884,7 +1884,6 @@ locked(
end ++ [Button],
if
NewButtons =:= Code -> % Correct
- do_unlock(),
{next_state, open, Data};
true -> % Incomplete | Incorrect
{keep_state, Data#{buttons := NewButtons},
@@ -1940,7 +1939,7 @@ handle_event(enter, _OldState, locked, Data) ->
handle_event(state_timeout, button, locked, Data) ->
{keep_state, Data#{buttons := []}};
handle_event(
- internal, {button,Digit}, locked,
+ internal, {button,Button}, locked,
#{code := Code, length := Length, buttons := Buttons} = Data) ->
NewButtons =
if
@@ -1951,7 +1950,6 @@ handle_event(
end ++ [Button],
if
NewButtons =:= Code -> % Correct
- do_unlock(),
{next_state, open, Data};
true -> % Incomplete | Incorrect
{keep_state, Data#{buttons := NewButtons},
@@ -2152,7 +2150,7 @@ handle_event(enter, _OldState, {locked,_}, Data) ->
handle_event(state_timeout, button, {locked,_}, Data) ->
{keep_state, Data#{buttons := []}};
handle_event(
- cast, {button,Digit}, {locked,LockButton},
+ cast, {button,Button}, {locked,LockButton},
#{code := Code, length := Length, buttons := Buttons} = Data) ->
NewButtons =
if
@@ -2163,7 +2161,6 @@ handle_event(
end ++ [Button],
if
NewButtons =:= Code -> % Correct
- do_unlock(),
{next_state, {open,LockButton}, Data};
true -> % Incomplete | Incorrect
{keep_state, Data#{buttons := NewButtons},
@@ -2177,11 +2174,11 @@ handle_event(enter, _OldState, {open,_}, _Data) ->
do_unlock(),
{keep_state_and_data,
[{state_timeout,10000,lock}]}; % Time in milliseconds
-handle_event(state_timeout, lock, {open,_}, Data) ->
- {next_state, locked, Data};
+handle_event(state_timeout, lock, {open,LockButton}, Data) ->
+ {next_state, {locked,LockButton}, Data};
handle_event(cast, {button,LockButton}, {open,LockButton}, Data) ->
{next_state, {locked,LockButton}, Data};
-handle_event(cast, {button,_}, {open,_}, Data) ->
+handle_event(cast, {button,_}, {open,_}, _Data) ->
{keep_state_and_data,[postpone]};
]]></code>
<code type="erl"><![CDATA[
diff --git a/system/doc/efficiency_guide/Makefile b/system/doc/efficiency_guide/Makefile
index b1630a36e1..72bcd2ee73 100644
--- a/system/doc/efficiency_guide/Makefile
+++ b/system/doc/efficiency_guide/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2001-2016. All Rights Reserved.
+# Copyright Ericsson AB 2001-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -99,6 +99,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)
+ rm -rf $(XMLDIR)
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/efficiency_guide/advanced.xml b/system/doc/efficiency_guide/advanced.xml
index 21d4a66d77..fe77ce8ea4 100644
--- a/system/doc/efficiency_guide/advanced.xml
+++ b/system/doc/efficiency_guide/advanced.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2001</year><year>2016</year>
+ <year>2001</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -188,11 +188,6 @@
limit can be raised or lowered using the <c>+t</c> option.</cell>
</row>
<row>
- <cell>Ets tables</cell>
- <cell>Default is 1400. It can be changed with the environment
- variable <c>ERL_MAX_ETS_TABLES</c>.</cell>
- </row>
- <row>
<cell>Elements in a tuple</cell>
<cell>The maximum number of elements in a tuple is 16,777,215
(24-bit unsigned integer).</cell>
diff --git a/system/doc/efficiency_guide/binaryhandling.xml b/system/doc/efficiency_guide/binaryhandling.xml
index d07ff1325f..b500329ef9 100644
--- a/system/doc/efficiency_guide/binaryhandling.xml
+++ b/system/doc/efficiency_guide/binaryhandling.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2007</year>
- <year>2017</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/system/doc/efficiency_guide/profiling.xml b/system/doc/efficiency_guide/profiling.xml
index f185456158..cdc80289cf 100644
--- a/system/doc/efficiency_guide/profiling.xml
+++ b/system/doc/efficiency_guide/profiling.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2001</year><year>2016</year>
+ <year>2001</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/system/doc/efficiency_guide/xmlfiles.mk b/system/doc/efficiency_guide/xmlfiles.mk
index 23c0d991b4..e275823dd1 100644
--- a/system/doc/efficiency_guide/xmlfiles.mk
+++ b/system/doc/efficiency_guide/xmlfiles.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009-2016. All Rights Reserved.
+# Copyright Ericsson AB 2009-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/system/doc/embedded/Makefile b/system/doc/embedded/Makefile
index 23d3168e34..396aef276b 100644
--- a/system/doc/embedded/Makefile
+++ b/system/doc/embedded/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -87,6 +87,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)
+ rm -rf $(XMLDIR)
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/embedded/starting.xml b/system/doc/embedded/starting.xml
index 11bf9b412a..6888f9c959 100644
--- a/system/doc/embedded/starting.xml
+++ b/system/doc/embedded/starting.xml
@@ -231,7 +231,7 @@ exec $BINDIR/erlexec -boot $RELDIR/$VSN/start -config $RELDIR/$VSN/sys $* <
<p>If a diskless and/or read-only client node with the SASL
configuration parameter <c>static_emulator</c> set to <c>true</c>
is about to start the <c>-boot</c> and <c>-config</c> flags must be
- changed. As such a client can not read a new <c>start_erl.data</c>
+ changed. As such a client cannot read a new <c>start_erl.data</c>
file (the file is not possible to change dynamically) the boot and
config files is always fetched from the same place (but with a new
contents if a new release has been installed). The
diff --git a/system/doc/getting_started/Makefile b/system/doc/getting_started/Makefile
index 13d767daf5..cdf1e121c2 100644
--- a/system/doc/getting_started/Makefile
+++ b/system/doc/getting_started/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2016. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -86,6 +86,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)
+ rm -rf $(XMLDIR)
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/getting_started/conc_prog.xml b/system/doc/getting_started/conc_prog.xml
index dc378dd582..4374a59e04 100644
--- a/system/doc/getting_started/conc_prog.xml
+++ b/system/doc/getting_started/conc_prog.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2017</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/system/doc/installation_guide/Makefile b/system/doc/installation_guide/Makefile
index 002c2a536a..4a1335cf31 100644
--- a/system/doc/installation_guide/Makefile
+++ b/system/doc/installation_guide/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2016. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -113,6 +113,7 @@ debug opt:
clean clean_docs:
rm -f $(GENERATED_XML_FILES)
rm -rf $(HTMLDIR)
+ rm -rf $(XMLDIR)
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/installation_guide/xmlfiles.mk b/system/doc/installation_guide/xmlfiles.mk
index 37fbeca96b..f005c8404b 100644
--- a/system/doc/installation_guide/xmlfiles.mk
+++ b/system/doc/installation_guide/xmlfiles.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009-2016. All Rights Reserved.
+# Copyright Ericsson AB 2009-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/system/doc/oam/Makefile b/system/doc/oam/Makefile
index dfebc6aca0..147f56f885 100644
--- a/system/doc/oam/Makefile
+++ b/system/doc/oam/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -88,6 +88,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)
+ rm -rf $(XMLDIR)
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/programming_examples/Makefile b/system/doc/programming_examples/Makefile
index af731f85b4..e4737ba069 100644
--- a/system/doc/programming_examples/Makefile
+++ b/system/doc/programming_examples/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2016. All Rights Reserved.
+# Copyright Ericsson AB 2003-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -85,6 +85,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)
+ rm -rf $(XMLDIR)
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/programming_examples/xmlfiles.mk b/system/doc/programming_examples/xmlfiles.mk
index 20b08d8cd3..e457ca0cce 100644
--- a/system/doc/programming_examples/xmlfiles.mk
+++ b/system/doc/programming_examples/xmlfiles.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009-2016. All Rights Reserved.
+# Copyright Ericsson AB 2009-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/system/doc/reference_manual/Makefile b/system/doc/reference_manual/Makefile
index 75c15e4b5f..d034ad2ff8 100644
--- a/system/doc/reference_manual/Makefile
+++ b/system/doc/reference_manual/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2016. All Rights Reserved.
+# Copyright Ericsson AB 2003-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -96,6 +96,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)
+ rm -rf $(XMLDIR)
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/reference_manual/expressions.xml b/system/doc/reference_manual/expressions.xml
index 94e40dd077..1f48233c39 100644
--- a/system/doc/reference_manual/expressions.xml
+++ b/system/doc/reference_manual/expressions.xml
@@ -567,6 +567,10 @@ Expr1 <input>op</input> Expr2</pre>
order is defined:</p>
<pre>
number &lt; atom &lt; reference &lt; fun &lt; port &lt; pid &lt; tuple &lt; map &lt; nil &lt; list &lt; bit string</pre>
+ <p><c>nil</c> in the previous expression represents the empty list
+ (<c>[]</c>), which is regarded as a separate type from
+ <c>list/0</c>. That is why <c>nil &lt; list</c>.
+ </p>
<p>Lists are compared element by element. Tuples are ordered by
size, two tuples with the same size are compared element by
element.</p>
@@ -574,6 +578,7 @@ number &lt; atom &lt; reference &lt; fun &lt; port &lt; pid &lt; tuple &lt; map
ascending term order and then by values in key order.
In maps key order integers types are considered less than floats types.
</p>
+ <p>Atoms are compared using their string value, codepoint by codepoint.</p>
<p>When comparing an integer to a float, the term with the lesser
precision is converted into the type of the other term, unless the
operator is one of <c>=:=</c> or <c>=/=</c>. A float is more precise than
diff --git a/system/doc/reference_manual/introduction.xml b/system/doc/reference_manual/introduction.xml
index afbdfa7434..69e52e0b37 100644
--- a/system/doc/reference_manual/introduction.xml
+++ b/system/doc/reference_manual/introduction.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2017</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -48,7 +48,7 @@
System Principles</seealso></p>
<p>Starting and stopping, boot scripts, code loading,
<seealso marker="doc/system_principles:error_logging">
- error logging</seealso>,
+ logging</seealso>,
<seealso marker="doc/system_principles:create_target">
creating target systems</seealso></p>
</item>
diff --git a/system/doc/reference_manual/macros.xml b/system/doc/reference_manual/macros.xml
index a341307ab7..8a8d5f3a4c 100644
--- a/system/doc/reference_manual/macros.xml
+++ b/system/doc/reference_manual/macros.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2017</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -150,6 +150,11 @@ bar(X) ->
<item>The name of the current function.</item>
<tag><c>?FUNCTION_ARITY</c></tag>
<item>The arity (number of arguments) for the current function.</item>
+ <tag><c>?OTP_RELEASE</c></tag>
+ <item>The OTP release that the currently executing ERTS
+ application is part of, as an integer. For details, see
+ <seealso marker="erts:erlang#system_info/1"><c>erlang:system_info(otp_release)</c></seealso>.
+ This macro was introduced in OTP release 21.</item>
</taglist>
</section>
@@ -202,8 +207,16 @@ f() ->
directive. If that condition is false, the lines following
<c>else</c> are evaluated instead.</item>
<tag><c>-endif.</c></tag>
- <item>Specifies the end of an <c>ifdef</c> or <c>ifndef</c>
- directive.</item>
+ <item>Specifies the end of an <c>ifdef</c>, an <c>ifndef</c>
+ directive, or the end of an <c>if</c> or <c>elif</c> directive.</item>
+ <tag><c>-if(Condition).</c></tag>
+ <item>Evaluates the following lines only if <c>Condition</c>
+ evaluates to true.</item>
+ <tag><c>-elif(Condition).</c></tag>
+ <item>Only allowed after an <c>if</c> or another <c>elif</c> directive.
+ If the preceding <c>if</c> or <c>elif</c> directives do not
+ evaluate to true, and the <c>Condition</c> evaluates to true,
+ the lines following the <c>elif</c> are evaluated instead.</item>
</taglist>
<note>
<p>The macro directives cannot be used inside functions.</p>
@@ -231,6 +244,24 @@ or
{ok,m}</pre>
<p><c>?LOG(Arg)</c> is then expanded to a call to <c>io:format/2</c>
and provide the user with some simple trace output.</p>
+
+ <p><em>Example:</em></p>
+ <code type="none">
+-module(m)
+...
+-ifdef(OTP_RELEASE).
+ %% OTP 21 or higher
+ -if(?OTP_RELEASE >= 22).
+ %% Code that will work in OTP 22 or higher
+ -elif(?OTP_RELEASE >= 21).
+ %% Code that will work in OTP 21 or higher
+ -endif.
+-else.
+ %% OTP 20 or lower.
+-endif.
+...</code>
+ <p>The code uses the <c>OTP_RELEASE</c> macro to conditionally
+ select code depending on release.</p>
</section>
<section>
diff --git a/system/doc/reference_manual/modules.xml b/system/doc/reference_manual/modules.xml
index 7dc71eb307..6f93198ec1 100644
--- a/system/doc/reference_manual/modules.xml
+++ b/system/doc/reference_manual/modules.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2017</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/system/doc/reference_manual/xmlfiles.mk b/system/doc/reference_manual/xmlfiles.mk
index fffcbdd911..92d232b628 100644
--- a/system/doc/reference_manual/xmlfiles.mk
+++ b/system/doc/reference_manual/xmlfiles.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009-2016. All Rights Reserved.
+# Copyright Ericsson AB 2009-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/system/doc/system_architecture_intro/Makefile b/system/doc/system_architecture_intro/Makefile
index 7a10f305ba..eb885a744d 100644
--- a/system/doc/system_architecture_intro/Makefile
+++ b/system/doc/system_architecture_intro/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -81,6 +81,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)
+ rm -rf $(XMLDIR)
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/system_architecture_intro/sys_arch_intro.xml b/system/doc/system_architecture_intro/sys_arch_intro.xml
index bf7659765f..e8ada6427b 100644
--- a/system/doc/system_architecture_intro/sys_arch_intro.xml
+++ b/system/doc/system_architecture_intro/sys_arch_intro.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2000</year><year>2016</year>
+ <year>2000</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/system/doc/system_principles/Makefile b/system/doc/system_principles/Makefile
index ec6591ec6b..1979deda4c 100644
--- a/system/doc/system_principles/Makefile
+++ b/system/doc/system_principles/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2016. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -82,6 +82,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)
+ rm -rf $(XMLDIR)
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/system_principles/create_target.xmlsrc b/system/doc/system_principles/create_target.xmlsrc
index dc6cbbe980..47b84e5760 100644
--- a/system/doc/system_principles/create_target.xmlsrc
+++ b/system/doc/system_principles/create_target.xmlsrc
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2002</year><year>2016</year>
+ <year>2002</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/system/doc/system_principles/error_logging.xml b/system/doc/system_principles/error_logging.xml
index c99d59ddb7..9cbf7a2e94 100644
--- a/system/doc/system_principles/error_logging.xml
+++ b/system/doc/system_principles/error_logging.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2016</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -39,80 +39,71 @@
<code type="none"><![CDATA[
=ERROR REPORT==== 9-Dec-2003::13:25:02 ===
Error in process <0.27.0> with exit value: {{badmatch,[1,2,3]},[{m,f,1},{shell,eval_loop,2}]}]]></code>
- <p>The error information is handled by the <em>error logger</em>, a
- system process registered as <c>error_logger</c>. This process
- receives all error messages from the Erlang runtime system as
- well as from the standard behaviours and different Erlang/OTP
- applications.</p>
+ <p>The error information is handled by Logger, which is part of
+ the Kernel application.</p>
<p>The exit reasons (such as <c>badarg</c>) used by
the runtime system are described in
<seealso marker="doc/reference_manual:errors#exit_reasons">
Errors and Error Handling</seealso>.</p>
- <p>For information about the process <c>error_logger</c> and its user
- interface (with the same name), see the
- <seealso marker="kernel:error_logger">error_logger(3)</seealso>
- manual page in Kernel. The system can be configured so that
- error information
- is written to file or to tty, or both. In addition, user-defined
- applications can send and format error information using
- <c>error_logger</c>.</p>
+ <p>For information about Logger and its user
+ interface, see the
+ <seealso marker="kernel:logger">logger(3)</seealso>
+ manual page and
+ the <seealso marker="kernel:logger_chapter">Logging</seealso>
+ section in the Kernel User's Guide. The system can be configured so that
+ log events are
+ written to file or to tty, or both. In addition, user-defined
+ applications can send and format log events using
+ Logger.</p>
</section>
<section>
- <title>SASL Error Logging</title>
+ <title>Log events from OTP behaviours</title>
<p>The standard behaviours (<c>supervisor</c>, <c>gen_server</c>,
- and so on) send progress and error information to <c>error_logger</c>.
- If the SASL application is started, this information is
- written to tty as well. For more information, see
+ and so on) send progress and error information to
+ Logger. Progress reports are by default not logged, but can be
+ enabled by setting the primary log level to <c>info</c>, for
+ example by using the Kernel configuration
+ parameter <c>logger_level</c>. Supervisor reports, crash reports
+ and other error and information reports are by default logged
+ through the log handler which is set up when the Kernel
+ application is started.</p>
+ <p>Prior to Erlang/OTP 21.0, supervisor, crash, and progress
+ reports were only logged when the SASL application was
+ running. This behaviour can, for backwards compatibility, be
+ enabled by setting the Kernel configuration
+ parameter <seealso marker="kernel:kernel_app#logger_sasl_compatible">
+ <c>logger_sasl_compatible</c></seealso>
+ to <c>true</c>. For more information, see
<seealso marker="sasl:error_logging">SASL Error Logging</seealso>
in the SASL User's Guide.</p>
<pre>
-% <input>erl -boot start_sasl</input>
-Erlang (BEAM) emulator version 5.4.13 [hipe] [threads:0] [kernel-poll]
+% <input>erl -kernel logger_level info</input>
+Erlang/OTP 21 [erts-10.0] [source-13c50db] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]
-
-=PROGRESS REPORT==== 31-Mar-2006::12:45:58 ===
- supervisor: {local,sasl_safe_sup}
- started: [{pid,&lt;0.33.0>},
- {name,alarm_handler},
- {mfa,{alarm_handler,start_link,[]}},
- {restart_type,permanent},
- {shutdown,2000},
- {child_type,worker}]
-
-=PROGRESS REPORT==== 31-Mar-2006::12:45:58 ===
- supervisor: {local,sasl_safe_sup}
- started: [{pid,&lt;0.34.0>},
- {name,overload},
- {mfa,{overload,start_link,[]}},
- {restart_type,permanent},
- {shutdown,2000},
- {child_type,worker}]
-
-=PROGRESS REPORT==== 31-Mar-2006::12:45:58 ===
- supervisor: {local,sasl_sup}
- started: [{pid,&lt;0.32.0>},
- {name,sasl_safe_sup},
- {mfa,{supervisor,
- start_link,
- [{local,sasl_safe_sup},sasl,safe]}},
- {restart_type,permanent},
- {shutdown,infinity},
- {child_type,supervisor}]
-
-=PROGRESS REPORT==== 31-Mar-2006::12:45:58 ===
- supervisor: {local,sasl_sup}
- started: [{pid,&lt;0.35.0>},
- {name,release_handler},
- {mfa,{release_handler,start_link,[]}},
- {restart_type,permanent},
- {shutdown,2000},
- {child_type,worker}]
-
-=PROGRESS REPORT==== 31-Mar-2006::12:45:58 ===
- application: sasl
- started_at: nonode@nohost
-Eshell V5.4.13 (abort with ^G)
+=PROGRESS REPORT==== 8-Jun-2018::16:54:19.916404 ===
+ application: kernel
+ started_at: nonode@nohost
+=PROGRESS REPORT==== 8-Jun-2018::16:54:19.922908 ===
+ application: stdlib
+ started_at: nonode@nohost
+=PROGRESS REPORT==== 8-Jun-2018::16:54:19.925755 ===
+ supervisor: {local,kernel_safe_sup}
+ started: [{pid,&lt;0.74.0>},
+ {id,disk_log_sup},
+ {mfargs,{disk_log_sup,start_link,[]}},
+ {restart_type,permanent},
+ {shutdown,1000},
+ {child_type,supervisor}]
+=PROGRESS REPORT==== 8-Jun-2018::16:54:19.926056 ===
+ supervisor: {local,kernel_safe_sup}
+ started: [{pid,&lt;0.75.0>},
+ {id,disk_log_server},
+ {mfargs,{disk_log_server,start_link,[]}},
+ {restart_type,permanent},
+ {shutdown,2000},
+ {child_type,worker}]
+Eshell V10.0 (abort with ^G)
1> </pre>
</section>
</chapter>
diff --git a/system/doc/system_principles/misc.xml b/system/doc/system_principles/misc.xml
new file mode 100644
index 0000000000..dd6c2a1336
--- /dev/null
+++ b/system/doc/system_principles/misc.xml
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2018</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>Support, Compatibility, Deprecations, and Removal</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date>2018-05-21</date>
+ <rev></rev>
+ <file>misc.xml</file>
+ </header>
+
+ <section>
+ <marker id="supported_releases"/>
+ <title>Supported Releases</title>
+ <p>
+ In general, bugs are only fixed on the latest
+ <seealso marker="versions#releases_and_patches">release</seealso>,
+ and new features are introduced in the upcoming release that is
+ under development. However, when we, due to internal reasons, fix
+ bugs on older releases, these will be available and announced as well.
+ </p>
+ <p>
+ Due to the above, pull requests are only accepted on the
+ <c>maint</c> and the <c>master</c> branches in our
+ <url href="https://github.com/erlang/otp">git repository</url>.
+ The <c>maint</c> branch contains changes planned for the next
+ <seealso marker="versions#releases_and_patches">maintenance patch package</seealso>
+ on the latest OTP release and the <c>master</c> branch contain
+ changes planned for the upcoming OTP release.
+ </p>
+ </section>
+
+ <section>
+ <marker id="compatibility"/>
+ <title>Compatibility</title>
+ <p>
+ We always strive to remain as compatible as possible
+ even in the cases where we give no compatibility guarantees.
+ </p>
+ <p>
+ Different parts of the system will be handled differently
+ regarding compatibility. The following items describe how
+ different parts of the system are handled.
+ </p>
+ <taglist>
+ <tag>Erlang Distribution</tag>
+ <item>
+ <p>
+ Erlang nodes can communicate across at least
+ two preceding and two subsequent releases.
+ </p>
+ </item>
+ <tag>Compiled BEAM Code, NIF Libraries and Drivers</tag>
+ <item>
+ <p>
+ Compiled code can be loaded on at least two
+ subsequent releases.
+ </p>
+ <p>
+ Loading on previous releases is <em>not</em> supported.
+ </p>
+ </item>
+ <tag>Compiled HiPE Code</tag>
+ <item>
+ <p>
+ Compiled HiPE code can be loaded on the exact same build
+ of ERTS that was used when compiling the code. It might
+ however work on other builds, the emulator verifies
+ checksums in order to determine if it can load the code
+ or not. Note that HiPE has some limitations. For more
+ information see the documentation of the
+ <seealso marker="hipe:HiPE_app">HiPE</seealso> application.
+ </p>
+ </item>
+ <tag>APIs</tag>
+ <item>
+ <p>Compatible between releases.</p>
+ </item>
+ <tag>Compiler Warnings</tag>
+ <item>
+ <p>New warnings may be issued between releases.</p>
+ </item>
+ <tag>Command Line Arguments</tag>
+ <item>
+ <p>Incompatible changes may occur between releases.</p>
+ </item>
+ <tag>OTP Build Procedures</tag>
+ <item><p>Incompatible changes may occur between releases.</p></item>
+ </taglist>
+ <p>
+ Under certain circumstances incompatible changes might be
+ introduced even in parts of the system that should be compatible
+ between releases. Things that might trigger incompatible changes
+ like this are:
+ </p>
+ <taglist>
+ <tag>Security Issues</tag>
+ <item>
+ <p>
+ It might be necessary to introduce incompatible changes
+ in order to solve a security issue. This kind of
+ incompatibility might occur in a patch.
+ </p>
+ </item>
+ <tag>Bug Fixes</tag>
+ <item>
+ <p>
+ We will not be bug-compatible. A bug fix might introduce
+ incompatible changes. This kind of incompatibility
+ might occur in a patch.
+ </p>
+ </item>
+ <tag>Severe Previous Design Issues</tag>
+ <item>
+ <p>
+ Some parts of OTP were designed a very long time ago and
+ did not necessarily take today's computing environments into
+ account. In some cases the consequences of those design
+ decisions are too severe. This may be performance wise,
+ scalability wise, etc. If we deem the consequences too
+ severe, we might introduce incompatible changes. This kind
+ of incompatibility will not be introduced in a patch, but
+ instead in the next release.
+ </p>
+ </item>
+ </taglist>
+ <p>
+ Peripheral, trace, and debug functionality is at greater
+ risk of being changed in an incompatible way than functionality
+ in the language itself and core libraries used during operation.
+ </p>
+ </section>
+
+ <section>
+ <marker id="deprecation"/>
+ <title>Deprecation</title>
+ <p>
+ Functionality is deprecated when new functionality is
+ introduced that is preferred to be used instead of the
+ old functionality that is being deprecated. The deprecation
+ does <em>not</em> imply removal of the functionality unless
+ an upcoming removal is explicitly stated in the deprecation.
+ </p>
+ <p>
+ Deprecated functionality will be documented as deprecated, and
+ compiler warnings will be issued, when appropriate, as
+ early as possible. That is, the new preferred functionality
+ will appear at the same time as the deprecation is issued.
+ A new deprecation will at least be announced in a release
+ note and the documentation.
+ </p>
+ </section>
+
+ <section>
+ <marker id="removal"/>
+ <title>Removal</title>
+ <p>
+ Legacy solutions may eventually need to be removed. In such
+ cases, they will be phased out on a long enough time period
+ to give users the time to adapt. Before removal of
+ functionality it will be deprecated at least during one
+ release with an explicit announcement about
+ the upcoming removal. A new deprecation will at least be
+ announced in a release note and the documentation.
+ </p>
+ <p>
+ Peripheral, trace, and debug functionality is at greater
+ risk of removal than functionality in the language itself
+ and core libraries used during operation.
+ </p>
+ </section>
+
+</chapter>
+
diff --git a/system/doc/system_principles/part.xml b/system/doc/system_principles/part.xml
index 1b87ecd350..6699389eec 100644
--- a/system/doc/system_principles/part.xml
+++ b/system/doc/system_principles/part.xml
@@ -4,7 +4,7 @@
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -34,4 +34,5 @@
<xi:include href="create_target.xml"/>
<xi:include href="upgrade.xml"/>
<xi:include href="versions.xml"/>
+ <xi:include href="misc.xml"/>
</part>
diff --git a/system/doc/system_principles/system_principles.xml b/system/doc/system_principles/system_principles.xml
index 3605df3ade..500522d778 100644
--- a/system/doc/system_principles/system_principles.xml
+++ b/system/doc/system_principles/system_principles.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1996</year><year>2015</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -93,7 +93,7 @@ init:stop()</pre>
{progress,kernel_load_completed}
{progress,modules_loaded}
{start,heart}
-{start,error_logger}
+{start,logger}
...</pre>
<p>For a detailed description of the syntax and contents of the
boot script, see the <c>script(4)</c> manual page in SASL.</p>
diff --git a/system/doc/system_principles/versions.xml b/system/doc/system_principles/versions.xml
index b9f7fa4bf6..11dc9d5637 100644
--- a/system/doc/system_principles/versions.xml
+++ b/system/doc/system_principles/versions.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2014</year><year>2016</year>
+ <year>2014</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,9 +32,9 @@
<rev></rev>
<file>versions.xml</file>
</header>
- <marker id="versions section"></marker>
<section>
+ <marker id="versions section"></marker>
<title>OTP Version</title>
<p>As of OTP release 17, the OTP release number corresponds to
the major part of the OTP version. The OTP version as a concept was
@@ -136,8 +136,8 @@
</section>
<section>
- <title>Version Scheme</title>
<marker id="version_scheme"/>
+ <title>Version Scheme</title>
<note><p>The version scheme was changed as of OTP 17.0. This implies
that application versions used prior to OTP 17.0 do not adhere to this
version scheme. <seealso marker="#otp_17_0_app_versions">A list of
@@ -207,8 +207,41 @@
</section>
<section>
- <title>OTP 17.0 Application Versions</title>
+ <marker id="releases_and_patches"/>
+ <title>Releases and Patches</title>
+ <p>
+ When a new OTP release is released it will have an OTP
+ version on the form <c>&lt;Major&gt;.0</c> where the
+ major OTP version number equals the release number.
+ The major version number is increased one step since the
+ last major version. All other OTP versions with the same
+ major OTP version number are patches on that OTP release.
+ </p>
+ <p>
+ Patches are either released as maintenance patch packages
+ or emergency patch packages. The only difference is that
+ maintenance patch packages are planned and usually contain
+ more changes than emergency patch packages. Emergency patch
+ packages are released to solve one or more specific issues
+ when such are discovered.
+ </p>
+ <p>
+ The release of a maintenance patch package usually imply
+ an increase of the OTP <c>&lt;Minor&gt;</c> version while
+ the release of an emergency patch package usually imply an
+ increase of the OTP <c>&lt;Patch&gt;</c> version. This is
+ however not necessarily always the case since changes of
+ OTP versions are based on the actual changes in the code
+ and not based on whether the patch was planned or not.
+ For more information see the
+ <seealso marker="#version_scheme">Version Scheme</seealso>
+ section above.
+ </p>
+ </section>
+
+ <section>
<marker id="otp_17_0_app_versions"/>
+ <title>OTP 17.0 Application Versions</title>
<p>The following list details the application versions that
were part of OTP 17.0. If
the normal part of an application version number compares
diff --git a/system/doc/system_principles/xmlfiles.mk b/system/doc/system_principles/xmlfiles.mk
index f8972b24a7..353c2c7f7f 100644
--- a/system/doc/system_principles/xmlfiles.mk
+++ b/system/doc/system_principles/xmlfiles.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009-2016. All Rights Reserved.
+# Copyright Ericsson AB 2009-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -21,7 +21,8 @@ SYSTEM_PRINCIPLES_CHAPTER_FILES = \
system_principles.xml \
error_logging.xml \
upgrade.xml \
- versions.xml
+ versions.xml \
+ misc.xml
SYSTEM_PRINCIPLES_CHAPTER_GEN_FILES = \
create_target.xml
diff --git a/system/doc/top/Makefile b/system/doc/top/Makefile
index 73c943caa1..0703b821f1 100644
--- a/system/doc/top/Makefile
+++ b/system/doc/top/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2016. All Rights Reserved.
+# Copyright Ericsson AB 1999-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/system/doc/top/book.xml b/system/doc/top/book.xml
index 540b6bfd24..61e75591ef 100644
--- a/system/doc/top/book.xml
+++ b/system/doc/top/book.xml
@@ -4,7 +4,7 @@
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<header titlestyle="normal">
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/system/doc/tutorial/Makefile b/system/doc/tutorial/Makefile
index 606064da72..5867096fc8 100644
--- a/system/doc/tutorial/Makefile
+++ b/system/doc/tutorial/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2000-2016. All Rights Reserved.
+# Copyright Ericsson AB 2000-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -110,6 +110,7 @@ debug opt:
clean clean_docs:
rm -rf $(HTMLDIR)
+ rm -rf $(XMLDIR)
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
diff --git a/system/doc/tutorial/xmlfiles.mk b/system/doc/tutorial/xmlfiles.mk
index 53f82c6475..74e174f6d4 100644
--- a/system/doc/tutorial/xmlfiles.mk
+++ b/system/doc/tutorial/xmlfiles.mk
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009-2016. All Rights Reserved.
+# Copyright Ericsson AB 2009-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/xcomp/erl-xcomp-armv8-rpi3-linux-gnueabihf.conf b/xcomp/erl-xcomp-armv8-rpi3-linux-gnueabihf.conf
new file mode 100644
index 0000000000..dffc4a4b56
--- /dev/null
+++ b/xcomp/erl-xcomp-armv8-rpi3-linux-gnueabihf.conf
@@ -0,0 +1,276 @@
+## -*-shell-script-*-
+##
+## %CopyrightBegin%
+##
+## Copyright Ericsson AB 2009-2018. All Rights Reserved.
+##
+## Licensed under the Apache License, Version 2.0 (the "License");
+## you may not use this file except in compliance with the License.
+## You may obtain a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+##
+## %CopyrightEnd%
+##
+## File: erl-xcomp-armv8-rpi3-linux-gnueabihf.conf
+## Author: Péter Dimitrov
+## Tested: macOS High Sierra 10.13.2 /
+## Raspberry Pi 3 Model B Rev 1.2
+##
+## -----------------------------------------------------------------------------
+## When cross compiling Erlang/OTP using `otp_build', copy this file and set
+## the variables needed below. Then pass the path to the copy of this file as
+## an argument to `otp_build' in the configure stage:
+## `otp_build configure --xcomp-conf=<FILE>'
+## -----------------------------------------------------------------------------
+
+## Note that you cannot define arbitrary variables in a cross compilation
+## configuration file. Only the ones listed below will be guaranteed to be
+## visible throughout the whole execution of all `configure' scripts. Other
+## variables needs to be defined as arguments to `configure' or exported in
+## the environment.
+
+## -- Variables for `otp_build' Only -------------------------------------------
+
+## Variables in this section are only used, when configuring Erlang/OTP for
+## cross compilation using `$ERL_TOP/otp_build configure'.
+
+## *NOTE*! These variables currently have *no* effect if you configure using
+## the `configure' script directly.
+
+# * `erl_xcomp_build' - The build system used. This value will be passed as
+# `--build=$erl_xcomp_build' argument to the `configure' script. It does
+# not have to be a full `CPU-VENDOR-OS' triplet, but can be. The full
+# `CPU-VENDOR-OS' triplet will be created by
+# `$ERL_TOP/erts/autoconf/config.sub $erl_xcomp_build'. If set to `guess',
+# the build system will be guessed using
+# `$ERL_TOP/erts/autoconf/config.guess'.
+erl_xcomp_build=guess
+
+# * `erl_xcomp_host' - Cross host/target system to build for. This value will
+# be passed as `--host=$erl_xcomp_host' argument to the `configure' script.
+# It does not have to be a full `CPU-VENDOR-OS' triplet, but can be. The
+# full `CPU-VENDOR-OS' triplet will be created by
+# `$ERL_TOP/erts/autoconf/config.sub $erl_xcomp_host'.
+erl_xcomp_host=armv8-rpi3-linux-gnueabihf
+
+# * `erl_xcomp_configure_flags' - Extra configure flags to pass to the
+# `configure' script.
+#erl_xcomp_configure_flags=
+
+## -- Cross Compiler and Other Tools -------------------------------------------
+
+## If the cross compilation tools are prefixed by `<HOST>-' you probably do
+## not need to set these variables (where `<HOST>' is what has been passed as
+## `--host=<HOST>' argument to `configure').
+
+## All variables in this section can also be used when native compiling.
+
+# * `CC' - C compiler.
+CC=armv8-rpi3-linux-gnueabihf-gcc
+
+# * `CFLAGS' - C compiler flags.
+#CFLAGS=
+
+# * `STATIC_CFLAGS' - Static C compiler flags.
+#STATIC_CFLAGS=
+
+# * `CFLAG_RUNTIME_LIBRARY_PATH' - This flag should set runtime library
+# search path for the shared libraries. Note that this actually is a
+# linker flag, but it needs to be passed via the compiler.
+#CFLAG_RUNTIME_LIBRARY_PATH=
+
+# * `CPP' - C pre-processor.
+CPP=armv8-rpi3-linux-gnueabihf-cpp
+
+# * `CPPFLAGS' - C pre-processor flags.
+#CPPFLAGS=
+
+# * `CXX' - C++ compiler.
+CXX=armv8-rpi3-linux-gnueabihf-g++
+
+# * `CXXFLAGS' - C++ compiler flags.
+#CXXFLAGS=
+
+# * `LD' - Linker.
+LD=armv8-rpi3-linux-gnueabihf-ld
+
+# * `LDFLAGS' - Linker flags.
+LDFLAGS="-L$RPI_SYSROOT/lib"
+
+# * `LIBS' - Libraries.
+#LIBS=
+
+## -- *D*ynamic *E*rlang *D*river Linking --
+
+## *NOTE*! Either set all or none of the `DED_LD*' variables.
+
+# * `DED_LD' - Linker for Dynamically loaded Erlang Drivers.
+#DED_LD=
+
+# * `DED_LDFLAGS' - Linker flags to use with `DED_LD'.
+#DED_LDFLAGS=
+
+# * `DED_LD_FLAG_RUNTIME_LIBRARY_PATH' - This flag should set runtime library
+# search path for shared libraries when linking with `DED_LD'.
+#DED_LD_FLAG_RUNTIME_LIBRARY_PATH=
+
+## -- Large File Support --
+
+## *NOTE*! Either set all or none of the `LFS_*' variables.
+
+# * `LFS_CFLAGS' - Large file support C compiler flags.
+#LFS_CFLAGS=
+
+# * `LFS_LDFLAGS' - Large file support linker flags.
+#LFS_LDFLAGS=
+
+# * `LFS_LIBS' - Large file support libraries.
+#LFS_LIBS=
+
+## -- Other Tools --
+
+# * `RANLIB' - `ranlib' archive index tool.
+RANLIB=armv8-rpi3-linux-gnueabihf-ranlib
+
+# * `AR' - `ar' archiving tool.
+AR=armv8-rpi3-linux-gnueabihf-ar
+
+# * `GETCONF' - `getconf' system configuration inspection tool. `getconf' is
+# currently used for finding out large file support flags to use, and
+# on Linux systems for finding out if we have an NPTL thread library or
+# not.
+#GETCONF=
+
+## -- Cross System Root Locations ----------------------------------------------
+
+# * `erl_xcomp_sysroot' - The absolute path to the system root of the cross
+# compilation environment. Currently, the `crypto', `odbc', `ssh' and
+# `ssl' applications need the system root. These applications will be
+# skipped if the system root has not been set. The system root might be
+# needed for other things too. If this is the case and the system root
+# has not been set, `configure' will fail and request you to set it.
+erl_xcomp_sysroot="$RPI_SYSROOT"
+
+# * `erl_xcomp_isysroot' - The absolute path to the system root for includes
+# of the cross compilation environment. If not set, this value defaults
+# to `$erl_xcomp_sysroot', i.e., only set this value if the include system
+# root path is not the same as the system root path.
+#erl_xcomp_isysroot=
+
+## -- Optional Feature, and Bug Tests ------------------------------------------
+
+## These tests cannot (always) be done automatically when cross compiling. You
+## usually do not need to set these variables. Only set these if you really
+## know what you are doing.
+
+## Note that some of these values will override results of tests performed
+## by `configure', and some will not be used until `configure' is sure that
+## it cannot figure the result out.
+
+## The `configure' script will issue a warning when a default value is used.
+## When a variable has been set, no warning will be issued.
+
+# * `erl_xcomp_after_morecore_hook' - `yes|no'. Defaults to `no'. If `yes',
+# the target system must have a working `__after_morecore_hook' that can be
+# used for tracking used `malloc()' implementations core memory usage.
+# This is currently only used by unsupported features.
+#erl_xcomp_after_morecore_hook=
+
+# * `erl_xcomp_bigendian' - `yes|no'. No default. If `yes', the target system
+# must be big endian. If `no', little endian. This can often be
+# automatically detected, but not always. If not automatically detected,
+# `configure' will fail unless this variable is set. Since no default
+# value is used, `configure' will try to figure this out automatically.
+#erl_xcomp_bigendian=
+
+# * `erl_xcomp_double_middle` - `yes|no`. No default. If `yes`, the
+# target system must have doubles in "middle-endian" format. If
+# `no`, it has "regular" endianness. This can often be automatically
+# detected, but not always. If not automatically detected,
+# `configure` will fail unless this variable is set. Since no
+# default value is used, `configure` will try to figure this out
+# automatically.
+#erl_xcomp_double_middle_endian
+
+# * `erl_xcomp_clock_gettime_cpu_time' - `yes|no'. Defaults to `no'. If `yes',
+# the target system must have a working `clock_gettime()' implementation
+# that can be used for retrieving process CPU time.
+#erl_xcomp_clock_gettime_cpu_time=
+
+# * `erl_xcomp_getaddrinfo' - `yes|no'. Defaults to `no'. If `yes', the target
+# system must have a working `getaddrinfo()' implementation that can
+# handle both IPv4 and IPv6.
+#erl_xcomp_getaddrinfo=
+
+# * `erl_xcomp_gethrvtime_procfs_ioctl' - `yes|no'. Defaults to `no'. If `yes',
+# the target system must have a working `gethrvtime()' implementation and
+# is used with procfs `ioctl()'.
+#erl_xcomp_gethrvtime_procfs_ioctl=
+
+# * `erl_xcomp_dlsym_brk_wrappers' - `yes|no'. Defaults to `no'. If `yes', the
+# target system must have a working `dlsym(RTLD_NEXT, <S>)' implementation
+# that can be used on `brk' and `sbrk' symbols used by the `malloc()'
+# implementation in use, and by this track the `malloc()' implementations
+# core memory usage. This is currently only used by unsupported features.
+#erl_xcomp_dlsym_brk_wrappers=
+
+# * `erl_xcomp_kqueue' - `yes|no'. Defaults to `no'. If `yes', the target
+# system must have a working `kqueue()' implementation that returns a file
+# descriptor which can be used by `poll()' and/or `select()'. If `no' and
+# the target system has not got `epoll()' or `/dev/poll', the kernel-poll
+# feature will be disabled.
+#erl_xcomp_kqueue=
+
+# * `erl_xcomp_linux_clock_gettime_correction' - `yes|no'. Defaults to `yes' on
+# Linux; otherwise, `no'. If `yes', `clock_gettime(CLOCK_MONOTONIC, _)' on
+# the target system must work. This variable is recommended to be set to
+# `no' on Linux systems with kernel versions less than 2.6.
+#erl_xcomp_linux_clock_gettime_correction=
+
+# * `erl_xcomp_linux_nptl' - `yes|no'. Defaults to `yes' on Linux; otherwise,
+# `no'. If `yes', the target system must have NPTL (Native POSIX Thread
+# Library). Older Linux systems have LinuxThreads instead of NPTL (Linux
+# kernel versions typically less than 2.6).
+#erl_xcomp_linux_nptl=
+
+# * `erl_xcomp_linux_usable_sigaltstack' - `yes|no'. Defaults to `yes' on Linux;
+# otherwise, `no'. If `yes', `sigaltstack()' must be usable on the target
+# system. `sigaltstack()' on Linux kernel versions less than 2.4 are
+# broken.
+#erl_xcomp_linux_usable_sigaltstack=
+
+# * `erl_xcomp_linux_usable_sigusrx' - `yes|no'. Defaults to `yes'. If `yes',
+# the `SIGUSR1' and `SIGUSR2' signals must be usable by the ERTS. Old
+# LinuxThreads thread libraries (Linux kernel versions typically less than
+# 2.2) used these signals and made them unusable by the ERTS.
+#erl_xcomp_linux_usable_sigusrx=
+
+# * `erl_xcomp_poll' - `yes|no'. Defaults to `no' on Darwin/MacOSX; otherwise,
+# `yes'. If `yes', the target system must have a working `poll()'
+# implementation that also can handle devices. If `no', `select()' will be
+# used instead of `poll()'.
+#erl_xcomp_poll=
+
+# * `erl_xcomp_putenv_copy' - `yes|no'. Defaults to `no'. If `yes', the target
+# system must have a `putenv()' implementation that stores a copy of the
+# key/value pair.
+#erl_xcomp_putenv_copy=
+
+# * `erl_xcomp_reliable_fpe' - `yes|no'. Defaults to `no'. If `yes', the target
+# system must have reliable floating point exceptions.
+#erl_xcomp_reliable_fpe=
+
+# * `erl_xcomp_posix_memalign' - `yes|no'. Defaults to `yes' if `posix_memalign'
+# system call exists; otherwise `no'. If `yes', the target system must have a
+# `posix_memalign' implementation that accepts larger than page size
+# alignment.
+#erl_xcomp_posix_memalign=
+
+## -----------------------------------------------------------------------------